@burdenoff/microfe-workspaces 2026.510.50 → 2026.511.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/generated/wspace-operations.d.ts +91 -0
- package/dist/generated/wspace-operations.d.ts.map +1 -1
- package/dist/generated/wspace-operations.js +79 -51
- package/dist/generated/wspace-operations.js.map +1 -1
- package/dist/hooks/useMemberMutations.d.ts.map +1 -1
- package/dist/hooks/useMemberMutations.js +141 -60
- package/dist/hooks/useMemberMutations.js.map +1 -1
- package/dist/hooks/useProjectMutations.d.ts.map +1 -1
- package/dist/hooks/useProjectMutations.js +84 -44
- package/dist/hooks/useProjectMutations.js.map +1 -1
- package/dist/hooks/useWorkspaceMutations.d.ts.map +1 -1
- package/dist/hooks/useWorkspaceMutations.js +64 -29
- package/dist/hooks/useWorkspaceMutations.js.map +1 -1
- package/dist/hooks/useWorkspacesEventEmitter.d.ts +5 -1
- package/dist/hooks/useWorkspacesEventEmitter.d.ts.map +1 -1
- package/dist/hooks/useWorkspacesEventEmitter.js +8 -7
- package/dist/hooks/useWorkspacesEventEmitter.js.map +1 -1
- package/dist/hooks/useWorkspacesPageView.d.ts +27 -0
- package/dist/hooks/useWorkspacesPageView.d.ts.map +1 -0
- package/dist/hooks/useWorkspacesPageView.js +29 -0
- package/dist/hooks/useWorkspacesPageView.js.map +1 -0
- package/dist/pages/ActivityListPage.d.ts.map +1 -1
- package/dist/pages/ActivityListPage.js +59 -56
- package/dist/pages/ActivityListPage.js.map +1 -1
- package/dist/pages/CreateWorkspacePage.d.ts.map +1 -1
- package/dist/pages/CreateWorkspacePage.js +104 -104
- package/dist/pages/CreateWorkspacePage.js.map +1 -1
- package/dist/pages/InviteAcceptancePage.d.ts.map +1 -1
- package/dist/pages/InviteAcceptancePage.js +197 -216
- package/dist/pages/InviteAcceptancePage.js.map +1 -1
- package/dist/pages/MembersListPage.d.ts.map +1 -1
- package/dist/pages/MembersListPage.js +142 -138
- package/dist/pages/MembersListPage.js.map +1 -1
- package/dist/pages/ProjectDetailPage.d.ts.map +1 -1
- package/dist/pages/ProjectDetailPage.js +181 -176
- package/dist/pages/ProjectDetailPage.js.map +1 -1
- package/dist/pages/ProjectsListPage.d.ts.map +1 -1
- package/dist/pages/ProjectsListPage.js +175 -171
- package/dist/pages/ProjectsListPage.js.map +1 -1
- package/dist/pages/WorkspaceDetailPage.d.ts.map +1 -1
- package/dist/pages/WorkspaceDetailPage.js +104 -101
- package/dist/pages/WorkspaceDetailPage.js.map +1 -1
- package/dist/pages/WorkspaceSettingsPage.d.ts.map +1 -1
- package/dist/pages/WorkspaceSettingsPage.js +182 -137
- package/dist/pages/WorkspaceSettingsPage.js.map +1 -1
- package/dist/pages/WorkspacesListPage.d.ts.map +1 -1
- package/dist/pages/WorkspacesListPage.js +77 -77
- package/dist/pages/WorkspacesListPage.js.map +1 -1
- package/dist/pages/dashboard/DashboardCustomizer.d.ts.map +1 -1
- package/dist/pages/dashboard/DashboardCustomizer.js +53 -55
- package/dist/pages/dashboard/DashboardCustomizer.js.map +1 -1
- package/dist/pages/dashboard/DashboardGrid.d.ts.map +1 -1
- package/dist/pages/dashboard/DashboardGrid.js +33 -36
- package/dist/pages/dashboard/DashboardGrid.js.map +1 -1
- package/dist/pages/dashboard/DashboardPage.d.ts.map +1 -1
- package/dist/pages/dashboard/DashboardPage.js +67 -65
- package/dist/pages/dashboard/DashboardPage.js.map +1 -1
- package/dist/pages/dashboard/WidgetWrapper.d.ts.map +1 -1
- package/dist/pages/dashboard/WidgetWrapper.js +3 -6
- package/dist/pages/dashboard/WidgetWrapper.js.map +1 -1
- package/dist/utils/i18n.d.ts +13 -0
- package/dist/utils/i18n.d.ts.map +1 -0
- package/dist/utils/i18n.js +12 -0
- package/dist/utils/i18n.js.map +1 -0
- package/dist/utils/telemetryError.d.ts +2 -0
- package/dist/utils/telemetryError.d.ts.map +1 -0
- package/dist/utils/telemetryError.js +28 -0
- package/dist/utils/telemetryError.js.map +1 -0
- package/package.json +9 -4
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ProjectsListPage.js","names":[],"sources":["../../src/pages/ProjectsListPage.tsx"],"sourcesContent":["import { useCallback, useEffect, useMemo, useState } from 'react';\nimport { useParams } from 'react-router-dom';\nimport { FolderKanban, Plus, Grid3x3, List, Search } from 'lucide-react';\nimport { TagBadge } from '@burdenoff/fe-libs/tag';\nimport {\n Button,\n Input,\n Card,\n CardContent,\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n Skeleton,\n} from '@burdenoff/fe-libs/ui';\nimport { useDebounce } from '@burdenoff/fe-libs/shared/hooks';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { useWorkspacesStore } from '../store/workspacesStore';\nimport { nativeConfirm, nativeImpact } from '../utils/nativeBridge';\nimport { useProjects } from '../hooks/useProjects';\nimport {\n useArchiveProject,\n useDeleteProject,\n useUnarchiveProject,\n} from '../hooks/useProjectMutations';\nimport { ProjectCard } from '../components/ProjectCard';\nimport { CreateProjectDialog } from '../components/CreateProjectDialog';\nimport { useWorkspacePermissions } from '../hooks/useWorkspacePermissions';\nimport type { ProjectTag, Workspace } from '../types';\n\nexport function ProjectsListPage() {\n const { t } = useI18n();\n const tr = useCallback(\n (key: string, fallback: string): string => {\n const value = t(key);\n return value === key ? fallback : value;\n },\n [t]\n );\n\n const { workspaceId } = useParams<{ workspaceId: string }>();\n const {\n viewMode,\n setViewMode,\n projectFilters,\n setProjectFilters,\n clearProjectFilters,\n selectedProjectIds,\n toggleProjectSelection,\n clearProjectSelection,\n openCreateProjectDialog,\n isCreateProjectDialogOpen,\n } = useWorkspacesStore();\n\n const [searchValue, setSearchValue] = useState(projectFilters.search || '');\n const [activeTagFilters, setActiveTagFilters] = useState<ProjectTag[]>([]);\n const [matchAllTagFilters, setMatchAllTagFilters] = useState(true);\n const debouncedSearch = useDebounce(searchValue, 500);\n\n // Update filters when debounced search changes\n useEffect(() => {\n setProjectFilters({ search: debouncedSearch });\n }, [debouncedSearch, setProjectFilters]);\n\n useEffect(() => {\n if (activeTagFilters.length === 0) {\n setProjectFilters({\n tagIds: undefined,\n tagHierarchyPaths: undefined,\n matchAllTags: undefined,\n includeDescendants: undefined,\n });\n return;\n }\n\n setProjectFilters({\n tagIds: activeTagFilters.map((tag) => tag.tagId),\n tagHierarchyPaths: activeTagFilters\n .map((tag) => tag.hierarchyPath)\n .filter((tagPath): tagPath is string => typeof tagPath === 'string' && tagPath.length > 0),\n matchAllTags: matchAllTagFilters,\n includeDescendants: true,\n });\n }, [activeTagFilters, matchAllTagFilters, setProjectFilters]);\n\n useEffect(() => {\n return () => clearProjectSelection();\n }, [clearProjectSelection]);\n\n const { data, isLoading, error } = useProjects(projectFilters, undefined, workspaceId);\n const { mutateAsync: archiveProject } = useArchiveProject(workspaceId);\n const { mutateAsync: unarchiveProject } = useUnarchiveProject(workspaceId);\n const { mutateAsync: deleteProject } = useDeleteProject(workspaceId);\n\n const selectedProjects = useMemo(\n () => data?.items.filter((project) => selectedProjectIds.has(project.id)) ?? [],\n [data?.items, selectedProjectIds]\n );\n\n const archivableProjects = useMemo(\n () => selectedProjects.filter((project) => !project.archived),\n [selectedProjects]\n );\n\n const unarchivableProjects = useMemo(\n () => selectedProjects.filter((project) => project.archived),\n [selectedProjects]\n );\n\n const allVisibleSelected =\n (data?.items.length ?? 0) > 0 &&\n (data?.items ?? []).every((project) => selectedProjectIds.has(project.id));\n const partiallySelected =\n (data?.items ?? []).some((project) => selectedProjectIds.has(project.id)) &&\n !allVisibleSelected;\n\n const {\n canListProjects,\n canCreateProject,\n canDeleteProject,\n canArchiveProject,\n isLoading: permissionsLoading,\n } = useWorkspacePermissions();\n\n if (permissionsLoading) {\n return (\n <div className=\"space-y-4 p-6\">\n <Skeleton className=\"h-10 w-1/3\" />\n <div className=\"grid grid-cols-1 md:grid-cols-3 gap-4\">\n <Skeleton className=\"h-32\" />\n <Skeleton className=\"h-32\" />\n <Skeleton className=\"h-32\" />\n </div>\n </div>\n );\n }\n\n if (!canListProjects) {\n return (\n <div className=\"flex items-center justify-center min-h-[400px]\">\n <div className=\"text-center space-y-2\">\n <h2 className=\"text-lg font-semibold\">\n {tr('projectsList.accessDenied', 'Access Denied')}\n </h2>\n <p className=\"text-sm text-muted-foreground\">\n {tr(\n 'projectsList.noPermissionToViewProjects',\n \"You don't have permission to view projects.\"\n )}\n </p>\n </div>\n </div>\n );\n }\n\n const handleCreateProject = () => {\n openCreateProjectDialog({} as Workspace);\n };\n\n const handleStatusFilter = (value: string) => {\n if (value === 'all') {\n const nextFilters = { ...projectFilters };\n delete nextFilters.status;\n setProjectFilters(nextFilters);\n } else {\n setProjectFilters({ status: value as 'ACTIVE' | 'INACTIVE' | 'ARCHIVED' });\n }\n };\n\n const handleArchivedFilter = (value: string) => {\n if (value === 'all') {\n const nextFilters = { ...projectFilters };\n delete nextFilters.archived;\n setProjectFilters(nextFilters);\n } else {\n setProjectFilters({ archived: value === 'true' });\n }\n };\n\n const toggleTagFilter = (tag: ProjectTag) => {\n setActiveTagFilters((current) => {\n const exists = current.some((entry) => entry.tagId === tag.tagId);\n if (exists) {\n return current.filter((entry) => entry.tagId !== tag.tagId);\n }\n\n return [...current, tag];\n });\n };\n\n const clearAllProjectFilters = () => {\n setSearchValue('');\n setActiveTagFilters([]);\n setMatchAllTagFilters(true);\n clearProjectFilters();\n };\n\n const toggleAllProjects = (checked: boolean) => {\n (data?.items ?? []).forEach((project) => {\n const isSelected = selectedProjectIds.has(project.id);\n if (checked !== isSelected) {\n toggleProjectSelection(project.id);\n }\n });\n };\n\n const handleBulkArchive = async () => {\n if (archivableProjects.length === 0) return;\n await Promise.allSettled(archivableProjects.map((project) => archiveProject(project.id)));\n clearProjectSelection();\n };\n\n const handleBulkUnarchive = async () => {\n if (unarchivableProjects.length === 0) return;\n await Promise.allSettled(unarchivableProjects.map((project) => unarchiveProject(project.id)));\n clearProjectSelection();\n };\n\n const handleBulkDelete = async () => {\n if (selectedProjects.length === 0) return;\n void nativeImpact('medium');\n const message =\n tr('projectsList.bulkDeleteConfirmPrefix', 'Delete ') +\n selectedProjects.length +\n ' ' +\n tr('projectsList.bulkDeleteConfirmProject', 'selected project') +\n (selectedProjects.length === 1 ? '' : tr('projectsList.bulkDeleteConfirmPluralSuffix', 's')) +\n tr('projectsList.bulkDeleteConfirmSuffix', '? This cannot be undone.');\n const native = await nativeConfirm({\n title: 'Delete projects',\n message,\n okButtonTitle: 'Delete',\n cancelButtonTitle: 'Cancel',\n });\n const confirmed = native === null ? window.confirm(message) : native;\n if (!confirmed) return;\n\n await Promise.allSettled(selectedProjects.map((project) => deleteProject(project.id)));\n clearProjectSelection();\n };\n\n return (\n <div className=\"space-y-4 sm:space-y-6 p-3 sm:p-6\">\n {/* Header */}\n <div className=\"flex flex-col sm:flex-row sm:items-center justify-between gap-4\">\n <div>\n <h1 className=\"text-2xl sm:text-3xl font-bold\">\n {tr('projectsList.pageTitle', 'Projects')}\n </h1>\n <p className=\"text-muted-foreground\">\n {tr('projectsList.pageSubtitle', 'Manage and organize your projects')}\n </p>\n </div>\n <div className=\"flex items-center gap-2\">\n {/* View mode toggle */}\n <div className=\"flex items-center gap-1 border rounded-lg p-1\">\n <Button\n variant={viewMode === 'grid' ? 'secondary' : 'ghost'}\n size=\"sm\"\n onClick={() => setViewMode('grid')}\n className=\"h-8 w-8 p-0\"\n aria-label={tr('projectsList.gridViewAriaLabel', 'Show projects in grid view')}\n >\n <Grid3x3 size={16} />\n </Button>\n <Button\n variant={viewMode === 'list' ? 'secondary' : 'ghost'}\n size=\"sm\"\n onClick={() => setViewMode('list')}\n className=\"h-8 w-8 p-0\"\n aria-label={tr('projectsList.listViewAriaLabel', 'Show projects in list view')}\n >\n <List size={16} />\n </Button>\n </div>\n {canCreateProject && (\n <Button onClick={handleCreateProject}>\n <Plus className=\"h-4 w-4 sm:mr-2\" />\n <span className=\"hidden sm:inline\">\n {tr('projectsList.createProject', 'Create Project')}\n </span>\n </Button>\n )}\n </div>\n </div>\n\n {/* Filters & Search */}\n <div className=\"flex flex-col sm:flex-row gap-3\">\n <div className=\"relative flex-1\">\n <Search\n className=\"absolute left-3 top-1/2 transform -translate-y-1/2 text-muted-foreground\"\n size={18}\n />\n <Input\n placeholder={tr('projectsList.searchPlaceholder', 'Search projects...')}\n value={searchValue}\n onChange={(e) => setSearchValue(e.target.value)}\n className=\"pl-[3.25rem]\"\n />\n </div>\n <Select value={projectFilters.status || 'all'} onValueChange={handleStatusFilter}>\n <SelectTrigger className=\"w-full sm:w-[180px]\">\n <SelectValue placeholder={tr('projectsList.filterByStatus', 'Filter by status')} />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"all\">{tr('projectsList.statusAll', 'All Statuses')}</SelectItem>\n <SelectItem value=\"ACTIVE\">{tr('projectsList.statusActive', 'Active')}</SelectItem>\n <SelectItem value=\"INACTIVE\">\n {tr('projectsList.statusInactive', 'Inactive')}\n </SelectItem>\n </SelectContent>\n </Select>\n <Select\n value={\n projectFilters.archived === undefined\n ? 'all'\n : projectFilters.archived\n ? 'true'\n : 'false'\n }\n onValueChange={handleArchivedFilter}\n >\n <SelectTrigger className=\"w-full sm:w-[180px]\">\n <SelectValue placeholder={tr('projectsList.filterByArchive', 'Filter by archive')} />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"all\">{tr('projectsList.archiveAll', 'All Projects')}</SelectItem>\n <SelectItem value=\"false\">\n {tr('projectsList.archiveActiveProjects', 'Active Projects')}\n </SelectItem>\n <SelectItem value=\"true\">{tr('projectsList.archiveArchived', 'Archived')}</SelectItem>\n </SelectContent>\n </Select>\n {(projectFilters.search ||\n projectFilters.status ||\n projectFilters.archived !== undefined ||\n activeTagFilters.length > 0) && (\n <Button variant=\"outline\" onClick={clearAllProjectFilters}>\n {tr('projectsList.clearFilters', 'Clear Filters')}\n </Button>\n )}\n </div>\n\n {activeTagFilters.length > 0 && (\n <div className=\"flex flex-col gap-3 rounded-lg border border-border bg-card px-4 py-3\">\n <div className=\"flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between\">\n <div>\n <p className=\"text-sm font-medium\">\n {tr('projectsList.activeTagFilters', 'Active tag filters')}\n </p>\n <p className=\"text-xs text-muted-foreground\">\n {tr(\n 'projectsList.activeTagFiltersDescription',\n 'Click a project tag to add or remove it from the current filter set.'\n )}\n </p>\n </div>\n <Select\n value={matchAllTagFilters ? 'all' : 'any'}\n onValueChange={(value) => setMatchAllTagFilters(value === 'all')}\n >\n <SelectTrigger className=\"w-full sm:w-[180px]\">\n <SelectValue placeholder={tr('projectsList.tagMatchMode', 'Tag match mode')} />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"all\">\n {tr('projectsList.tagMatchAll', 'Match all tags')}\n </SelectItem>\n <SelectItem value=\"any\">\n {tr('projectsList.tagMatchAny', 'Match any tag')}\n </SelectItem>\n </SelectContent>\n </Select>\n </div>\n\n <div className=\"flex flex-wrap gap-2\">\n {activeTagFilters.map((tag) => (\n <TagBadge\n key={tag.tagId}\n id={tag.tagId}\n label={tag.label}\n color={tag.color ?? undefined}\n icon={tag.icon ?? undefined}\n description={tag.description ?? undefined}\n removable\n onRemove={() => toggleTagFilter(tag)}\n size=\"sm\"\n />\n ))}\n </div>\n </div>\n )}\n\n {/* Error State */}\n {error && (\n <Card className=\"border-destructive\">\n <CardContent className=\"pt-6\">\n <div className=\"flex flex-col items-center justify-center py-8 text-center\">\n <p className=\"text-destructive font-semibold mb-2\">\n {tr('projectsList.errorLoading', 'Error loading projects')}\n </p>\n <p className=\"text-sm text-muted-foreground\">\n {error instanceof Error\n ? error.message\n : tr('projectsList.unknownError', 'An unknown error occurred')}\n </p>\n </div>\n </CardContent>\n </Card>\n )}\n\n {/* Loading State */}\n {isLoading && (\n <div className=\"grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-4\">\n {Array.from({ length: 6 }).map((_, i) => (\n <Card key={i}>\n <CardContent className=\"pt-6\">\n <div className=\"space-y-3\">\n <Skeleton className=\"h-12 w-12 rounded-lg\" />\n <Skeleton className=\"h-4 w-3/4\" />\n <Skeleton className=\"h-4 w-1/2\" />\n </div>\n </CardContent>\n </Card>\n ))}\n </div>\n )}\n\n {/* Empty State */}\n {!isLoading && !error && data?.items.length === 0 && (\n <Card>\n <CardContent className=\"pt-6\">\n <div className=\"flex flex-col items-center justify-center py-12 text-center\">\n <div className=\"rounded-full bg-muted p-6 mb-4\">\n <FolderKanban size={48} className=\"text-muted-foreground\" />\n </div>\n <h3 className=\"text-lg font-semibold mb-2\">\n {tr('projectsList.noProjectsFound', 'No projects found')}\n </h3>\n <p className=\"text-muted-foreground max-w-sm mb-4\">\n {projectFilters.search\n ? tr('projectsList.adjustSearchOrFilters', 'Try adjusting your search or filters')\n : tr(\n 'projectsList.createFirstProject',\n 'Create your first project to get started organizing your work'\n )}\n </p>\n {!projectFilters.search && canCreateProject && (\n <Button onClick={handleCreateProject}>\n <Plus size={16} className=\"mr-2\" />\n {tr('projectsList.createProject', 'Create Project')}\n </Button>\n )}\n </div>\n </CardContent>\n </Card>\n )}\n\n {/* Projects Grid */}\n {!isLoading && !error && data && data.items.length > 0 && (\n <>\n <div className=\"flex flex-col gap-3 rounded-lg border bg-card p-4 sm:flex-row sm:items-center sm:justify-between\">\n <label className=\"flex items-center gap-2 text-sm text-foreground\">\n <input\n type=\"checkbox\"\n checked={allVisibleSelected}\n ref={(input) => {\n if (input) {\n input.indeterminate = partiallySelected && !allVisibleSelected;\n }\n }}\n onChange={(event) => toggleAllProjects(event.target.checked)}\n aria-label={tr('projectsList.selectAllAriaLabel', 'Select all projects')}\n className=\"h-4 w-4 rounded border-border text-primary\"\n />\n <span>{tr('projectsList.selectAllVisible', 'Select all visible')}</span>\n </label>\n\n <div className=\"flex flex-wrap items-center gap-2\">\n <span className=\"text-sm text-muted-foreground\">\n {selectedProjectIds.size} {tr('projectsList.selected', 'selected')}\n </span>\n {selectedProjectIds.size > 0 && (\n <Button variant=\"ghost\" size=\"sm\" onClick={clearProjectSelection}>\n {tr('projectsList.clearSelection', 'Clear selection')}\n </Button>\n )}\n {canArchiveProject && (\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={handleBulkArchive}\n disabled={archivableProjects.length === 0}\n >\n {tr('projectsList.archiveSelected', 'Archive Selected')}\n {archivableProjects.length > 0 ? ` (${archivableProjects.length})` : ''}\n </Button>\n )}\n {canArchiveProject && (\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={handleBulkUnarchive}\n disabled={unarchivableProjects.length === 0}\n >\n {tr('projectsList.unarchiveSelected', 'Unarchive Selected')}\n {unarchivableProjects.length > 0 ? ` (${unarchivableProjects.length})` : ''}\n </Button>\n )}\n {canDeleteProject && (\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={handleBulkDelete}\n disabled={selectedProjects.length === 0}\n className=\"text-destructive\"\n >\n {tr('projectsList.deleteSelected', 'Delete Selected')}\n {selectedProjects.length > 0 ? ` (${selectedProjects.length})` : ''}\n </Button>\n )}\n </div>\n </div>\n\n <div\n className={\n viewMode === 'list'\n ? 'space-y-3'\n : 'grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-4'\n }\n >\n {data.items.map((project) => (\n <ProjectCard\n key={project.id}\n project={project}\n selected={selectedProjectIds.has(project.id)}\n canArchive={canArchiveProject}\n canDelete={canDeleteProject}\n onTagClick={toggleTagFilter}\n onToggleSelect={(checked) => {\n const isSelected = selectedProjectIds.has(project.id);\n if (checked !== isSelected) {\n toggleProjectSelection(project.id);\n }\n }}\n />\n ))}\n </div>\n\n {/* Pagination Info */}\n {data.total > data.items.length && (\n <div className=\"text-center text-sm text-muted-foreground\">\n {tr('projectsList.showingPrefix', 'Showing')} {data.items.length}{' '}\n {tr('projectsList.showingOf', 'of')} {data.total}{' '}\n {tr('projectsList.showingProjects', 'projects')}\n </div>\n )}\n </>\n )}\n\n {/* Create Project Dialog */}\n {isCreateProjectDialogOpen && <CreateProjectDialog workspaceId={workspaceId} />}\n </div>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ProjectsListPage.js","names":[],"sources":["../../src/pages/ProjectsListPage.tsx"],"sourcesContent":["import { useEffect, useMemo, useState } from 'react';\nimport { useParams } from 'react-router-dom';\nimport { FolderKanban, Plus, Grid3x3, List, Search } from 'lucide-react';\nimport { TagBadge } from '@burdenoff/fe-libs/tag';\nimport {\n Button,\n Input,\n Card,\n CardContent,\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n Skeleton,\n} from '@burdenoff/fe-libs/ui';\nimport { useDebounce } from '@burdenoff/fe-libs/shared/hooks';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { useWorkspacesStore } from '../store/workspacesStore';\nimport { nativeConfirm, nativeImpact } from '../utils/nativeBridge';\nimport { useProjects } from '../hooks/useProjects';\nimport {\n useArchiveProject,\n useDeleteProject,\n useUnarchiveProject,\n} from '../hooks/useProjectMutations';\nimport { ProjectCard } from '../components/ProjectCard';\nimport { CreateProjectDialog } from '../components/CreateProjectDialog';\nimport { useWorkspacePermissions } from '../hooks/useWorkspacePermissions';\nimport { useWorkspacesPageView } from '../hooks/useWorkspacesPageView';\nimport { tWithFallback } from '../utils/i18n';\nimport type { ProjectTag, Workspace } from '../types';\n\nexport function ProjectsListPage() {\n const { t } = useI18n();\n\n const { workspaceId } = useParams<{ workspaceId: string }>();\n useWorkspacesPageView('workspaces.projects', { workspaceId, requireParams: true });\n const {\n viewMode,\n setViewMode,\n projectFilters,\n setProjectFilters,\n clearProjectFilters,\n selectedProjectIds,\n toggleProjectSelection,\n clearProjectSelection,\n openCreateProjectDialog,\n isCreateProjectDialogOpen,\n } = useWorkspacesStore();\n\n const [searchValue, setSearchValue] = useState(projectFilters.search || '');\n const [activeTagFilters, setActiveTagFilters] = useState<ProjectTag[]>([]);\n const [matchAllTagFilters, setMatchAllTagFilters] = useState(true);\n const debouncedSearch = useDebounce(searchValue, 500);\n\n // Update filters when debounced search changes\n useEffect(() => {\n setProjectFilters({ search: debouncedSearch });\n }, [debouncedSearch, setProjectFilters]);\n\n useEffect(() => {\n if (activeTagFilters.length === 0) {\n setProjectFilters({\n tagIds: undefined,\n tagHierarchyPaths: undefined,\n matchAllTags: undefined,\n includeDescendants: undefined,\n });\n return;\n }\n\n setProjectFilters({\n tagIds: activeTagFilters.map((tag) => tag.tagId),\n tagHierarchyPaths: activeTagFilters\n .map((tag) => tag.hierarchyPath)\n .filter((tagPath): tagPath is string => typeof tagPath === 'string' && tagPath.length > 0),\n matchAllTags: matchAllTagFilters,\n includeDescendants: true,\n });\n }, [activeTagFilters, matchAllTagFilters, setProjectFilters]);\n\n useEffect(() => {\n return () => clearProjectSelection();\n }, [clearProjectSelection]);\n\n const { data, isLoading, error } = useProjects(projectFilters, undefined, workspaceId);\n const { mutateAsync: archiveProject } = useArchiveProject(workspaceId);\n const { mutateAsync: unarchiveProject } = useUnarchiveProject(workspaceId);\n const { mutateAsync: deleteProject } = useDeleteProject(workspaceId);\n\n const selectedProjects = useMemo(\n () => data?.items.filter((project) => selectedProjectIds.has(project.id)) ?? [],\n [data?.items, selectedProjectIds]\n );\n\n const archivableProjects = useMemo(\n () => selectedProjects.filter((project) => !project.archived),\n [selectedProjects]\n );\n\n const unarchivableProjects = useMemo(\n () => selectedProjects.filter((project) => project.archived),\n [selectedProjects]\n );\n\n const allVisibleSelected =\n (data?.items.length ?? 0) > 0 &&\n (data?.items ?? []).every((project) => selectedProjectIds.has(project.id));\n const partiallySelected =\n (data?.items ?? []).some((project) => selectedProjectIds.has(project.id)) &&\n !allVisibleSelected;\n\n const {\n canListProjects,\n canCreateProject,\n canDeleteProject,\n canArchiveProject,\n isLoading: permissionsLoading,\n } = useWorkspacePermissions();\n\n if (permissionsLoading) {\n return (\n <div className=\"space-y-4 p-6\">\n <Skeleton className=\"h-10 w-1/3\" />\n <div className=\"grid grid-cols-1 md:grid-cols-3 gap-4\">\n <Skeleton className=\"h-32\" />\n <Skeleton className=\"h-32\" />\n <Skeleton className=\"h-32\" />\n </div>\n </div>\n );\n }\n\n if (!canListProjects) {\n return (\n <div className=\"flex items-center justify-center min-h-[400px]\">\n <div className=\"text-center space-y-2\">\n <h2 className=\"text-lg font-semibold\">\n {tWithFallback(t, 'projectsList.accessDenied', 'Access Denied')}\n </h2>\n <p className=\"text-sm text-muted-foreground\">\n {tWithFallback(\n t,\n 'projectsList.noPermissionToViewProjects',\n \"You don't have permission to view projects.\"\n )}\n </p>\n </div>\n </div>\n );\n }\n\n const handleCreateProject = () => {\n openCreateProjectDialog({} as Workspace);\n };\n\n const handleStatusFilter = (value: string) => {\n if (value === 'all') {\n const nextFilters = { ...projectFilters };\n delete nextFilters.status;\n setProjectFilters(nextFilters);\n } else {\n setProjectFilters({ status: value as 'ACTIVE' | 'INACTIVE' | 'ARCHIVED' });\n }\n };\n\n const handleArchivedFilter = (value: string) => {\n if (value === 'all') {\n const nextFilters = { ...projectFilters };\n delete nextFilters.archived;\n setProjectFilters(nextFilters);\n } else {\n setProjectFilters({ archived: value === 'true' });\n }\n };\n\n const toggleTagFilter = (tag: ProjectTag) => {\n setActiveTagFilters((current) => {\n const exists = current.some((entry) => entry.tagId === tag.tagId);\n if (exists) {\n return current.filter((entry) => entry.tagId !== tag.tagId);\n }\n\n return [...current, tag];\n });\n };\n\n const clearAllProjectFilters = () => {\n setSearchValue('');\n setActiveTagFilters([]);\n setMatchAllTagFilters(true);\n clearProjectFilters();\n };\n\n const toggleAllProjects = (checked: boolean) => {\n (data?.items ?? []).forEach((project) => {\n const isSelected = selectedProjectIds.has(project.id);\n if (checked !== isSelected) {\n toggleProjectSelection(project.id);\n }\n });\n };\n\n const handleBulkArchive = async () => {\n if (archivableProjects.length === 0) return;\n await Promise.allSettled(archivableProjects.map((project) => archiveProject(project.id)));\n clearProjectSelection();\n };\n\n const handleBulkUnarchive = async () => {\n if (unarchivableProjects.length === 0) return;\n await Promise.allSettled(unarchivableProjects.map((project) => unarchiveProject(project.id)));\n clearProjectSelection();\n };\n\n const handleBulkDelete = async () => {\n if (selectedProjects.length === 0) return;\n void nativeImpact('medium');\n const message =\n tWithFallback(t, 'projectsList.bulkDeleteConfirmPrefix', 'Delete ') +\n selectedProjects.length +\n ' ' +\n tWithFallback(t, 'projectsList.bulkDeleteConfirmProject', 'selected project') +\n (selectedProjects.length === 1\n ? ''\n : tWithFallback(t, 'projectsList.bulkDeleteConfirmPluralSuffix', 's')) +\n tWithFallback(t, 'projectsList.bulkDeleteConfirmSuffix', '? This cannot be undone.');\n const native = await nativeConfirm({\n title: 'Delete projects',\n message,\n okButtonTitle: 'Delete',\n cancelButtonTitle: 'Cancel',\n });\n const confirmed = native === null ? window.confirm(message) : native;\n if (!confirmed) return;\n\n await Promise.allSettled(selectedProjects.map((project) => deleteProject(project.id)));\n clearProjectSelection();\n };\n\n return (\n <div className=\"space-y-4 sm:space-y-6 p-3 sm:p-6\">\n {/* Header */}\n <div className=\"flex flex-col sm:flex-row sm:items-center justify-between gap-4\">\n <div>\n <h1 className=\"text-2xl sm:text-3xl font-bold\">\n {tWithFallback(t, 'projectsList.pageTitle', 'Projects')}\n </h1>\n <p className=\"text-muted-foreground\">\n {tWithFallback(t, 'projectsList.pageSubtitle', 'Manage and organize your projects')}\n </p>\n </div>\n <div className=\"flex items-center gap-2\">\n {/* View mode toggle */}\n <div className=\"flex items-center gap-1 border rounded-lg p-1\">\n <Button\n variant={viewMode === 'grid' ? 'secondary' : 'ghost'}\n size=\"sm\"\n onClick={() => setViewMode('grid')}\n className=\"h-8 w-8 p-0\"\n aria-label={tWithFallback(\n t,\n 'projectsList.gridViewAriaLabel',\n 'Show projects in grid view'\n )}\n >\n <Grid3x3 size={16} />\n </Button>\n <Button\n variant={viewMode === 'list' ? 'secondary' : 'ghost'}\n size=\"sm\"\n onClick={() => setViewMode('list')}\n className=\"h-8 w-8 p-0\"\n aria-label={tWithFallback(\n t,\n 'projectsList.listViewAriaLabel',\n 'Show projects in list view'\n )}\n >\n <List size={16} />\n </Button>\n </div>\n {canCreateProject && (\n <Button onClick={handleCreateProject}>\n <Plus className=\"h-4 w-4 sm:mr-2\" />\n <span className=\"hidden sm:inline\">\n {tWithFallback(t, 'projectsList.createProject', 'Create Project')}\n </span>\n </Button>\n )}\n </div>\n </div>\n\n {/* Filters & Search */}\n <div className=\"flex flex-col sm:flex-row gap-3\">\n <div className=\"relative flex-1\">\n <Search\n className=\"absolute left-3 top-1/2 transform -translate-y-1/2 text-muted-foreground\"\n size={18}\n />\n <Input\n placeholder={tWithFallback(t, 'projectsList.searchPlaceholder', 'Search projects...')}\n value={searchValue}\n onChange={(e) => setSearchValue(e.target.value)}\n className=\"pl-[3.25rem]\"\n />\n </div>\n <Select value={projectFilters.status || 'all'} onValueChange={handleStatusFilter}>\n <SelectTrigger className=\"w-full sm:w-[180px]\">\n <SelectValue\n placeholder={tWithFallback(t, 'projectsList.filterByStatus', 'Filter by status')}\n />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"all\">\n {tWithFallback(t, 'projectsList.statusAll', 'All Statuses')}\n </SelectItem>\n <SelectItem value=\"ACTIVE\">\n {tWithFallback(t, 'projectsList.statusActive', 'Active')}\n </SelectItem>\n <SelectItem value=\"INACTIVE\">\n {tWithFallback(t, 'projectsList.statusInactive', 'Inactive')}\n </SelectItem>\n </SelectContent>\n </Select>\n <Select\n value={\n projectFilters.archived === undefined\n ? 'all'\n : projectFilters.archived\n ? 'true'\n : 'false'\n }\n onValueChange={handleArchivedFilter}\n >\n <SelectTrigger className=\"w-full sm:w-[180px]\">\n <SelectValue\n placeholder={tWithFallback(t, 'projectsList.filterByArchive', 'Filter by archive')}\n />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"all\">\n {tWithFallback(t, 'projectsList.archiveAll', 'All Projects')}\n </SelectItem>\n <SelectItem value=\"false\">\n {tWithFallback(t, 'projectsList.archiveActiveProjects', 'Active Projects')}\n </SelectItem>\n <SelectItem value=\"true\">\n {tWithFallback(t, 'projectsList.archiveArchived', 'Archived')}\n </SelectItem>\n </SelectContent>\n </Select>\n {(projectFilters.search ||\n projectFilters.status ||\n projectFilters.archived !== undefined ||\n activeTagFilters.length > 0) && (\n <Button variant=\"outline\" onClick={clearAllProjectFilters}>\n {tWithFallback(t, 'projectsList.clearFilters', 'Clear Filters')}\n </Button>\n )}\n </div>\n\n {activeTagFilters.length > 0 && (\n <div className=\"flex flex-col gap-3 rounded-lg border border-border bg-card px-4 py-3\">\n <div className=\"flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between\">\n <div>\n <p className=\"text-sm font-medium\">\n {tWithFallback(t, 'projectsList.activeTagFilters', 'Active tag filters')}\n </p>\n <p className=\"text-xs text-muted-foreground\">\n {tWithFallback(\n t,\n 'projectsList.activeTagFiltersDescription',\n 'Click a project tag to add or remove it from the current filter set.'\n )}\n </p>\n </div>\n <Select\n value={matchAllTagFilters ? 'all' : 'any'}\n onValueChange={(value) => setMatchAllTagFilters(value === 'all')}\n >\n <SelectTrigger className=\"w-full sm:w-[180px]\">\n <SelectValue\n placeholder={tWithFallback(t, 'projectsList.tagMatchMode', 'Tag match mode')}\n />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"all\">\n {tWithFallback(t, 'projectsList.tagMatchAll', 'Match all tags')}\n </SelectItem>\n <SelectItem value=\"any\">\n {tWithFallback(t, 'projectsList.tagMatchAny', 'Match any tag')}\n </SelectItem>\n </SelectContent>\n </Select>\n </div>\n\n <div className=\"flex flex-wrap gap-2\">\n {activeTagFilters.map((tag) => (\n <TagBadge\n key={tag.tagId}\n id={tag.tagId}\n label={tag.label}\n color={tag.color ?? undefined}\n icon={tag.icon ?? undefined}\n description={tag.description ?? undefined}\n removable\n onRemove={() => toggleTagFilter(tag)}\n size=\"sm\"\n />\n ))}\n </div>\n </div>\n )}\n\n {/* Error State */}\n {error && (\n <Card className=\"border-destructive\">\n <CardContent className=\"pt-6\">\n <div className=\"flex flex-col items-center justify-center py-8 text-center\">\n <p className=\"text-destructive font-semibold mb-2\">\n {tWithFallback(t, 'projectsList.errorLoading', 'Error loading projects')}\n </p>\n <p className=\"text-sm text-muted-foreground\">\n {error instanceof Error\n ? error.message\n : tWithFallback(t, 'projectsList.unknownError', 'An unknown error occurred')}\n </p>\n </div>\n </CardContent>\n </Card>\n )}\n\n {/* Loading State */}\n {isLoading && (\n <div className=\"grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-4\">\n {Array.from({ length: 6 }).map((_, i) => (\n <Card key={i}>\n <CardContent className=\"pt-6\">\n <div className=\"space-y-3\">\n <Skeleton className=\"h-12 w-12 rounded-lg\" />\n <Skeleton className=\"h-4 w-3/4\" />\n <Skeleton className=\"h-4 w-1/2\" />\n </div>\n </CardContent>\n </Card>\n ))}\n </div>\n )}\n\n {/* Empty State */}\n {!isLoading && !error && data?.items.length === 0 && (\n <Card>\n <CardContent className=\"pt-6\">\n <div className=\"flex flex-col items-center justify-center py-12 text-center\">\n <div className=\"rounded-full bg-muted p-6 mb-4\">\n <FolderKanban size={48} className=\"text-muted-foreground\" />\n </div>\n <h3 className=\"text-lg font-semibold mb-2\">\n {tWithFallback(t, 'projectsList.noProjectsFound', 'No projects found')}\n </h3>\n <p className=\"text-muted-foreground max-w-sm mb-4\">\n {projectFilters.search\n ? tWithFallback(\n t,\n 'projectsList.adjustSearchOrFilters',\n 'Try adjusting your search or filters'\n )\n : tWithFallback(\n t,\n 'projectsList.createFirstProject',\n 'Create your first project to get started organizing your work'\n )}\n </p>\n {!projectFilters.search && canCreateProject && (\n <Button onClick={handleCreateProject}>\n <Plus size={16} className=\"mr-2\" />\n {tWithFallback(t, 'projectsList.createProject', 'Create Project')}\n </Button>\n )}\n </div>\n </CardContent>\n </Card>\n )}\n\n {/* Projects Grid */}\n {!isLoading && !error && data && data.items.length > 0 && (\n <>\n <div className=\"flex flex-col gap-3 rounded-lg border bg-card p-4 sm:flex-row sm:items-center sm:justify-between\">\n <label className=\"flex items-center gap-2 text-sm text-foreground\">\n <input\n type=\"checkbox\"\n checked={allVisibleSelected}\n ref={(input) => {\n if (input) {\n input.indeterminate = partiallySelected && !allVisibleSelected;\n }\n }}\n onChange={(event) => toggleAllProjects(event.target.checked)}\n aria-label={tWithFallback(\n t,\n 'projectsList.selectAllAriaLabel',\n 'Select all projects'\n )}\n className=\"h-4 w-4 rounded border-border text-primary\"\n />\n <span>{tWithFallback(t, 'projectsList.selectAllVisible', 'Select all visible')}</span>\n </label>\n\n <div className=\"flex flex-wrap items-center gap-2\">\n <span className=\"text-sm text-muted-foreground\">\n {selectedProjectIds.size} {tWithFallback(t, 'projectsList.selected', 'selected')}\n </span>\n {selectedProjectIds.size > 0 && (\n <Button variant=\"ghost\" size=\"sm\" onClick={clearProjectSelection}>\n {tWithFallback(t, 'projectsList.clearSelection', 'Clear selection')}\n </Button>\n )}\n {canArchiveProject && (\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={handleBulkArchive}\n disabled={archivableProjects.length === 0}\n >\n {tWithFallback(t, 'projectsList.archiveSelected', 'Archive Selected')}\n {archivableProjects.length > 0 ? ` (${archivableProjects.length})` : ''}\n </Button>\n )}\n {canArchiveProject && (\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={handleBulkUnarchive}\n disabled={unarchivableProjects.length === 0}\n >\n {tWithFallback(t, 'projectsList.unarchiveSelected', 'Unarchive Selected')}\n {unarchivableProjects.length > 0 ? ` (${unarchivableProjects.length})` : ''}\n </Button>\n )}\n {canDeleteProject && (\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={handleBulkDelete}\n disabled={selectedProjects.length === 0}\n className=\"text-destructive\"\n >\n {tWithFallback(t, 'projectsList.deleteSelected', 'Delete Selected')}\n {selectedProjects.length > 0 ? ` (${selectedProjects.length})` : ''}\n </Button>\n )}\n </div>\n </div>\n\n <div\n className={\n viewMode === 'list'\n ? 'space-y-3'\n : 'grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-4'\n }\n >\n {data.items.map((project) => (\n <ProjectCard\n key={project.id}\n project={project}\n selected={selectedProjectIds.has(project.id)}\n canArchive={canArchiveProject}\n canDelete={canDeleteProject}\n onTagClick={toggleTagFilter}\n onToggleSelect={(checked) => {\n const isSelected = selectedProjectIds.has(project.id);\n if (checked !== isSelected) {\n toggleProjectSelection(project.id);\n }\n }}\n />\n ))}\n </div>\n\n {/* Pagination Info */}\n {data.total > data.items.length && (\n <div className=\"text-center text-sm text-muted-foreground\">\n {tWithFallback(t, 'projectsList.showingPrefix', 'Showing')} {data.items.length}{' '}\n {tWithFallback(t, 'projectsList.showingOf', 'of')} {data.total}{' '}\n {tWithFallback(t, 'projectsList.showingProjects', 'projects')}\n </div>\n )}\n </>\n )}\n\n {/* Create Project Dialog */}\n {isCreateProjectDialogOpen && <CreateProjectDialog workspaceId={workspaceId} />}\n </div>\n );\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"WorkspaceDetailPage.d.ts","sourceRoot":"","sources":["../../src/pages/WorkspaceDetailPage.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"WorkspaceDetailPage.d.ts","sourceRoot":"","sources":["../../src/pages/WorkspaceDetailPage.tsx"],"names":[],"mappings":"AAsBA,wBAAgB,mBAAmB,4CA2PlC"}
|
|
@@ -1,223 +1,226 @@
|
|
|
1
1
|
import { useWorkspacesContext as e } from "../providers/WorkspacesProvider.js";
|
|
2
2
|
import { useWorkspace as t } from "../hooks/useWorkspaces.js";
|
|
3
3
|
import { useScopedNavigation as n } from "../hooks/useScopedNavigation.js";
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
4
|
+
import { tWithFallback as r } from "../utils/i18n.js";
|
|
5
|
+
import { useWorkspacesPageView as i } from "../hooks/useWorkspacesPageView.js";
|
|
6
|
+
import { useWorkspaceMembers as a } from "../hooks/useWorkspaceMembers.js";
|
|
7
|
+
import { useProjects as o } from "../hooks/useProjects.js";
|
|
8
|
+
import { useWorkspaceActivity as s } from "../hooks/useWorkspaceActivity.js";
|
|
9
|
+
import { useWorkspacePermissions as c } from "../hooks/useWorkspacePermissions.js";
|
|
10
|
+
import { Activity as l, ArrowLeft as u, ChevronRight as d, FolderKanban as f, Settings as p, Users as m } from "lucide-react";
|
|
11
|
+
import { Fragment as h, jsx as g, jsxs as _ } from "react/jsx-runtime";
|
|
12
|
+
import { Badge as v, Button as y, Card as b, CardContent as x, CardHeader as S, CardTitle as C, Skeleton as w } from "@burdenoff/fe-libs/ui";
|
|
13
|
+
import { useNavigate as T, useParams as E } from "react-router-dom";
|
|
14
|
+
import { useI18n as D } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
|
|
14
15
|
//#region src/pages/WorkspaceDetailPage.tsx
|
|
15
|
-
function
|
|
16
|
-
let {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
16
|
+
function O() {
|
|
17
|
+
let { workspaceId: O } = E();
|
|
18
|
+
i("workspaces.detail", {
|
|
19
|
+
workspaceId: O,
|
|
20
|
+
requireParams: !0
|
|
21
|
+
});
|
|
22
|
+
let { t: k } = D(), A = T(), { basePath: j = "/" } = e(), { withCurrentSearch: M } = n(), { data: N, isLoading: P, error: F } = t(O || ""), { data: I } = o({ workspaceId: O }, { limit: 1 }, O), { data: L } = a(O || "", { limit: 1 }), { data: R } = s(O), { canViewWorkspace: z, canUpdateWorkspace: B, isLoading: V } = c();
|
|
23
|
+
if (V) return /* @__PURE__ */ _("div", {
|
|
21
24
|
className: "space-y-4 sm:space-y-6 p-3 sm:p-6",
|
|
22
|
-
children: [/* @__PURE__ */
|
|
25
|
+
children: [/* @__PURE__ */ g(w, { className: "h-10 w-1/3" }), /* @__PURE__ */ _("div", {
|
|
23
26
|
className: "grid grid-cols-1 md:grid-cols-3 gap-4",
|
|
24
27
|
children: [
|
|
25
|
-
/* @__PURE__ */
|
|
26
|
-
/* @__PURE__ */
|
|
27
|
-
/* @__PURE__ */
|
|
28
|
+
/* @__PURE__ */ g(w, { className: "h-32" }),
|
|
29
|
+
/* @__PURE__ */ g(w, { className: "h-32" }),
|
|
30
|
+
/* @__PURE__ */ g(w, { className: "h-32" })
|
|
28
31
|
]
|
|
29
32
|
})]
|
|
30
33
|
});
|
|
31
|
-
if (!z) return /* @__PURE__ */
|
|
34
|
+
if (!z) return /* @__PURE__ */ g("div", {
|
|
32
35
|
className: "flex items-center justify-center min-h-[400px]",
|
|
33
|
-
children: /* @__PURE__ */
|
|
36
|
+
children: /* @__PURE__ */ _("div", {
|
|
34
37
|
className: "text-center space-y-2",
|
|
35
|
-
children: [/* @__PURE__ */
|
|
38
|
+
children: [/* @__PURE__ */ g("h2", {
|
|
36
39
|
className: "text-lg font-semibold",
|
|
37
|
-
children:
|
|
38
|
-
}), /* @__PURE__ */
|
|
40
|
+
children: r(k, "workspaceDetail.accessDenied", "Access Denied")
|
|
41
|
+
}), /* @__PURE__ */ g("p", {
|
|
39
42
|
className: "text-sm text-muted-foreground",
|
|
40
|
-
children:
|
|
43
|
+
children: r(k, "workspaceDetail.accessDeniedDesc", "You don't have permission to view this workspace.")
|
|
41
44
|
})]
|
|
42
45
|
})
|
|
43
46
|
});
|
|
44
|
-
if (P) return /* @__PURE__ */
|
|
47
|
+
if (P) return /* @__PURE__ */ _("div", {
|
|
45
48
|
className: "space-y-4 sm:space-y-6 p-3 sm:p-6",
|
|
46
|
-
children: [/* @__PURE__ */
|
|
49
|
+
children: [/* @__PURE__ */ g(w, { className: "h-10 w-1/3" }), /* @__PURE__ */ _("div", {
|
|
47
50
|
className: "grid grid-cols-1 md:grid-cols-3 gap-4",
|
|
48
51
|
children: [
|
|
49
|
-
/* @__PURE__ */
|
|
50
|
-
/* @__PURE__ */
|
|
51
|
-
/* @__PURE__ */
|
|
52
|
+
/* @__PURE__ */ g(w, { className: "h-32" }),
|
|
53
|
+
/* @__PURE__ */ g(w, { className: "h-32" }),
|
|
54
|
+
/* @__PURE__ */ g(w, { className: "h-32" })
|
|
52
55
|
]
|
|
53
56
|
})]
|
|
54
57
|
});
|
|
55
|
-
if (F || !N) return /* @__PURE__ */
|
|
58
|
+
if (F || !N) return /* @__PURE__ */ _("div", {
|
|
56
59
|
className: "space-y-4 p-6",
|
|
57
|
-
children: [/* @__PURE__ */
|
|
60
|
+
children: [/* @__PURE__ */ _(y, {
|
|
58
61
|
variant: "ghost",
|
|
59
62
|
onClick: () => A(M(`${j}/list`)),
|
|
60
63
|
className: "gap-2",
|
|
61
|
-
children: [/* @__PURE__ */
|
|
62
|
-
}), /* @__PURE__ */
|
|
64
|
+
children: [/* @__PURE__ */ g(u, { size: 20 }), r(k, "workspaceDetail.backToWorkspaces", "Back to Workspaces")]
|
|
65
|
+
}), /* @__PURE__ */ g("div", {
|
|
63
66
|
className: "text-center py-12",
|
|
64
|
-
children: /* @__PURE__ */
|
|
67
|
+
children: /* @__PURE__ */ g("p", {
|
|
65
68
|
className: "text-destructive",
|
|
66
|
-
children:
|
|
69
|
+
children: r(k, "workspaceDetail.notFound", "Workspace not found")
|
|
67
70
|
})
|
|
68
71
|
})]
|
|
69
72
|
});
|
|
70
73
|
let H = (e, t) => {
|
|
71
74
|
(e.key === "Enter" || e.key === " ") && (e.preventDefault(), A(t));
|
|
72
75
|
};
|
|
73
|
-
return /* @__PURE__ */
|
|
76
|
+
return /* @__PURE__ */ _("div", {
|
|
74
77
|
className: "space-y-4 sm:space-y-6 p-3 sm:p-6",
|
|
75
78
|
children: [
|
|
76
|
-
/* @__PURE__ */
|
|
79
|
+
/* @__PURE__ */ _("div", {
|
|
77
80
|
className: "flex flex-col sm:flex-row sm:items-center sm:justify-between gap-3",
|
|
78
|
-
children: [/* @__PURE__ */
|
|
79
|
-
/* @__PURE__ */
|
|
81
|
+
children: [/* @__PURE__ */ _("div", { children: [
|
|
82
|
+
/* @__PURE__ */ _(y, {
|
|
80
83
|
variant: "ghost",
|
|
81
84
|
onClick: () => A(M(`${j}/list`)),
|
|
82
85
|
className: "gap-2 mb-2 -ml-2",
|
|
83
|
-
children: [/* @__PURE__ */
|
|
86
|
+
children: [/* @__PURE__ */ g(u, { size: 20 }), r(k, "workspaceDetail.backToWorkspaces", "Back to Workspaces")]
|
|
84
87
|
}),
|
|
85
|
-
/* @__PURE__ */
|
|
88
|
+
/* @__PURE__ */ g("h1", {
|
|
86
89
|
className: "text-2xl sm:text-3xl font-bold",
|
|
87
90
|
children: N.name
|
|
88
91
|
}),
|
|
89
|
-
/* @__PURE__ */
|
|
92
|
+
/* @__PURE__ */ _("div", {
|
|
90
93
|
className: "flex items-center gap-2 mt-2",
|
|
91
|
-
children: [/* @__PURE__ */
|
|
94
|
+
children: [/* @__PURE__ */ g(v, {
|
|
92
95
|
variant: "outline",
|
|
93
96
|
children: N.type
|
|
94
|
-
}), /* @__PURE__ */
|
|
97
|
+
}), /* @__PURE__ */ g(v, { children: N.status })]
|
|
95
98
|
})
|
|
96
|
-
] }), B && /* @__PURE__ */
|
|
97
|
-
onClick: () => A(M(`${j}/${
|
|
99
|
+
] }), B && /* @__PURE__ */ _(y, {
|
|
100
|
+
onClick: () => A(M(`${j}/${O}/settings`)),
|
|
98
101
|
className: "gap-2",
|
|
99
|
-
children: [/* @__PURE__ */
|
|
102
|
+
children: [/* @__PURE__ */ g(p, { size: 20 }), r(k, "workspaceDetail.settings", "Settings")]
|
|
100
103
|
})]
|
|
101
104
|
}),
|
|
102
|
-
/* @__PURE__ */
|
|
105
|
+
/* @__PURE__ */ _("div", {
|
|
103
106
|
className: "grid grid-cols-1 md:grid-cols-3 gap-4",
|
|
104
107
|
children: [
|
|
105
|
-
/* @__PURE__ */
|
|
108
|
+
/* @__PURE__ */ _(b, {
|
|
106
109
|
className: "cursor-pointer hover:border-primary/50 hover:shadow-md transition-all duration-200",
|
|
107
|
-
onClick: () => A(M(`${j}/${
|
|
110
|
+
onClick: () => A(M(`${j}/${O}/projects`)),
|
|
108
111
|
role: "button",
|
|
109
112
|
tabIndex: 0,
|
|
110
|
-
onKeyDown: (e) => H(e, M(`${j}/${
|
|
111
|
-
children: [/* @__PURE__ */
|
|
113
|
+
onKeyDown: (e) => H(e, M(`${j}/${O}/projects`)),
|
|
114
|
+
children: [/* @__PURE__ */ _(S, {
|
|
112
115
|
className: "flex flex-row items-center justify-between pb-2",
|
|
113
|
-
children: [/* @__PURE__ */
|
|
116
|
+
children: [/* @__PURE__ */ _(C, {
|
|
114
117
|
className: "flex items-center gap-2",
|
|
115
|
-
children: [/* @__PURE__ */
|
|
118
|
+
children: [/* @__PURE__ */ g(f, {
|
|
116
119
|
size: 20,
|
|
117
120
|
className: "text-muted-foreground"
|
|
118
|
-
}),
|
|
119
|
-
}), /* @__PURE__ */
|
|
121
|
+
}), r(k, "workspaceDetail.projects", "Projects")]
|
|
122
|
+
}), /* @__PURE__ */ g(d, {
|
|
120
123
|
size: 20,
|
|
121
124
|
className: "text-muted-foreground"
|
|
122
125
|
})]
|
|
123
|
-
}), /* @__PURE__ */
|
|
126
|
+
}), /* @__PURE__ */ _(x, { children: [/* @__PURE__ */ g("p", {
|
|
124
127
|
className: "text-3xl font-bold",
|
|
125
128
|
children: I?.total ?? N.projectCount ?? 0
|
|
126
|
-
}), /* @__PURE__ */
|
|
129
|
+
}), /* @__PURE__ */ g("p", {
|
|
127
130
|
className: "text-sm text-muted-foreground",
|
|
128
|
-
children:
|
|
131
|
+
children: r(k, "workspaceDetail.projectsDesc", "Projects in this workspace")
|
|
129
132
|
})] })]
|
|
130
133
|
}),
|
|
131
|
-
/* @__PURE__ */
|
|
134
|
+
/* @__PURE__ */ _(b, {
|
|
132
135
|
className: "cursor-pointer hover:border-primary/50 hover:shadow-md transition-all duration-200",
|
|
133
|
-
onClick: () => A(M(`${j}/${
|
|
136
|
+
onClick: () => A(M(`${j}/${O}/members`)),
|
|
134
137
|
role: "button",
|
|
135
138
|
tabIndex: 0,
|
|
136
|
-
onKeyDown: (e) => H(e, M(`${j}/${
|
|
137
|
-
children: [/* @__PURE__ */
|
|
139
|
+
onKeyDown: (e) => H(e, M(`${j}/${O}/members`)),
|
|
140
|
+
children: [/* @__PURE__ */ _(S, {
|
|
138
141
|
className: "flex flex-row items-center justify-between pb-2",
|
|
139
|
-
children: [/* @__PURE__ */
|
|
142
|
+
children: [/* @__PURE__ */ _(C, {
|
|
140
143
|
className: "flex items-center gap-2",
|
|
141
|
-
children: [/* @__PURE__ */
|
|
144
|
+
children: [/* @__PURE__ */ g(m, {
|
|
142
145
|
size: 20,
|
|
143
146
|
className: "text-muted-foreground"
|
|
144
|
-
}),
|
|
145
|
-
}), /* @__PURE__ */
|
|
147
|
+
}), r(k, "workspaceDetail.members", "Members")]
|
|
148
|
+
}), /* @__PURE__ */ g(d, {
|
|
146
149
|
size: 20,
|
|
147
150
|
className: "text-muted-foreground"
|
|
148
151
|
})]
|
|
149
|
-
}), /* @__PURE__ */
|
|
152
|
+
}), /* @__PURE__ */ _(x, { children: [/* @__PURE__ */ g("p", {
|
|
150
153
|
className: "text-3xl font-bold",
|
|
151
154
|
children: L?.total ?? N.memberCount ?? 0
|
|
152
|
-
}), /* @__PURE__ */
|
|
155
|
+
}), /* @__PURE__ */ g("p", {
|
|
153
156
|
className: "text-sm text-muted-foreground",
|
|
154
|
-
children:
|
|
157
|
+
children: r(k, "workspaceDetail.membersDesc", "Workspace members")
|
|
155
158
|
})] })]
|
|
156
159
|
}),
|
|
157
|
-
/* @__PURE__ */
|
|
160
|
+
/* @__PURE__ */ _(b, {
|
|
158
161
|
className: "cursor-pointer hover:border-primary/50 hover:shadow-md transition-all duration-200",
|
|
159
|
-
onClick: () => A(M(`${j}/${
|
|
162
|
+
onClick: () => A(M(`${j}/${O}/activity`)),
|
|
160
163
|
role: "button",
|
|
161
164
|
tabIndex: 0,
|
|
162
|
-
onKeyDown: (e) => H(e, M(`${j}/${
|
|
163
|
-
children: [/* @__PURE__ */
|
|
165
|
+
onKeyDown: (e) => H(e, M(`${j}/${O}/activity`)),
|
|
166
|
+
children: [/* @__PURE__ */ _(S, {
|
|
164
167
|
className: "flex flex-row items-center justify-between pb-2",
|
|
165
|
-
children: [/* @__PURE__ */
|
|
168
|
+
children: [/* @__PURE__ */ _(C, {
|
|
166
169
|
className: "flex items-center gap-2",
|
|
167
|
-
children: [/* @__PURE__ */
|
|
170
|
+
children: [/* @__PURE__ */ g(l, {
|
|
168
171
|
size: 20,
|
|
169
172
|
className: "text-muted-foreground"
|
|
170
|
-
}),
|
|
171
|
-
}), /* @__PURE__ */
|
|
173
|
+
}), r(k, "workspaceDetail.activity", "Activity")]
|
|
174
|
+
}), /* @__PURE__ */ g(d, {
|
|
172
175
|
size: 20,
|
|
173
176
|
className: "text-muted-foreground"
|
|
174
177
|
})]
|
|
175
|
-
}), /* @__PURE__ */
|
|
178
|
+
}), /* @__PURE__ */ _(x, { children: [/* @__PURE__ */ g("p", {
|
|
176
179
|
className: "text-3xl font-bold",
|
|
177
180
|
children: R?.length ?? 0
|
|
178
|
-
}), /* @__PURE__ */
|
|
181
|
+
}), /* @__PURE__ */ g("p", {
|
|
179
182
|
className: "text-sm text-muted-foreground",
|
|
180
|
-
children:
|
|
183
|
+
children: r(k, "workspaceDetail.activityDesc", "Recent activity items")
|
|
181
184
|
})] })]
|
|
182
185
|
})
|
|
183
186
|
]
|
|
184
187
|
}),
|
|
185
|
-
/* @__PURE__ */
|
|
188
|
+
/* @__PURE__ */ _(b, { children: [/* @__PURE__ */ g(S, { children: /* @__PURE__ */ g(C, { children: r(k, "workspaceDetail.workspaceInformation", "Workspace Information") }) }), /* @__PURE__ */ g(x, {
|
|
186
189
|
className: "space-y-2",
|
|
187
|
-
children: /* @__PURE__ */
|
|
190
|
+
children: /* @__PURE__ */ _("div", {
|
|
188
191
|
className: "grid grid-cols-2 gap-2 text-sm",
|
|
189
192
|
children: [
|
|
190
|
-
/* @__PURE__ */
|
|
193
|
+
/* @__PURE__ */ g("span", {
|
|
191
194
|
className: "text-muted-foreground",
|
|
192
|
-
children:
|
|
195
|
+
children: r(k, "workspaceDetail.id", "ID:")
|
|
193
196
|
}),
|
|
194
|
-
/* @__PURE__ */
|
|
197
|
+
/* @__PURE__ */ g("span", {
|
|
195
198
|
className: "font-mono text-xs",
|
|
196
199
|
children: N.id
|
|
197
200
|
}),
|
|
198
|
-
N.domain && /* @__PURE__ */
|
|
201
|
+
N.domain && /* @__PURE__ */ _(h, { children: [/* @__PURE__ */ g("span", {
|
|
199
202
|
className: "text-muted-foreground",
|
|
200
|
-
children:
|
|
201
|
-
}), /* @__PURE__ */
|
|
202
|
-
N.contactEmail && /* @__PURE__ */
|
|
203
|
+
children: r(k, "workspaceDetail.domain", "Domain:")
|
|
204
|
+
}), /* @__PURE__ */ g("span", { children: N.domain })] }),
|
|
205
|
+
N.contactEmail && /* @__PURE__ */ _(h, { children: [/* @__PURE__ */ g("span", {
|
|
203
206
|
className: "text-muted-foreground",
|
|
204
|
-
children:
|
|
205
|
-
}), /* @__PURE__ */
|
|
206
|
-
N.website && /* @__PURE__ */
|
|
207
|
+
children: r(k, "workspaceDetail.contactEmail", "Contact Email:")
|
|
208
|
+
}), /* @__PURE__ */ g("span", { children: N.contactEmail })] }),
|
|
209
|
+
N.website && /* @__PURE__ */ _(h, { children: [/* @__PURE__ */ g("span", {
|
|
207
210
|
className: "text-muted-foreground",
|
|
208
|
-
children:
|
|
209
|
-
}), /* @__PURE__ */
|
|
211
|
+
children: r(k, "workspaceDetail.website", "Website:")
|
|
212
|
+
}), /* @__PURE__ */ g("a", {
|
|
210
213
|
href: N.website,
|
|
211
214
|
target: "_blank",
|
|
212
215
|
rel: "noopener noreferrer",
|
|
213
216
|
className: "text-primary hover:underline transition-colors duration-200",
|
|
214
217
|
children: N.website
|
|
215
218
|
})] }),
|
|
216
|
-
/* @__PURE__ */
|
|
219
|
+
/* @__PURE__ */ g("span", {
|
|
217
220
|
className: "text-muted-foreground",
|
|
218
|
-
children:
|
|
221
|
+
children: r(k, "workspaceDetail.created", "Created:")
|
|
219
222
|
}),
|
|
220
|
-
/* @__PURE__ */
|
|
223
|
+
/* @__PURE__ */ g("span", { children: new Date(N.createdAt).toLocaleDateString() })
|
|
221
224
|
]
|
|
222
225
|
})
|
|
223
226
|
})] })
|
|
@@ -225,6 +228,6 @@ function D() {
|
|
|
225
228
|
});
|
|
226
229
|
}
|
|
227
230
|
//#endregion
|
|
228
|
-
export {
|
|
231
|
+
export { O as WorkspaceDetailPage };
|
|
229
232
|
|
|
230
233
|
//# sourceMappingURL=WorkspaceDetailPage.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"WorkspaceDetailPage.js","names":[],"sources":["../../src/pages/WorkspaceDetailPage.tsx"],"sourcesContent":["import { useCallback } from 'react';\nimport { useParams, useNavigate } from 'react-router-dom';\nimport { Settings, ArrowLeft, FolderKanban, Users, Activity, ChevronRight } from 'lucide-react';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport {\n Button,\n Card,\n CardHeader,\n CardTitle,\n CardContent,\n Badge,\n Skeleton,\n} from '@burdenoff/fe-libs/ui';\nimport { useWorkspace } from '../hooks/useWorkspaces';\nimport { useProjects } from '../hooks/useProjects';\nimport { useWorkspaceMembers } from '../hooks/useWorkspaceMembers';\nimport { useWorkspaceActivity } from '../hooks/useWorkspaceActivity';\nimport { useWorkspacesContext } from '../providers/WorkspacesProvider';\nimport { useScopedNavigation } from '../hooks/useScopedNavigation';\nimport { useWorkspacePermissions } from '../hooks/useWorkspacePermissions';\n\nexport function WorkspaceDetailPage() {\n const { t } = useI18n();\n const tr = useCallback(\n (key: string, fallback: string): string => {\n const value = t(key);\n return value === key ? fallback : value;\n },\n [t]\n );\n const { workspaceId } = useParams<{ workspaceId: string }>();\n const navigate = useNavigate();\n const { basePath = '/' } = useWorkspacesContext();\n const { withCurrentSearch } = useScopedNavigation();\n const { data: workspace, isLoading, error } = useWorkspace(workspaceId || '');\n const { data: projects } = useProjects({ workspaceId }, { limit: 1 }, workspaceId);\n const { data: members } = useWorkspaceMembers(workspaceId || '', { limit: 1 });\n const { data: activities } = useWorkspaceActivity(workspaceId);\n const {\n canViewWorkspace,\n canUpdateWorkspace,\n isLoading: permissionsLoading,\n } = useWorkspacePermissions();\n\n if (permissionsLoading) {\n return (\n <div className=\"space-y-4 sm:space-y-6 p-3 sm:p-6\">\n <Skeleton className=\"h-10 w-1/3\" />\n <div className=\"grid grid-cols-1 md:grid-cols-3 gap-4\">\n <Skeleton className=\"h-32\" />\n <Skeleton className=\"h-32\" />\n <Skeleton className=\"h-32\" />\n </div>\n </div>\n );\n }\n\n if (!canViewWorkspace) {\n return (\n <div className=\"flex items-center justify-center min-h-[400px]\">\n <div className=\"text-center space-y-2\">\n <h2 className=\"text-lg font-semibold\">\n {tr('workspaceDetail.accessDenied', 'Access Denied')}\n </h2>\n <p className=\"text-sm text-muted-foreground\">\n {tr(\n 'workspaceDetail.accessDeniedDesc',\n \"You don't have permission to view this workspace.\"\n )}\n </p>\n </div>\n </div>\n );\n }\n\n if (isLoading) {\n return (\n <div className=\"space-y-4 sm:space-y-6 p-3 sm:p-6\">\n <Skeleton className=\"h-10 w-1/3\" />\n <div className=\"grid grid-cols-1 md:grid-cols-3 gap-4\">\n <Skeleton className=\"h-32\" />\n <Skeleton className=\"h-32\" />\n <Skeleton className=\"h-32\" />\n </div>\n </div>\n );\n }\n\n if (error || !workspace) {\n return (\n <div className=\"space-y-4 p-6\">\n <Button\n variant=\"ghost\"\n onClick={() => navigate(withCurrentSearch(`${basePath}/list`))}\n className=\"gap-2\"\n >\n <ArrowLeft size={20} />\n {tr('workspaceDetail.backToWorkspaces', 'Back to Workspaces')}\n </Button>\n <div className=\"text-center py-12\">\n <p className=\"text-destructive\">\n {tr('workspaceDetail.notFound', 'Workspace not found')}\n </p>\n </div>\n </div>\n );\n }\n\n const handleCardKeyDown = (e: React.KeyboardEvent, path: string) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n navigate(path);\n }\n };\n\n return (\n <div className=\"space-y-4 sm:space-y-6 p-3 sm:p-6\">\n {/* Header */}\n <div className=\"flex flex-col sm:flex-row sm:items-center sm:justify-between gap-3\">\n <div>\n <Button\n variant=\"ghost\"\n onClick={() => navigate(withCurrentSearch(`${basePath}/list`))}\n className=\"gap-2 mb-2 -ml-2\"\n >\n <ArrowLeft size={20} />\n {tr('workspaceDetail.backToWorkspaces', 'Back to Workspaces')}\n </Button>\n <h1 className=\"text-2xl sm:text-3xl font-bold\">{workspace.name}</h1>\n <div className=\"flex items-center gap-2 mt-2\">\n <Badge variant=\"outline\">{workspace.type}</Badge>\n <Badge>{workspace.status}</Badge>\n </div>\n </div>\n {canUpdateWorkspace && (\n <Button\n onClick={() => navigate(withCurrentSearch(`${basePath}/${workspaceId}/settings`))}\n className=\"gap-2\"\n >\n <Settings size={20} />\n {tr('workspaceDetail.settings', 'Settings')}\n </Button>\n )}\n </div>\n\n {/* Stats Cards */}\n <div className=\"grid grid-cols-1 md:grid-cols-3 gap-4\">\n <Card\n className=\"cursor-pointer hover:border-primary/50 hover:shadow-md transition-all duration-200\"\n onClick={() => navigate(withCurrentSearch(`${basePath}/${workspaceId}/projects`))}\n role=\"button\"\n tabIndex={0}\n onKeyDown={(e) =>\n handleCardKeyDown(e, withCurrentSearch(`${basePath}/${workspaceId}/projects`))\n }\n >\n <CardHeader className=\"flex flex-row items-center justify-between pb-2\">\n <CardTitle className=\"flex items-center gap-2\">\n <FolderKanban size={20} className=\"text-muted-foreground\" />\n {tr('workspaceDetail.projects', 'Projects')}\n </CardTitle>\n <ChevronRight size={20} className=\"text-muted-foreground\" />\n </CardHeader>\n <CardContent>\n <p className=\"text-3xl font-bold\">{projects?.total ?? workspace.projectCount ?? 0}</p>\n <p className=\"text-sm text-muted-foreground\">\n {tr('workspaceDetail.projectsDesc', 'Projects in this workspace')}\n </p>\n </CardContent>\n </Card>\n\n <Card\n className=\"cursor-pointer hover:border-primary/50 hover:shadow-md transition-all duration-200\"\n onClick={() => navigate(withCurrentSearch(`${basePath}/${workspaceId}/members`))}\n role=\"button\"\n tabIndex={0}\n onKeyDown={(e) =>\n handleCardKeyDown(e, withCurrentSearch(`${basePath}/${workspaceId}/members`))\n }\n >\n <CardHeader className=\"flex flex-row items-center justify-between pb-2\">\n <CardTitle className=\"flex items-center gap-2\">\n <Users size={20} className=\"text-muted-foreground\" />\n {tr('workspaceDetail.members', 'Members')}\n </CardTitle>\n <ChevronRight size={20} className=\"text-muted-foreground\" />\n </CardHeader>\n <CardContent>\n <p className=\"text-3xl font-bold\">{members?.total ?? workspace.memberCount ?? 0}</p>\n <p className=\"text-sm text-muted-foreground\">\n {tr('workspaceDetail.membersDesc', 'Workspace members')}\n </p>\n </CardContent>\n </Card>\n\n <Card\n className=\"cursor-pointer hover:border-primary/50 hover:shadow-md transition-all duration-200\"\n onClick={() => navigate(withCurrentSearch(`${basePath}/${workspaceId}/activity`))}\n role=\"button\"\n tabIndex={0}\n onKeyDown={(e) =>\n handleCardKeyDown(e, withCurrentSearch(`${basePath}/${workspaceId}/activity`))\n }\n >\n <CardHeader className=\"flex flex-row items-center justify-between pb-2\">\n <CardTitle className=\"flex items-center gap-2\">\n <Activity size={20} className=\"text-muted-foreground\" />\n {tr('workspaceDetail.activity', 'Activity')}\n </CardTitle>\n <ChevronRight size={20} className=\"text-muted-foreground\" />\n </CardHeader>\n <CardContent>\n <p className=\"text-3xl font-bold\">{activities?.length ?? 0}</p>\n <p className=\"text-sm text-muted-foreground\">\n {tr('workspaceDetail.activityDesc', 'Recent activity items')}\n </p>\n </CardContent>\n </Card>\n </div>\n\n {/* Workspace Info */}\n <Card>\n <CardHeader>\n <CardTitle>\n {tr('workspaceDetail.workspaceInformation', 'Workspace Information')}\n </CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-2\">\n <div className=\"grid grid-cols-2 gap-2 text-sm\">\n <span className=\"text-muted-foreground\">{tr('workspaceDetail.id', 'ID:')}</span>\n <span className=\"font-mono text-xs\">{workspace.id}</span>\n\n {workspace.domain && (\n <>\n <span className=\"text-muted-foreground\">\n {tr('workspaceDetail.domain', 'Domain:')}\n </span>\n <span>{workspace.domain}</span>\n </>\n )}\n\n {workspace.contactEmail && (\n <>\n <span className=\"text-muted-foreground\">\n {tr('workspaceDetail.contactEmail', 'Contact Email:')}\n </span>\n <span>{workspace.contactEmail}</span>\n </>\n )}\n\n {workspace.website && (\n <>\n <span className=\"text-muted-foreground\">\n {tr('workspaceDetail.website', 'Website:')}\n </span>\n <a\n href={workspace.website}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"text-primary hover:underline transition-colors duration-200\"\n >\n {workspace.website}\n </a>\n </>\n )}\n\n <span className=\"text-muted-foreground\">\n {tr('workspaceDetail.created', 'Created:')}\n </span>\n <span>{new Date(workspace.createdAt).toLocaleDateString()}</span>\n </div>\n </CardContent>\n </Card>\n </div>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"WorkspaceDetailPage.js","names":[],"sources":["../../src/pages/WorkspaceDetailPage.tsx"],"sourcesContent":["import { useParams, useNavigate } from 'react-router-dom';\nimport { Settings, ArrowLeft, FolderKanban, Users, Activity, ChevronRight } from 'lucide-react';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { tWithFallback } from '../utils/i18n';\nimport {\n Button,\n Card,\n CardHeader,\n CardTitle,\n CardContent,\n Badge,\n Skeleton,\n} from '@burdenoff/fe-libs/ui';\nimport { useWorkspace } from '../hooks/useWorkspaces';\nimport { useProjects } from '../hooks/useProjects';\nimport { useWorkspaceMembers } from '../hooks/useWorkspaceMembers';\nimport { useWorkspaceActivity } from '../hooks/useWorkspaceActivity';\nimport { useWorkspacesContext } from '../providers/WorkspacesProvider';\nimport { useScopedNavigation } from '../hooks/useScopedNavigation';\nimport { useWorkspacePermissions } from '../hooks/useWorkspacePermissions';\nimport { useWorkspacesPageView } from '../hooks/useWorkspacesPageView';\n\nexport function WorkspaceDetailPage() {\n const { workspaceId } = useParams<{ workspaceId: string }>();\n useWorkspacesPageView('workspaces.detail', { workspaceId, requireParams: true });\n const { t } = useI18n();\n const navigate = useNavigate();\n const { basePath = '/' } = useWorkspacesContext();\n const { withCurrentSearch } = useScopedNavigation();\n const { data: workspace, isLoading, error } = useWorkspace(workspaceId || '');\n const { data: projects } = useProjects({ workspaceId }, { limit: 1 }, workspaceId);\n const { data: members } = useWorkspaceMembers(workspaceId || '', { limit: 1 });\n const { data: activities } = useWorkspaceActivity(workspaceId);\n const {\n canViewWorkspace,\n canUpdateWorkspace,\n isLoading: permissionsLoading,\n } = useWorkspacePermissions();\n\n if (permissionsLoading) {\n return (\n <div className=\"space-y-4 sm:space-y-6 p-3 sm:p-6\">\n <Skeleton className=\"h-10 w-1/3\" />\n <div className=\"grid grid-cols-1 md:grid-cols-3 gap-4\">\n <Skeleton className=\"h-32\" />\n <Skeleton className=\"h-32\" />\n <Skeleton className=\"h-32\" />\n </div>\n </div>\n );\n }\n\n if (!canViewWorkspace) {\n return (\n <div className=\"flex items-center justify-center min-h-[400px]\">\n <div className=\"text-center space-y-2\">\n <h2 className=\"text-lg font-semibold\">\n {tWithFallback(t, 'workspaceDetail.accessDenied', 'Access Denied')}\n </h2>\n <p className=\"text-sm text-muted-foreground\">\n {tWithFallback(\n t,\n 'workspaceDetail.accessDeniedDesc',\n \"You don't have permission to view this workspace.\"\n )}\n </p>\n </div>\n </div>\n );\n }\n\n if (isLoading) {\n return (\n <div className=\"space-y-4 sm:space-y-6 p-3 sm:p-6\">\n <Skeleton className=\"h-10 w-1/3\" />\n <div className=\"grid grid-cols-1 md:grid-cols-3 gap-4\">\n <Skeleton className=\"h-32\" />\n <Skeleton className=\"h-32\" />\n <Skeleton className=\"h-32\" />\n </div>\n </div>\n );\n }\n\n if (error || !workspace) {\n return (\n <div className=\"space-y-4 p-6\">\n <Button\n variant=\"ghost\"\n onClick={() => navigate(withCurrentSearch(`${basePath}/list`))}\n className=\"gap-2\"\n >\n <ArrowLeft size={20} />\n {tWithFallback(t, 'workspaceDetail.backToWorkspaces', 'Back to Workspaces')}\n </Button>\n <div className=\"text-center py-12\">\n <p className=\"text-destructive\">\n {tWithFallback(t, 'workspaceDetail.notFound', 'Workspace not found')}\n </p>\n </div>\n </div>\n );\n }\n\n const handleCardKeyDown = (e: React.KeyboardEvent, path: string) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n navigate(path);\n }\n };\n\n return (\n <div className=\"space-y-4 sm:space-y-6 p-3 sm:p-6\">\n {/* Header */}\n <div className=\"flex flex-col sm:flex-row sm:items-center sm:justify-between gap-3\">\n <div>\n <Button\n variant=\"ghost\"\n onClick={() => navigate(withCurrentSearch(`${basePath}/list`))}\n className=\"gap-2 mb-2 -ml-2\"\n >\n <ArrowLeft size={20} />\n {tWithFallback(t, 'workspaceDetail.backToWorkspaces', 'Back to Workspaces')}\n </Button>\n <h1 className=\"text-2xl sm:text-3xl font-bold\">{workspace.name}</h1>\n <div className=\"flex items-center gap-2 mt-2\">\n <Badge variant=\"outline\">{workspace.type}</Badge>\n <Badge>{workspace.status}</Badge>\n </div>\n </div>\n {canUpdateWorkspace && (\n <Button\n onClick={() => navigate(withCurrentSearch(`${basePath}/${workspaceId}/settings`))}\n className=\"gap-2\"\n >\n <Settings size={20} />\n {tWithFallback(t, 'workspaceDetail.settings', 'Settings')}\n </Button>\n )}\n </div>\n\n {/* Stats Cards */}\n <div className=\"grid grid-cols-1 md:grid-cols-3 gap-4\">\n <Card\n className=\"cursor-pointer hover:border-primary/50 hover:shadow-md transition-all duration-200\"\n onClick={() => navigate(withCurrentSearch(`${basePath}/${workspaceId}/projects`))}\n role=\"button\"\n tabIndex={0}\n onKeyDown={(e) =>\n handleCardKeyDown(e, withCurrentSearch(`${basePath}/${workspaceId}/projects`))\n }\n >\n <CardHeader className=\"flex flex-row items-center justify-between pb-2\">\n <CardTitle className=\"flex items-center gap-2\">\n <FolderKanban size={20} className=\"text-muted-foreground\" />\n {tWithFallback(t, 'workspaceDetail.projects', 'Projects')}\n </CardTitle>\n <ChevronRight size={20} className=\"text-muted-foreground\" />\n </CardHeader>\n <CardContent>\n <p className=\"text-3xl font-bold\">{projects?.total ?? workspace.projectCount ?? 0}</p>\n <p className=\"text-sm text-muted-foreground\">\n {tWithFallback(t, 'workspaceDetail.projectsDesc', 'Projects in this workspace')}\n </p>\n </CardContent>\n </Card>\n\n <Card\n className=\"cursor-pointer hover:border-primary/50 hover:shadow-md transition-all duration-200\"\n onClick={() => navigate(withCurrentSearch(`${basePath}/${workspaceId}/members`))}\n role=\"button\"\n tabIndex={0}\n onKeyDown={(e) =>\n handleCardKeyDown(e, withCurrentSearch(`${basePath}/${workspaceId}/members`))\n }\n >\n <CardHeader className=\"flex flex-row items-center justify-between pb-2\">\n <CardTitle className=\"flex items-center gap-2\">\n <Users size={20} className=\"text-muted-foreground\" />\n {tWithFallback(t, 'workspaceDetail.members', 'Members')}\n </CardTitle>\n <ChevronRight size={20} className=\"text-muted-foreground\" />\n </CardHeader>\n <CardContent>\n <p className=\"text-3xl font-bold\">{members?.total ?? workspace.memberCount ?? 0}</p>\n <p className=\"text-sm text-muted-foreground\">\n {tWithFallback(t, 'workspaceDetail.membersDesc', 'Workspace members')}\n </p>\n </CardContent>\n </Card>\n\n <Card\n className=\"cursor-pointer hover:border-primary/50 hover:shadow-md transition-all duration-200\"\n onClick={() => navigate(withCurrentSearch(`${basePath}/${workspaceId}/activity`))}\n role=\"button\"\n tabIndex={0}\n onKeyDown={(e) =>\n handleCardKeyDown(e, withCurrentSearch(`${basePath}/${workspaceId}/activity`))\n }\n >\n <CardHeader className=\"flex flex-row items-center justify-between pb-2\">\n <CardTitle className=\"flex items-center gap-2\">\n <Activity size={20} className=\"text-muted-foreground\" />\n {tWithFallback(t, 'workspaceDetail.activity', 'Activity')}\n </CardTitle>\n <ChevronRight size={20} className=\"text-muted-foreground\" />\n </CardHeader>\n <CardContent>\n <p className=\"text-3xl font-bold\">{activities?.length ?? 0}</p>\n <p className=\"text-sm text-muted-foreground\">\n {tWithFallback(t, 'workspaceDetail.activityDesc', 'Recent activity items')}\n </p>\n </CardContent>\n </Card>\n </div>\n\n {/* Workspace Info */}\n <Card>\n <CardHeader>\n <CardTitle>\n {tWithFallback(t, 'workspaceDetail.workspaceInformation', 'Workspace Information')}\n </CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-2\">\n <div className=\"grid grid-cols-2 gap-2 text-sm\">\n <span className=\"text-muted-foreground\">\n {tWithFallback(t, 'workspaceDetail.id', 'ID:')}\n </span>\n <span className=\"font-mono text-xs\">{workspace.id}</span>\n\n {workspace.domain && (\n <>\n <span className=\"text-muted-foreground\">\n {tWithFallback(t, 'workspaceDetail.domain', 'Domain:')}\n </span>\n <span>{workspace.domain}</span>\n </>\n )}\n\n {workspace.contactEmail && (\n <>\n <span className=\"text-muted-foreground\">\n {tWithFallback(t, 'workspaceDetail.contactEmail', 'Contact Email:')}\n </span>\n <span>{workspace.contactEmail}</span>\n </>\n )}\n\n {workspace.website && (\n <>\n <span className=\"text-muted-foreground\">\n {tWithFallback(t, 'workspaceDetail.website', 'Website:')}\n </span>\n <a\n href={workspace.website}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"text-primary hover:underline transition-colors duration-200\"\n >\n {workspace.website}\n </a>\n </>\n )}\n\n <span className=\"text-muted-foreground\">\n {tWithFallback(t, 'workspaceDetail.created', 'Created:')}\n </span>\n <span>{new Date(workspace.createdAt).toLocaleDateString()}</span>\n </div>\n </CardContent>\n </Card>\n </div>\n );\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"WorkspaceSettingsPage.d.ts","sourceRoot":"","sources":["../../src/pages/WorkspaceSettingsPage.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"WorkspaceSettingsPage.d.ts","sourceRoot":"","sources":["../../src/pages/WorkspaceSettingsPage.tsx"],"names":[],"mappings":"AAsCA,wBAAgB,qBAAqB,4CAyRpC"}
|