Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions infrastructure/group-charter-manager/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
node_modules
dist
.DS_Store
server/public
vite.config.ts.*
*.tar.gz
36 changes: 36 additions & 0 deletions infrastructure/group-charter-manager/.replit
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
modules = ["nodejs-20", "web", "postgresql-16"]
run = "npm run dev"
hidden = [".config", ".git", "generated-icon.png", "node_modules", "dist"]

[nix]
channel = "stable-24_05"

[deployment]
deploymentTarget = "autoscale"
build = ["npm", "run", "build"]
run = ["npm", "run", "start"]

[[ports]]
localPort = 5000
externalPort = 80

[workflows]
runButton = "Project"

[[workflows.workflow]]
name = "Project"
mode = "parallel"
author = "agent"

[[workflows.workflow.tasks]]
task = "workflow.run"
args = "Start application"

[[workflows.workflow]]
name = "Start application"
author = "agent"

[[workflows.workflow.tasks]]
task = "shell.exec"
args = "npm run dev"
waitForPort = 5000
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
15 changes: 15 additions & 0 deletions infrastructure/group-charter-manager/client/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css" />
<title>Group Charter</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
<!-- This is a replit script which adds a banner on the top of the page when opened in development mode outside the replit environment -->
<script type="text/javascript" src="https://replit.com/public/js/replit-dev-banner.js"></script>
</body>
</html>
82 changes: 82 additions & 0 deletions infrastructure/group-charter-manager/client/src/App.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import { Switch, Route } from "wouter";
import { queryClient } from "./lib/queryClient";
import { QueryClientProvider } from "@tanstack/react-query";
import { Toaster } from "@/components/ui/toaster";
import { TooltipProvider } from "@/components/ui/tooltip";
import { useAuth } from "@/hooks/useAuth";
import Navbar from "@/components/layout/navbar";
import Dashboard from "@/pages/dashboard";
import CharterDetail from "@/pages/charter-detail";
import CreateCharter from "@/pages/create-charter";
import EditCharter from "@/pages/edit-charter";
import NotFound from "@/pages/not-found";

function Router() {
return <AuthenticatedApp />;
}

function AuthenticatedApp() {
const { isAuthenticated, isLoading } = useAuth();

// Show loading state while checking authentication
if (isLoading) {
return (
<div className="min-h-screen gradient-bg flex items-center justify-center">
<div className="animate-pulse space-y-4">
<div className="h-8 bg-black bg-opacity-10 rounded w-32 mx-auto"></div>
<div className="h-4 bg-black bg-opacity-10 rounded w-48 mx-auto">Checking authentication...</div>
</div>
</div>
);
}

// Show login button for unauthenticated users instead of auto-redirect
if (!isAuthenticated) {
return (
<div className="min-h-screen gradient-bg flex items-center justify-center">
<div className="text-center space-y-6">
<div className="space-y-2">
<h1 className="text-3xl font-bold text-gray-800">Group Charter</h1>
<p className="text-gray-600">Please sign in to access your dashboard</p>
</div>
<button
onClick={() => window.location.href = "/api/login"}
className="gradient-primary text-white px-6 py-3 rounded-2xl font-medium hover:shadow-xl transform hover:scale-105 transition-all duration-300"
>
Sign In with Replit
</button>
</div>
</div>
);
}

// Show authenticated app
return (
<div className="min-h-screen gradient-bg">
<Navbar />
<div className="pt-10">
<Switch>
<Route path="/" component={Dashboard} />
<Route path="/charter/:id" component={CharterDetail} />
<Route path="/charter/:id/edit" component={EditCharter} />
<Route path="/create" component={CreateCharter} />
<Route path="/create-charter" component={CreateCharter} />
<Route component={NotFound} />
</Switch>
</div>
</div>
);
}

function App() {
return (
<QueryClientProvider client={queryClient}>
<TooltipProvider>
<Toaster />
<Router />
</TooltipProvider>
</QueryClientProvider>
);
}

export default App;
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { Link } from "wouter";
import { CheckCircle, Clock, Eye, Crown } from "lucide-react";
import { CharterWithGroup } from "@shared/schema";
import { PlatformBadge } from "./platform-badge";
import { useAuth } from "@/hooks/useAuth";

interface CharterCardProps {
charter: CharterWithGroup;
}

export default function CharterCard({ charter }: CharterCardProps) {
const { user } = useAuth();
const StatusIcon = charter.isActive ? CheckCircle : Clock;
const statusColor = charter.isActive ? "text-green-600" : "text-yellow-600";
const statusBg = charter.isActive ? "bg-green-100" : "bg-yellow-100";
const isOwner = user?.id === charter.ownerId;



return (
<div className="bg-white/70 backdrop-blur-sm rounded-3xl p-4 sm:p-6 soft-shadow hover-lift cursor-pointer fade-in">
<div className="flex items-start justify-between mb-3 sm:mb-4">
<div className="flex items-center space-x-2 sm:space-x-3 flex-1 min-w-0">
<div className="min-w-0 flex-1">
<h4 className="font-semibold text-gray-800 text-sm sm:text-base truncate">{charter.name}</h4>
<p className="text-xs sm:text-sm text-gray-600 truncate mt-1">{charter.group.name}</p>
<div className="flex items-center mt-1">
<PlatformBadge platform={charter.group.platform} className="text-xs" />
</div>
</div>
</div>
<div className="flex items-center space-x-2 flex-shrink-0 ml-2">
{isOwner && (
<div className="w-6 h-6 sm:w-8 sm:h-8 bg-yellow-100 rounded-full flex items-center justify-center">
<Crown className="text-yellow-600 text-sm" size={12} />
</div>
)}
<div className={`w-6 h-6 sm:w-8 sm:h-8 ${statusBg} rounded-full flex items-center justify-center`}>
<StatusIcon className={`${statusColor} text-sm`} size={12} />
</div>
</div>
</div>

<div className="flex flex-col sm:flex-row sm:items-center sm:justify-between space-y-2 sm:space-y-0">
<span className="text-xs text-gray-500">
Updated {charter.updatedAt ? new Date(charter.updatedAt).toLocaleDateString() : "recently"}
</span>
<Link href={`/charter/${charter.id}`}>
<button className="text-amber-600 hover:text-amber-700 font-medium text-sm flex items-center space-x-1 w-fit">
<Eye size={14} />
<span>View Charter</span>
</button>
</Link>
</div>
</div>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
interface CertificateRibbonProps {
className?: string;
size?: number;
}

export function CertificateRibbon({ className = "", size = 24 }: CertificateRibbonProps) {
return (
<svg
width={size}
height={size}
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
className={className}
>
{/* Outer seal ring */}
<circle
cx="12"
cy="12"
r="10"
fill="currentColor"
stroke="none"
/>

{/* Inner seal ring */}
<circle
cx="12"
cy="12"
r="7.5"
fill="none"
stroke="white"
strokeWidth="1"
opacity="0.3"
/>

{/* Star in center */}
<path
d="M12 4 L13.5 8.5 L18 8.5 L14.5 11.5 L16 16 L12 13 L8 16 L9.5 11.5 L6 8.5 L10.5 8.5 Z"
fill="white"
stroke="none"
/>

{/* Inner circle around star */}
<circle
cx="12"
cy="12"
r="5"
fill="none"
stroke="white"
strokeWidth="0.5"
opacity="0.4"
/>

{/* Decorative notches around outer edge */}
<path
d="M12 1 L12.5 2.5 L12 4 L11.5 2.5 Z"
fill="white"
opacity="0.6"
/>
<path
d="M12 20 L12.5 21.5 L12 23 L11.5 21.5 Z"
fill="white"
opacity="0.6"
/>
<path
d="M1 12 L2.5 12.5 L4 12 L2.5 11.5 Z"
fill="white"
opacity="0.6"
/>
<path
d="M20 12 L21.5 12.5 L23 12 L21.5 11.5 Z"
fill="white"
opacity="0.6"
/>

{/* Diagonal notches */}
<path
d="M4.5 4.5 L5.5 5 L6 6 L5 5.5 Z"
fill="white"
opacity="0.6"
/>
<path
d="M17.5 17.5 L18.5 18 L19 19 L18 18.5 Z"
fill="white"
opacity="0.6"
/>
<path
d="M17.5 4.5 L18.5 5 L19 6 L18 5.5 Z"
fill="white"
opacity="0.6"
/>
<path
d="M4.5 17.5 L5.5 18 L6 19 L5 18.5 Z"
fill="white"
opacity="0.6"
/>
</svg>
);
}
Loading
Loading