Skip to content

Commit

Permalink
refactor(frontend): small typos [2024-11-10]
Browse files Browse the repository at this point in the history
  • Loading branch information
CHRISCARLON committed Nov 10, 2024
1 parent 2b42335 commit 97f004e
Show file tree
Hide file tree
Showing 3 changed files with 232 additions and 25 deletions.
51 changes: 51 additions & 0 deletions gridwalk-ui/src/app/api/new_workspace/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { NextRequest, NextResponse } from "next/server";

export async function POST(request: NextRequest) {
try {
const authToken = request.cookies.get("sid")?.value;
if (!authToken) {
return NextResponse.json(
{ success: false, error: "Authentication required" },
{ status: 401 },
);
}

const body = await request.json();
const { name } = body;

if (!name || typeof name !== "string" || name.trim().length === 0) {
return NextResponse.json(
{ success: false, error: "Workspace name is required" },
{ status: 400 },
);
}

const response = await fetch(`${process.env.GRIDWALK_API}/workspace`, {
method: "POST",
headers: {
Authorization: `Bearer ${authToken}`,
"Content-Type": "application/json",
},
body: JSON.stringify({ name: name.trim() }),
});

if (!response.ok) {
throw new Error(`Failed to create workspace: ${response.statusText}`);
}

return NextResponse.json({
success: true,
message: "Workspace created successfully",
});
} catch (error) {
console.error("Error creating workspace:", error);
return NextResponse.json(
{
success: false,
error:
error instanceof Error ? error.message : "Failed to create workspace",
},
{ status: 500 },
);
}
}
28 changes: 14 additions & 14 deletions gridwalk-ui/src/app/workspace/[workspaceId]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ export default function WorkspaceProjectsPage() {
const params = useParams();
const workspaceId = params.workspaceId as string;

const [isDialogOpen, setIsDialogOpen] = useState(false);
const [isProjectDialogOpen, setIsProjectDialogOpen] = useState(false);
const [projects, setProjects] = useState<string[]>([]);
const [isLoading, setIsLoading] = useState(true);
const [error, setError] = useState<string | null>(null);
Expand Down Expand Up @@ -212,14 +212,11 @@ export default function WorkspaceProjectsPage() {
const versionA = getProjectVersion(a);
const versionB = getProjectVersion(b);

// If both have versions, sort by version number descending
if (versionA !== null && versionB !== null) {
return versionB - versionA;
}
// If only one has a version, put versioned items first
if (versionA !== null) return -1;
if (versionB !== null) return 1;
// If neither has a version, sort alphabetically
return a.localeCompare(b);
});
};
Expand All @@ -234,15 +231,18 @@ export default function WorkspaceProjectsPage() {
</h1>
<p className="text-gray-600">Workspace: {workspaceId}</p>
</div>
<button
onClick={() => setIsDialogOpen(true)}
className="bg-blue-500 hover:bg-blue-600 text-white px-4 py-2 rounded-lg flex items-center gap-2 transition-colors w-full sm:w-auto justify-center sm:justify-start"
>
<Plus size={20} />
New Project
</button>
<div className="flex flex-col sm:flex-row gap-2">
<button
onClick={() => setIsProjectDialogOpen(true)}
className="bg-blue-500 hover:bg-blue-600 text-white px-4 py-2 rounded-lg flex items-center gap-2 transition-colors w-full sm:w-auto justify-center sm:justify-start"
>
<Plus size={20} />
New Project
</button>
</div>
</div>

{/* Rest of the existing JSX */}
<div className="mt-8">
{isLoading ? (
<div className="flex items-center justify-center p-8">
Expand Down Expand Up @@ -283,10 +283,10 @@ export default function WorkspaceProjectsPage() {
)}
</div>

{isDialogOpen && (
{isProjectDialogOpen && (
<CreateProjectModal
isOpen={isDialogOpen}
onClose={() => setIsDialogOpen(false)}
isOpen={isProjectDialogOpen}
onClose={() => setIsProjectDialogOpen(false)}
onSubmit={handleCreateProject}
/>
)}
Expand Down
178 changes: 167 additions & 11 deletions gridwalk-ui/src/app/workspace/workspace-sidebar.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,133 @@
import React from "react";
"use client";
import React, { useState } from "react";
import { Sidebar, SidebarContent } from "@/components/ui/sidebar";
import { Building2, FolderKanban } from "lucide-react";
import { Building2, Briefcase } from "lucide-react";
import { Avatar, AvatarFallback } from "@/components/ui/avatar";
import Link from "next/link";

interface CreateWorkspaceModalProps {
isOpen: boolean;
onClose: () => void;
onSubmit: (name: string) => Promise<void>;
}

const CreateWorkspaceModal: React.FC<CreateWorkspaceModalProps> = ({
isOpen,
onClose,
onSubmit,
}) => {
const [workspaceName, setWorkspaceName] = useState("");
const [isLoading, setIsLoading] = useState(false);
const [error, setError] = useState<string | null>(null);

const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
setIsLoading(true);
setError(null);

try {
await onSubmit(workspaceName.trim());
onClose();
setWorkspaceName("");
} catch (err) {
setError(err instanceof Error ? err.message : "An error occurred");
} finally {
setIsLoading(false);
}
};

if (!isOpen) return null;

return (
<div className="fixed inset-0 bg-black/50 flex items-center justify-center z-50 p-4">
<div className="bg-white rounded-lg p-6 w-full max-w-md relative">
<div className="flex justify-between items-center mb-4">
<h2 className="text-xl font-bold text-gray-900">
Create New Workspace
</h2>
<button
onClick={onClose}
className="text-gray-500 hover:text-gray-700"
>
</button>
</div>

{error && (
<div className="bg-red-50 text-red-600 p-3 rounded-md mb-4">
{error}
</div>
)}

<form onSubmit={handleSubmit}>
<div className="mb-4">
<label
htmlFor="workspaceName"
className="block text-sm font-medium text-gray-700 mb-1"
>
Workspace Name
</label>
<input
id="workspaceName"
type="text"
value={workspaceName}
onChange={(e) => setWorkspaceName(e.target.value)}
className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
placeholder="Enter workspace name..."
minLength={3}
maxLength={50}
required
/>
</div>

<div className="flex justify-end gap-2">
<button
type="button"
onClick={onClose}
className="px-4 py-2 text-gray-700 bg-gray-100 rounded-md hover:bg-gray-200"
>
Cancel
</button>
<button
type="submit"
disabled={isLoading || !workspaceName.trim()}
className="px-4 py-2 bg-blue-500 text-white rounded-md hover:bg-blue-600 disabled:opacity-50 disabled:cursor-not-allowed flex items-center gap-2"
>
{isLoading ? (
<>
<LoadingSpinner />
Creating...
</>
) : (
"Create Workspace"
)}
</button>
</div>
</form>
</div>
</div>
);
};

const LoadingSpinner: React.FC = () => (
<svg className="animate-spin h-4 w-4" viewBox="0 0 24 24">
<circle
className="opacity-25"
cx="12"
cy="12"
r="10"
stroke="currentColor"
strokeWidth="4"
fill="none"
/>
<path
className="opacity-75"
fill="currentColor"
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
/>
</svg>
);

interface AppSidebarProps {
userName?: string;
userEmail?: string;
Expand All @@ -15,17 +139,49 @@ export function AppSidebar({
userEmail = "",
workspaceNames = [],
}: AppSidebarProps) {
const [isWorkspaceDialogOpen, setIsWorkspaceDialogOpen] = useState(false);
const avatar = userName.charAt(0).toUpperCase();

const handleCreateWorkspace = async (name: string) => {
try {
// Call the API to create a new workspace
const response = await fetch("/api/new_workspace", {
method: "POST",
headers: { "Content-Type": "application/json" },
credentials: "include",
body: JSON.stringify({
name: name.trim(),
}),
});

const data = await response.json();
if (!data.success) {
throw new Error(data.error || "Failed to create workspace");
}

// Refresh the workspaceNames list
// ...
} catch (err) {
// Handle the error
console.error("Error creating workspace:", err);
}
};

return (
<Sidebar className="border-r">
<SidebarContent>
<div className="flex h-full flex-col">
{/* Logo */}
<div className="px-4 py-6">
<h1 className="text-xl font-bold">Workspaces</h1>
<button
onClick={() => setIsWorkspaceDialogOpen(true)}
className="mt-4 flex items-center gap-2 rounded-lg bg-blue-500 px-3 py-2 text-sm font-medium text-white hover:bg-blue-600 transition-colors"
>
<Briefcase size={20} />
New Workspace
</button>
</div>

<div className="flex-1 px-2">
<div className="mb-4">
<h2 className="px-3 text-sm font-semibold text-gray-500 uppercase tracking-wider">
Expand All @@ -45,14 +201,6 @@ export function AppSidebar({
))}
</nav>
</div>

<div className="px-2 mb-4">
<button className="w-full flex items-center gap-2 rounded-lg px-3 py-2 text-sm font-medium text-blue-600 hover:bg-blue-50">
<FolderKanban className="h-5 w-5" />
New Workspace
</button>
</div>

<div className="border-t p-4">
<div className="flex items-center gap-3">
<Avatar>
Expand All @@ -66,6 +214,14 @@ export function AppSidebar({
</div>
</div>
</SidebarContent>

{isWorkspaceDialogOpen && (
<CreateWorkspaceModal
isOpen={isWorkspaceDialogOpen}
onClose={() => setIsWorkspaceDialogOpen(false)}
onSubmit={handleCreateWorkspace}
/>
)}
</Sidebar>
);
}

0 comments on commit 97f004e

Please sign in to comment.