From 1e5f0b6b5e1d31ce660c5a5cdab625ec6d2d670d Mon Sep 17 00:00:00 2001 From: Amirhossein Khalili Date: Mon, 27 Apr 2026 20:52:18 +0330 Subject: [PATCH] refactor(lists): align client and project page controls --- src/pages/Clients.tsx | 165 +++++++++++++------------- src/pages/Projects.tsx | 261 ++++++++++++++++++++--------------------- src/pages/Tags.tsx | 2 +- 3 files changed, 211 insertions(+), 217 deletions(-) diff --git a/src/pages/Clients.tsx b/src/pages/Clients.tsx index 82ece98..7b76ab3 100644 --- a/src/pages/Clients.tsx +++ b/src/pages/Clients.tsx @@ -1,13 +1,13 @@ import { useEffect, useState } from "react" import { Plus, Building2, Loader2, Pencil, Trash2 } from "lucide-react" import { useWorkspace } from "../context/WorkspaceContext" -import { useTranslation } from "../hooks/useTranslation" -import { - CLIENTS_CREATE, - CLIENTS_DELETE, - CLIENTS_EDIT, - canWorkspace, -} from "../lib/permissions" +import { useTranslation } from "../hooks/useTranslation" +import { + CLIENTS_CREATE, + CLIENTS_DELETE, + CLIENTS_EDIT, + canWorkspace, +} from "../lib/permissions" import { type Client } from "../types/client" import { getClients } from "../api/clients" import CreateClientModal from "../components/CreateClientModal" @@ -38,12 +38,12 @@ export default function Clients() { const [editClient, setEditClient] = useState(null) const [deleteClient, setDeleteClient] = useState(null) - const { t, lang } = useTranslation() - const isFa = lang === "fa" - const workspaceRole = activeWorkspace?.my_role - const canCreateClient = canWorkspace(workspaceRole, CLIENTS_CREATE) - const canEditClient = canWorkspace(workspaceRole, CLIENTS_EDIT) - const canDeleteClient = canWorkspace(workspaceRole, CLIENTS_DELETE) + const { t, lang } = useTranslation() + const isFa = lang === "fa" + const workspaceRole = activeWorkspace?.my_role + const canCreateClient = canWorkspace(workspaceRole, CLIENTS_CREATE) + const canEditClient = canWorkspace(workspaceRole, CLIENTS_EDIT) + const canDeleteClient = canWorkspace(workspaceRole, CLIENTS_DELETE) const orderingOptions = [ { value: "-created_at", label: t.ordering?.createdAtDesc || "Newest First" }, @@ -116,24 +116,24 @@ export default function Clients() { return (
-
-
-

{t.clients.title}

-

- {t.clients.description(activeWorkspace.name)} -

-
- - {canCreateClient && ( - - )} +
+
+

{t.clients.title}

+

+ {t.clients.description(activeWorkspace.name)} +

+
+ + {canCreateClient && ( + + )}
)} -
- {t.clients.addedOn}: {formatDate(client.created_at)} -
- {(canEditClient || canDeleteClient) && ( -
- {canEditClient && ( - - )} - {canDeleteClient && ( - - )} -
- )} + {(canEditClient || canDeleteClient) && ( +
+ {canEditClient && ( + + )} + {canDeleteClient && ( + + )} +
+ )} ))} @@ -216,32 +213,32 @@ export default function Clients() { /> )} - {canCreateClient && ( - setIsCreateModalOpen(false)} - onSuccess={fetchClientsList} - workspaceId={activeWorkspace.id} - /> - )} - - {canEditClient && ( - setEditClient(null)} - onSuccess={fetchClientsList} - client={editClient} - /> - )} - - {canDeleteClient && ( - setDeleteClient(null)} - onSuccess={fetchClientsList} - client={deleteClient} - /> - )} + {canCreateClient && ( + setIsCreateModalOpen(false)} + onSuccess={fetchClientsList} + workspaceId={activeWorkspace.id} + /> + )} + + {canEditClient && ( + setEditClient(null)} + onSuccess={fetchClientsList} + client={editClient} + /> + )} + + {canDeleteClient && ( + setDeleteClient(null)} + onSuccess={fetchClientsList} + client={deleteClient} + /> + )}
) } diff --git a/src/pages/Projects.tsx b/src/pages/Projects.tsx index e280c5a..e03f2b9 100644 --- a/src/pages/Projects.tsx +++ b/src/pages/Projects.tsx @@ -9,26 +9,26 @@ import { Plus, Archive, Trash2, Pencil } from "lucide-react"; import FilterBar from "../components/FilterBar"; import { Button } from "../components/ui/button"; -import { Card } from "../components/ui/card"; +import { Card } from "../components/ui/card"; import { Modal } from "../components/Modal"; -import { toast } from "sonner"; -import { Input } from "../components/ui/input"; -import { - PROJECTS_ARCHIVE, - PROJECTS_CREATE, - PROJECTS_DELETE, - PROJECTS_EDIT, - canWorkspace, -} from "../lib/permissions"; +import { toast } from "sonner"; +import { Input } from "../components/ui/input"; +import { + PROJECTS_ARCHIVE, + PROJECTS_CREATE, + PROJECTS_DELETE, + PROJECTS_EDIT, + canWorkspace, +} from "../lib/permissions"; -export const Projects: React.FC = () => { - const { t, lang } = useTranslation(); - const { activeWorkspace } = useWorkspace(); - const workspaceRole = activeWorkspace?.my_role; - const canCreateProject = canWorkspace(workspaceRole, PROJECTS_CREATE); - const canEditProject = canWorkspace(workspaceRole, PROJECTS_EDIT); - const canDeleteProject = canWorkspace(workspaceRole, PROJECTS_DELETE); - const canArchiveProject = canWorkspace(workspaceRole, PROJECTS_ARCHIVE); +export const Projects: React.FC = () => { + const { t, lang } = useTranslation(); + const { activeWorkspace } = useWorkspace(); + const workspaceRole = activeWorkspace?.my_role; + const canCreateProject = canWorkspace(workspaceRole, PROJECTS_CREATE); + const canEditProject = canWorkspace(workspaceRole, PROJECTS_EDIT); + const canDeleteProject = canWorkspace(workspaceRole, PROJECTS_DELETE); + const canArchiveProject = canWorkspace(workspaceRole, PROJECTS_ARCHIVE); const [projects, setProjects] = useState([]); const [loading, setLoading] = useState(false); @@ -100,7 +100,7 @@ export const Projects: React.FC = () => { setProjectToDelete(project); }; - const confirmDelete = async () => { + const confirmDelete = async () => { if (!deleteModal.project) return; try { const deletedId = deleteModal.project.id; @@ -118,20 +118,20 @@ export const Projects: React.FC = () => { } catch (error) { toast.error(t.projects?.deleteError || 'Failed to delete project'); } - }; - - const formatDate = (dateStr: string | undefined) => { - if (!dateStr) return "-" - try { - const date = new Date(dateStr) - return new Intl.DateTimeFormat(lang === "fa" ? "fa-IR" : "en-US", { - dateStyle: "long", - timeZone: "Asia/Tehran", - }).format(date) - } catch { - return dateStr - } - } + }; + + const formatDate = (dateStr: string | undefined) => { + if (!dateStr) return "-" + try { + const date = new Date(dateStr) + return new Intl.DateTimeFormat(lang === "fa" ? "fa-IR" : "en-US", { + dateStyle: "long", + timeZone: "Asia/Tehran", + }).format(date) + } catch { + return dateStr + } + } return ( @@ -142,26 +142,26 @@ export const Projects: React.FC = () => {

{t.projects?.description(activeWorkspace?.name || "-") || 'Manage your projects'}

- {canArchiveProject && ( - - )} - {canCreateProject && ( - - )} + {canArchiveProject && ( + + )} + {canCreateProject && ( + + )}
@@ -174,76 +174,73 @@ export const Projects: React.FC = () => { searchPlaceholder={t.projects?.searchPlaceholder || 'Search projects...'} /> - {loading ? ( -
-
{t.projects?.loading || 'Loading...'}
-
- ) : ( -
- -
- {projects.length === 0 ? ( -
-

{t.projects?.emptyState || 'No projects found'}

-
- ) : ( -
    - {projects.map((project) => ( -
  • -
    -

    {project.name}

    -

    - {project.client ? `${t.projects?.client || "Client"}: ${project.client.name}` : t.projects?.noClient || "No client"} -

    - {project.description && ( -

    - {project.description} -

    - )} -
    - {(t.projects as any)?.addedOn || "Added on"}: {formatDate(project.created_at)} -
    -
    - - {(canEditProject || canDeleteProject) && ( -
    - {canEditProject && ( - - )} - - {canDeleteProject && ( - - )} -
    - )} -
  • - ))} -
- )} -
-
- - +
{t.projects?.loading || 'Loading...'}
+
+ ) : ( +
+ +
+ {projects.length === 0 ? ( +
+

{t.projects?.emptyState || 'No projects found'}

+
+ ) : ( +
    + {projects.map((project) => ( +
  • +
    +

    {project.name}

    +

    + {project.client ? `${t.projects?.client || "Client"}: ${project.client.name}` : t.projects?.noClient || "No client"} +

    + {project.description && ( +

    + {project.description} +

    + )} +
    + + {(canEditProject || canDeleteProject) && ( +
    + {canEditProject && ( + + )} + + {canDeleteProject && ( + + )} +
    + )} +
  • + ))} +
+ )} +
+
+ + { )} {/* Modals */} - {canCreateProject && isCreateModalOpen && ( - setIsCreateModalOpen(false)} - /> - )} - - {canEditProject && editingProject && ( - setIsCreateModalOpen(false)} + /> + )} + + {canEditProject && editingProject && ( + setEditingProject(null)} diff --git a/src/pages/Tags.tsx b/src/pages/Tags.tsx index f8bd659..cd8dabc 100644 --- a/src/pages/Tags.tsx +++ b/src/pages/Tags.tsx @@ -153,7 +153,7 @@ export default function Tags() {
{canCreateTag && ( )}