@locusai/web 0.1.7 → 0.2.2

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.
Files changed (346) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/next.config.js +15 -2
  3. package/package.json +26 -3
  4. package/src/app/(auth)/invite/page.tsx +109 -0
  5. package/src/app/(auth)/layout.tsx +19 -0
  6. package/src/app/(auth)/login/page.tsx +65 -0
  7. package/src/app/(auth)/onboarding/workspace/page.tsx +46 -0
  8. package/src/app/(auth)/register/page.tsx +165 -0
  9. package/src/app/(dashboard)/activity/page.tsx +7 -0
  10. package/src/app/(dashboard)/backlog/page.tsx +195 -0
  11. package/src/app/(dashboard)/board/page.tsx +141 -0
  12. package/src/app/(dashboard)/layout.tsx +32 -0
  13. package/src/app/(dashboard)/page.tsx +14 -0
  14. package/src/app/(dashboard)/settings/page.tsx +161 -0
  15. package/src/app/(dashboard)/settings/team/page.tsx +75 -0
  16. package/src/app/globals.css +259 -0
  17. package/src/app/layout.tsx +10 -20
  18. package/src/app/providers.tsx +26 -3
  19. package/src/components/AuthLayoutUI.tsx +53 -0
  20. package/src/components/BoardFilter.tsx +75 -74
  21. package/src/components/CreateModal/CreateModal.tsx +142 -0
  22. package/src/components/CreateModal/index.ts +1 -0
  23. package/src/components/Editor.tsx +279 -0
  24. package/src/components/Header.tsx +99 -12
  25. package/src/components/PageLayout.tsx +69 -0
  26. package/src/components/PropertyItem.tsx +55 -9
  27. package/src/components/Sidebar.tsx +280 -36
  28. package/src/components/SprintCreateModal.tsx +84 -0
  29. package/src/components/TaskCard.tsx +196 -78
  30. package/src/components/TaskCreateModal.tsx +181 -178
  31. package/src/components/TaskPanel.tsx +140 -692
  32. package/src/components/WorkspaceCreateModal.tsx +97 -0
  33. package/src/components/WorkspaceProtected.tsx +91 -0
  34. package/src/components/auth/InviteSteps.tsx +220 -0
  35. package/src/components/auth/LoginSteps.tsx +86 -0
  36. package/src/components/auth/RegisterSteps.tsx +371 -0
  37. package/src/components/auth/index.ts +3 -0
  38. package/src/components/backlog/BacklogList.tsx +92 -0
  39. package/src/components/backlog/BacklogSection.tsx +137 -0
  40. package/src/components/backlog/CompletedSprintItem.tsx +95 -0
  41. package/src/components/backlog/CompletedSprintsSection.tsx +77 -0
  42. package/src/components/backlog/SprintSection.tsx +155 -0
  43. package/src/components/backlog/constants.ts +26 -0
  44. package/src/components/board/BoardColumn.tsx +97 -0
  45. package/src/components/board/BoardContent.tsx +84 -0
  46. package/src/components/board/BoardEmptyState.tsx +82 -0
  47. package/src/components/board/BoardHeader.tsx +47 -0
  48. package/src/components/board/SprintMindmap.tsx +65 -0
  49. package/src/components/board/constants.ts +40 -0
  50. package/src/components/board/index.ts +5 -0
  51. package/src/components/common/ErrorState.tsx +124 -0
  52. package/src/components/common/LoadingState.tsx +83 -0
  53. package/src/components/common/index.ts +40 -0
  54. package/src/components/dashboard/ActivityFeed.tsx +77 -0
  55. package/src/components/dashboard/ActivityItem.tsx +207 -0
  56. package/src/components/dashboard/QuickActions.tsx +50 -0
  57. package/src/components/dashboard/StatCard.tsx +79 -0
  58. package/src/components/dnd/index.tsx +51 -0
  59. package/src/components/docs/DocsEditorArea.tsx +87 -0
  60. package/src/components/docs/DocsHeaderActions.tsx +121 -0
  61. package/src/components/docs/DocsSidebar.tsx +351 -0
  62. package/src/components/index.ts +7 -0
  63. package/src/components/onboarding/StepProgress.tsx +21 -0
  64. package/src/components/onboarding/index.ts +1 -0
  65. package/src/components/settings/ApiKeyConfirmationModal.tsx +81 -0
  66. package/src/components/settings/ApiKeyCreatedModal.tsx +96 -0
  67. package/src/components/settings/ApiKeysList.tsx +143 -0
  68. package/src/components/settings/ApiKeysSettings.tsx +144 -0
  69. package/src/components/settings/InviteMemberModal.tsx +106 -0
  70. package/src/components/settings/ProjectSetupGuide.tsx +147 -0
  71. package/src/components/settings/SettingItem.tsx +32 -0
  72. package/src/components/settings/SettingSection.tsx +50 -0
  73. package/src/components/settings/TeamInvitationsList.tsx +90 -0
  74. package/src/components/settings/TeamMembersList.tsx +95 -0
  75. package/src/components/settings/index.ts +8 -0
  76. package/src/components/task-panel/TaskActivity.tsx +127 -0
  77. package/src/components/task-panel/TaskChecklist.tsx +142 -0
  78. package/src/components/task-panel/TaskDescription.tsx +201 -0
  79. package/src/components/task-panel/TaskDocs.tsx +137 -0
  80. package/src/components/task-panel/TaskHeader.tsx +125 -0
  81. package/src/components/task-panel/TaskProperties.tsx +111 -0
  82. package/src/components/task-panel/index.ts +12 -0
  83. package/src/components/typography/EmptyStateText.tsx +59 -0
  84. package/src/components/typography/MetadataText.tsx +65 -0
  85. package/src/components/typography/SecondaryText.tsx +60 -0
  86. package/src/components/typography/SectionLabel.tsx +60 -0
  87. package/src/components/typography/index.ts +14 -0
  88. package/src/components/typography-scales.tsx +218 -0
  89. package/src/components/ui/Avatar.tsx +123 -0
  90. package/src/components/ui/Badge.tsx +69 -2
  91. package/src/components/ui/Button.tsx +71 -30
  92. package/src/components/ui/Checkbox.tsx +34 -0
  93. package/src/components/ui/Dropdown.tsx +67 -1
  94. package/src/components/ui/EmptyState.tsx +129 -0
  95. package/src/components/ui/Input.tsx +53 -6
  96. package/src/components/ui/Modal.tsx +45 -12
  97. package/src/components/ui/OtpInput.tsx +148 -0
  98. package/src/components/ui/Skeleton.tsx +36 -0
  99. package/src/components/ui/Spinner.tsx +112 -0
  100. package/src/components/ui/Textarea.tsx +28 -3
  101. package/src/components/ui/Toast.tsx +99 -0
  102. package/src/components/ui/Toggle.tsx +63 -0
  103. package/src/components/ui/constants.ts +108 -0
  104. package/src/components/ui/index.ts +7 -0
  105. package/src/context/AuthContext.tsx +140 -0
  106. package/src/context/index.ts +1 -0
  107. package/src/hooks/backlog/index.ts +13 -0
  108. package/src/hooks/backlog/useBacklogActions.ts +144 -0
  109. package/src/hooks/backlog/useBacklogComposite.ts +73 -0
  110. package/src/hooks/backlog/useBacklogData.ts +74 -0
  111. package/src/hooks/backlog/useBacklogDragDrop.ts +118 -0
  112. package/src/hooks/backlog/useBacklogUI.ts +74 -0
  113. package/src/hooks/index.ts +22 -0
  114. package/src/hooks/task-panel/index.ts +13 -0
  115. package/src/hooks/task-panel/useTaskActions.ts +200 -0
  116. package/src/hooks/task-panel/useTaskComputedValues.ts +30 -0
  117. package/src/hooks/task-panel/useTaskData.ts +78 -0
  118. package/src/hooks/task-panel/useTaskPanelComposite.ts +161 -0
  119. package/src/hooks/task-panel/useTaskUIState.ts +80 -0
  120. package/src/hooks/useAuthLayoutLogic.ts +43 -0
  121. package/src/hooks/useAuthenticatedUser.ts +36 -0
  122. package/src/hooks/useAuthenticatedUserWithOrg.ts +41 -0
  123. package/src/hooks/useBacklog.ts +303 -0
  124. package/src/hooks/useBoard.ts +230 -0
  125. package/src/hooks/useDashboardLayout.ts +49 -0
  126. package/src/hooks/useDocs.ts +279 -0
  127. package/src/hooks/useDocsQuery.ts +99 -0
  128. package/src/hooks/useDocsSidebarState.ts +104 -0
  129. package/src/hooks/useFormState.ts +40 -0
  130. package/src/hooks/useGlobalKeydowns.ts +52 -0
  131. package/src/hooks/useInviteForm.ts +122 -0
  132. package/src/hooks/useLoginForm.ts +84 -0
  133. package/src/hooks/useMutationWithToast.ts +56 -0
  134. package/src/hooks/useOrganizationQuery.ts +55 -0
  135. package/src/hooks/useRegisterForm.ts +216 -0
  136. package/src/hooks/useSprintsQuery.ts +38 -0
  137. package/src/hooks/useTaskDescription.ts +102 -0
  138. package/src/hooks/useTaskPanel.ts +341 -0
  139. package/src/hooks/useTasksQuery.ts +39 -0
  140. package/src/hooks/useTeamManagement.ts +92 -0
  141. package/src/hooks/useWorkspaceCreateForm.ts +70 -0
  142. package/src/hooks/useWorkspaceId.ts +29 -0
  143. package/src/lib/api-client.ts +40 -23
  144. package/src/lib/config.ts +25 -0
  145. package/src/lib/constants.ts +83 -0
  146. package/src/lib/options.ts +96 -0
  147. package/src/lib/query-keys.ts +91 -0
  148. package/src/lib/typography.ts +103 -0
  149. package/src/lib/utils.ts +4 -0
  150. package/src/lib/validation.ts +192 -0
  151. package/src/services/index.ts +7 -3
  152. package/src/services/notifications.ts +80 -0
  153. package/src/utils/env.utils.ts +15 -0
  154. package/src/views/ActivityView.tsx +123 -0
  155. package/src/views/Dashboard.tsx +126 -0
  156. package/src/views/Docs.tsx +98 -612
  157. package/tsconfig.tsbuildinfo +1 -1
  158. package/.next/BUILD_ID +0 -1
  159. package/.next/app-build-manifest.json +0 -55
  160. package/.next/app-path-routes-manifest.json +0 -8
  161. package/.next/build-manifest.json +0 -33
  162. package/.next/cache/.previewinfo +0 -1
  163. package/.next/cache/.rscinfo +0 -1
  164. package/.next/cache/.tsbuildinfo +0 -1
  165. package/.next/cache/config.json +0 -7
  166. package/.next/cache/webpack/client-production/0.pack +0 -0
  167. package/.next/cache/webpack/client-production/index.pack +0 -0
  168. package/.next/cache/webpack/edge-server-production/0.pack +0 -0
  169. package/.next/cache/webpack/edge-server-production/index.pack +0 -0
  170. package/.next/cache/webpack/server-production/0.pack +0 -0
  171. package/.next/cache/webpack/server-production/index.pack +0 -0
  172. package/.next/diagnostics/build-diagnostics.json +0 -6
  173. package/.next/diagnostics/framework.json +0 -1
  174. package/.next/export-detail.json +0 -5
  175. package/.next/export-marker.json +0 -6
  176. package/.next/images-manifest.json +0 -57
  177. package/.next/next-minimal-server.js.nft.json +0 -1
  178. package/.next/next-server.js.nft.json +0 -1
  179. package/.next/package.json +0 -1
  180. package/.next/prerender-manifest.json +0 -137
  181. package/.next/react-loadable-manifest.json +0 -32
  182. package/.next/required-server-files.json +0 -324
  183. package/.next/routes-manifest.json +0 -77
  184. package/.next/server/app/_not-found/page.js +0 -2
  185. package/.next/server/app/_not-found/page.js.nft.json +0 -1
  186. package/.next/server/app/_not-found/page_client-reference-manifest.js +0 -1
  187. package/.next/server/app/_not-found.html +0 -1
  188. package/.next/server/app/_not-found.meta +0 -8
  189. package/.next/server/app/_not-found.rsc +0 -21
  190. package/.next/server/app/backlog/page.js +0 -2
  191. package/.next/server/app/backlog/page.js.nft.json +0 -1
  192. package/.next/server/app/backlog/page_client-reference-manifest.js +0 -1
  193. package/.next/server/app/backlog.html +0 -1
  194. package/.next/server/app/backlog.meta +0 -7
  195. package/.next/server/app/backlog.rsc +0 -25
  196. package/.next/server/app/docs/page.js +0 -97
  197. package/.next/server/app/docs/page.js.nft.json +0 -1
  198. package/.next/server/app/docs/page_client-reference-manifest.js +0 -1
  199. package/.next/server/app/docs.html +0 -1
  200. package/.next/server/app/docs.meta +0 -7
  201. package/.next/server/app/docs.rsc +0 -26
  202. package/.next/server/app/favicon.ico/route.js +0 -1
  203. package/.next/server/app/favicon.ico/route.js.nft.json +0 -1
  204. package/.next/server/app/favicon.ico.body +0 -0
  205. package/.next/server/app/favicon.ico.meta +0 -1
  206. package/.next/server/app/index.html +0 -1
  207. package/.next/server/app/index.meta +0 -7
  208. package/.next/server/app/index.rsc +0 -25
  209. package/.next/server/app/page.js +0 -2
  210. package/.next/server/app/page.js.nft.json +0 -1
  211. package/.next/server/app/page_client-reference-manifest.js +0 -1
  212. package/.next/server/app/settings/page.js +0 -2
  213. package/.next/server/app/settings/page.js.nft.json +0 -1
  214. package/.next/server/app/settings/page_client-reference-manifest.js +0 -1
  215. package/.next/server/app/settings.html +0 -1
  216. package/.next/server/app/settings.meta +0 -7
  217. package/.next/server/app/settings.rsc +0 -25
  218. package/.next/server/app-paths-manifest.json +0 -8
  219. package/.next/server/chunks/496.js +0 -6
  220. package/.next/server/chunks/585.js +0 -1
  221. package/.next/server/chunks/665.js +0 -1
  222. package/.next/server/chunks/699.js +0 -22
  223. package/.next/server/chunks/852.js +0 -7
  224. package/.next/server/functions-config-manifest.json +0 -4
  225. package/.next/server/interception-route-rewrite-manifest.js +0 -1
  226. package/.next/server/middleware-build-manifest.js +0 -1
  227. package/.next/server/middleware-manifest.json +0 -6
  228. package/.next/server/middleware-react-loadable-manifest.js +0 -1
  229. package/.next/server/next-font-manifest.js +0 -1
  230. package/.next/server/next-font-manifest.json +0 -1
  231. package/.next/server/pages/404.html +0 -1
  232. package/.next/server/pages/500.html +0 -1
  233. package/.next/server/pages/_app.js +0 -1
  234. package/.next/server/pages/_app.js.nft.json +0 -1
  235. package/.next/server/pages/_document.js +0 -1
  236. package/.next/server/pages/_document.js.nft.json +0 -1
  237. package/.next/server/pages/_error.js +0 -19
  238. package/.next/server/pages/_error.js.nft.json +0 -1
  239. package/.next/server/pages-manifest.json +0 -6
  240. package/.next/server/server-reference-manifest.js +0 -1
  241. package/.next/server/server-reference-manifest.json +0 -1
  242. package/.next/server/webpack-runtime.js +0 -1
  243. package/.next/static/D0NXe04ZCLNDckV_quc8g/_buildManifest.js +0 -1
  244. package/.next/static/D0NXe04ZCLNDckV_quc8g/_ssgManifest.js +0 -1
  245. package/.next/static/chunks/138.b98511c56423f8bb.js +0 -1
  246. package/.next/static/chunks/146-34259952c594a3b0.js +0 -1
  247. package/.next/static/chunks/337-d3bb75304d130513.js +0 -1
  248. package/.next/static/chunks/477.1a6ecfe53375bd9c.js +0 -1
  249. package/.next/static/chunks/487-1808785ba665f784.js +0 -1
  250. package/.next/static/chunks/544.a9569941cc886e9d.js +0 -1
  251. package/.next/static/chunks/87c73c54-1f4741035a95c140.js +0 -1
  252. package/.next/static/chunks/902-d6926825a9fe8784.js +0 -1
  253. package/.next/static/chunks/955-c8f8f6235ae8f8c6.js +0 -1
  254. package/.next/static/chunks/996.e0a334e6ae90900e.js +0 -1
  255. package/.next/static/chunks/app/_not-found/page-44b1804abb44a34d.js +0 -1
  256. package/.next/static/chunks/app/backlog/page-dce1450769bfae8f.js +0 -1
  257. package/.next/static/chunks/app/docs/page-1efee819f25492cb.js +0 -1
  258. package/.next/static/chunks/app/layout-05f504c042b9f7ee.js +0 -1
  259. package/.next/static/chunks/app/page-3fd91aaaa4776ced.js +0 -1
  260. package/.next/static/chunks/app/settings/page-84e16c9638d657e4.js +0 -1
  261. package/.next/static/chunks/framework-152a1bc8c81c7458.js +0 -1
  262. package/.next/static/chunks/main-843ab130fc1be309.js +0 -1
  263. package/.next/static/chunks/main-app-123e879c5a937a00.js +0 -1
  264. package/.next/static/chunks/pages/_app-a050a8e6e4fb04cf.js +0 -1
  265. package/.next/static/chunks/pages/_error-3e422ffd891594de.js +0 -1
  266. package/.next/static/chunks/polyfills-42372ed130431b0a.js +0 -1
  267. package/.next/static/chunks/webpack-99a10a055b5bb9c4.js +0 -1
  268. package/.next/static/css/13e8617b72f9d3aa.css +0 -1
  269. package/.next/static/css/8aea088cdc4338f0.css +0 -1
  270. package/.next/static/css/b301ab0424111664.css +0 -1
  271. package/.next/static/media/24c15609eaa28576-s.woff2 +0 -0
  272. package/.next/static/media/2c07349e02a7b712-s.woff2 +0 -0
  273. package/.next/static/media/456105d6ea6d39e0-s.woff2 +0 -0
  274. package/.next/static/media/47cbc4e2adbc5db9-s.p.woff2 +0 -0
  275. package/.next/static/media/4f77bef990aad698-s.woff2 +0 -0
  276. package/.next/static/media/627d916fd739a539-s.woff2 +0 -0
  277. package/.next/static/media/63b255f18bea0ca9-s.woff2 +0 -0
  278. package/.next/static/media/70bd82ac89b4fa42-s.woff2 +0 -0
  279. package/.next/static/media/84602850c8fd81c3-s.woff2 +0 -0
  280. package/.next/trace +0 -46
  281. package/.next/types/app/backlog/page.ts +0 -84
  282. package/.next/types/app/docs/page.ts +0 -84
  283. package/.next/types/app/layout.ts +0 -84
  284. package/.next/types/app/page.ts +0 -84
  285. package/.next/types/app/settings/page.ts +0 -84
  286. package/.next/types/cache-life.d.ts +0 -141
  287. package/.next/types/package.json +0 -1
  288. package/next-env.d.ts +0 -5
  289. package/out/404.html +0 -1
  290. package/out/_next/static/D0NXe04ZCLNDckV_quc8g/_buildManifest.js +0 -1
  291. package/out/_next/static/D0NXe04ZCLNDckV_quc8g/_ssgManifest.js +0 -1
  292. package/out/_next/static/chunks/138.b98511c56423f8bb.js +0 -1
  293. package/out/_next/static/chunks/146-34259952c594a3b0.js +0 -1
  294. package/out/_next/static/chunks/337-d3bb75304d130513.js +0 -1
  295. package/out/_next/static/chunks/477.1a6ecfe53375bd9c.js +0 -1
  296. package/out/_next/static/chunks/487-1808785ba665f784.js +0 -1
  297. package/out/_next/static/chunks/544.a9569941cc886e9d.js +0 -1
  298. package/out/_next/static/chunks/87c73c54-1f4741035a95c140.js +0 -1
  299. package/out/_next/static/chunks/902-d6926825a9fe8784.js +0 -1
  300. package/out/_next/static/chunks/955-c8f8f6235ae8f8c6.js +0 -1
  301. package/out/_next/static/chunks/996.e0a334e6ae90900e.js +0 -1
  302. package/out/_next/static/chunks/app/_not-found/page-44b1804abb44a34d.js +0 -1
  303. package/out/_next/static/chunks/app/backlog/page-dce1450769bfae8f.js +0 -1
  304. package/out/_next/static/chunks/app/docs/page-1efee819f25492cb.js +0 -1
  305. package/out/_next/static/chunks/app/layout-05f504c042b9f7ee.js +0 -1
  306. package/out/_next/static/chunks/app/page-3fd91aaaa4776ced.js +0 -1
  307. package/out/_next/static/chunks/app/settings/page-84e16c9638d657e4.js +0 -1
  308. package/out/_next/static/chunks/framework-152a1bc8c81c7458.js +0 -1
  309. package/out/_next/static/chunks/main-843ab130fc1be309.js +0 -1
  310. package/out/_next/static/chunks/main-app-123e879c5a937a00.js +0 -1
  311. package/out/_next/static/chunks/pages/_app-a050a8e6e4fb04cf.js +0 -1
  312. package/out/_next/static/chunks/pages/_error-3e422ffd891594de.js +0 -1
  313. package/out/_next/static/chunks/polyfills-42372ed130431b0a.js +0 -1
  314. package/out/_next/static/chunks/webpack-99a10a055b5bb9c4.js +0 -1
  315. package/out/_next/static/css/13e8617b72f9d3aa.css +0 -1
  316. package/out/_next/static/css/8aea088cdc4338f0.css +0 -1
  317. package/out/_next/static/css/b301ab0424111664.css +0 -1
  318. package/out/_next/static/media/24c15609eaa28576-s.woff2 +0 -0
  319. package/out/_next/static/media/2c07349e02a7b712-s.woff2 +0 -0
  320. package/out/_next/static/media/456105d6ea6d39e0-s.woff2 +0 -0
  321. package/out/_next/static/media/47cbc4e2adbc5db9-s.p.woff2 +0 -0
  322. package/out/_next/static/media/4f77bef990aad698-s.woff2 +0 -0
  323. package/out/_next/static/media/627d916fd739a539-s.woff2 +0 -0
  324. package/out/_next/static/media/63b255f18bea0ca9-s.woff2 +0 -0
  325. package/out/_next/static/media/70bd82ac89b4fa42-s.woff2 +0 -0
  326. package/out/_next/static/media/84602850c8fd81c3-s.woff2 +0 -0
  327. package/out/backlog.html +0 -1
  328. package/out/backlog.txt +0 -25
  329. package/out/docs.html +0 -1
  330. package/out/docs.txt +0 -26
  331. package/out/favicon.ico +0 -0
  332. package/out/index.html +0 -1
  333. package/out/index.txt +0 -25
  334. package/out/logo.png +0 -0
  335. package/out/settings.html +0 -1
  336. package/out/settings.txt +0 -25
  337. package/src/app/backlog/page.tsx +0 -19
  338. package/src/app/page.tsx +0 -16
  339. package/src/app/settings/page.tsx +0 -194
  340. package/src/hooks/useTasks.ts +0 -119
  341. package/src/services/doc.service.ts +0 -27
  342. package/src/services/sprint.service.ts +0 -24
  343. package/src/services/task.service.ts +0 -75
  344. package/src/views/Backlog.tsx +0 -691
  345. package/src/views/Board.tsx +0 -306
  346. /package/src/app/{docs → (dashboard)/docs}/page.tsx +0 -0
@@ -0,0 +1,195 @@
1
+ "use client";
2
+
3
+ import { closestCenter, DndContext, DragOverlay } from "@dnd-kit/core";
4
+ import { AnimatePresence } from "framer-motion";
5
+ import { Layers, Plus } from "lucide-react";
6
+ import { BacklogList } from "@/components/backlog/BacklogList";
7
+ import { CompletedSprintsSection } from "@/components/backlog/CompletedSprintsSection";
8
+ import { SprintSection } from "@/components/backlog/SprintSection";
9
+ import { PageLayout } from "@/components/PageLayout";
10
+ import { SprintCreateModal } from "@/components/SprintCreateModal";
11
+ import { TaskCard } from "@/components/TaskCard";
12
+ import { TaskCreateModal } from "@/components/TaskCreateModal";
13
+ import { TaskPanel } from "@/components/TaskPanel";
14
+ import { Button, Spinner } from "@/components/ui";
15
+ import { useBacklog } from "@/hooks/useBacklog";
16
+
17
+ export default function BacklogPage() {
18
+ const {
19
+ tasks,
20
+ sprints,
21
+ backlogTasks,
22
+ activeSprint,
23
+ plannedSprints,
24
+ completedSprints,
25
+ getSprintTasks,
26
+ isLoading,
27
+ isTaskModalOpen,
28
+ setIsTaskModalOpen,
29
+ isSprintModalOpen,
30
+ setIsSprintModalOpen,
31
+ selectedTaskId,
32
+ setSelectedTaskId,
33
+ activeTask,
34
+ expandedSections,
35
+ isSubmitting,
36
+ sensors,
37
+ toggleSection,
38
+ handleDragStart,
39
+ handleDragEnd,
40
+ handleCreateSprint,
41
+ handleStartSprint,
42
+ handleCompleteSprint,
43
+ handleDeleteTask,
44
+ refetchTasks,
45
+ } = useBacklog();
46
+
47
+ if (isLoading) {
48
+ return (
49
+ <div className="flex items-center justify-center h-full">
50
+ <Spinner size="lg" />
51
+ </div>
52
+ );
53
+ }
54
+
55
+ const headerActions = (
56
+ <div className="flex items-center gap-3">
57
+ <Button
58
+ variant="outline"
59
+ onClick={() => setIsSprintModalOpen(true)}
60
+ className="h-9 border-border/50"
61
+ >
62
+ <Layers size={16} className="mr-2" />
63
+ New Sprint
64
+ </Button>
65
+ <Button
66
+ onClick={() => setIsTaskModalOpen(true)}
67
+ className="h-9 shadow-lg shadow-primary/20"
68
+ >
69
+ <Plus size={16} className="mr-2" />
70
+ New Task
71
+ </Button>
72
+ </div>
73
+ );
74
+
75
+ const headerStats = (
76
+ <div className="flex items-center gap-2">
77
+ <span className="text-primary font-bold">{tasks.length} tasks</span>
78
+ <span className="w-1 h-1 rounded-full bg-muted-foreground/30" />
79
+ <span>{sprints.length} sprints</span>
80
+ </div>
81
+ );
82
+
83
+ return (
84
+ <DndContext
85
+ sensors={sensors}
86
+ collisionDetection={closestCenter}
87
+ onDragStart={handleDragStart}
88
+ onDragEnd={handleDragEnd}
89
+ >
90
+ <PageLayout
91
+ title="Backlog"
92
+ description={headerStats}
93
+ actions={headerActions}
94
+ >
95
+ <div className="space-y-4">
96
+ <AnimatePresence mode="popLayout">
97
+ {/* 1. Active Sprint */}
98
+ {activeSprint && (
99
+ <SprintSection
100
+ key={`section-active-${activeSprint.id}`}
101
+ sprint={activeSprint}
102
+ tasks={getSprintTasks(activeSprint.id)}
103
+ isExpanded={expandedSections.has("active")}
104
+ onToggle={() => toggleSection("active")}
105
+ isActive={true}
106
+ onComplete={handleCompleteSprint}
107
+ onTaskClick={setSelectedTaskId}
108
+ onTaskDelete={handleDeleteTask}
109
+ isSubmitting={isSubmitting}
110
+ />
111
+ )}
112
+
113
+ {/* 2. Planned Sprints */}
114
+ {plannedSprints.map((sprint) => (
115
+ <SprintSection
116
+ key={`section-planned-${sprint.id}`}
117
+ sprint={sprint}
118
+ tasks={getSprintTasks(sprint.id)}
119
+ isExpanded={expandedSections.has(`planned-${sprint.id}`)}
120
+ onToggle={() => toggleSection(`planned-${sprint.id}`)}
121
+ canStart={!activeSprint}
122
+ onStart={handleStartSprint}
123
+ onTaskClick={setSelectedTaskId}
124
+ onTaskDelete={handleDeleteTask}
125
+ isSubmitting={isSubmitting}
126
+ />
127
+ ))}
128
+
129
+ {/* 3. Backlog Section */}
130
+ <BacklogList
131
+ key="backlog-list"
132
+ tasks={backlogTasks}
133
+ isExpanded={expandedSections.has("backlog")}
134
+ onToggle={() => toggleSection("backlog")}
135
+ onTaskClick={setSelectedTaskId}
136
+ onTaskDelete={handleDeleteTask}
137
+ />
138
+
139
+ {/* 4. Completed Sprints */}
140
+ <CompletedSprintsSection
141
+ key="completed-sprints"
142
+ sprints={completedSprints}
143
+ isExpanded={expandedSections.has("completed")}
144
+ onToggle={() => toggleSection("completed")}
145
+ getSprintTasks={getSprintTasks}
146
+ expandedSprints={expandedSections}
147
+ onToggleSprint={toggleSection}
148
+ onTaskClick={setSelectedTaskId}
149
+ />
150
+ </AnimatePresence>
151
+ </div>
152
+ </PageLayout>
153
+
154
+ {/* Drag Overlay */}
155
+ <DragOverlay>
156
+ {activeTask && (
157
+ <div className="opacity-80 rotate-1 shadow-2xl cursor-grabbing scale-105 transition-transform duration-200">
158
+ <TaskCard task={activeTask} variant="list" />
159
+ </div>
160
+ )}
161
+ </DragOverlay>
162
+
163
+ {/* Modals */}
164
+ <TaskCreateModal
165
+ isOpen={isTaskModalOpen}
166
+ onClose={() => setIsTaskModalOpen(false)}
167
+ onCreated={() => {
168
+ refetchTasks();
169
+ setIsTaskModalOpen(false);
170
+ }}
171
+ />
172
+
173
+ <SprintCreateModal
174
+ isOpen={isSprintModalOpen}
175
+ onClose={() => setIsSprintModalOpen(false)}
176
+ onCreated={handleCreateSprint}
177
+ isSubmitting={isSubmitting}
178
+ />
179
+
180
+ {selectedTaskId && (
181
+ <TaskPanel
182
+ taskId={selectedTaskId}
183
+ onClose={() => setSelectedTaskId(null)}
184
+ onUpdated={() => {
185
+ refetchTasks();
186
+ }}
187
+ onDeleted={() => {
188
+ refetchTasks();
189
+ setSelectedTaskId(null);
190
+ }}
191
+ />
192
+ )}
193
+ </DndContext>
194
+ );
195
+ }
@@ -0,0 +1,141 @@
1
+ "use client";
2
+
3
+ import { LayoutGrid, Map as MapIcon } from "lucide-react";
4
+ import {
5
+ BoardFilter,
6
+ PageLayout,
7
+ TaskCreateModal,
8
+ TaskPanel,
9
+ } from "@/components";
10
+ import { BoardContent, BoardHeader, SprintMindmap } from "@/components/board";
11
+ import { Button, Spinner } from "@/components/ui";
12
+ import { useBoard } from "@/hooks";
13
+
14
+ export default function BoardPage() {
15
+ const {
16
+ activeSprint,
17
+ filteredTasks,
18
+ tasksByStatus,
19
+ activeTask,
20
+ isLoading,
21
+ shouldShowEmptyState,
22
+ isCreateModalOpen,
23
+ setIsCreateModalOpen,
24
+ selectedTaskId,
25
+ setSelectedTaskId,
26
+ searchQuery,
27
+ setSearchQuery,
28
+ priorityFilter,
29
+ setPriorityFilter,
30
+ roleFilter,
31
+ setRoleFilter,
32
+ view,
33
+ setView,
34
+ sensors,
35
+ handleDragStart,
36
+ handleDragEnd,
37
+ handleDeleteTask,
38
+ refetch,
39
+ } = useBoard();
40
+
41
+ if (isLoading) {
42
+ return (
43
+ <div className="flex items-center justify-center h-full">
44
+ <Spinner size="lg" />
45
+ </div>
46
+ );
47
+ }
48
+
49
+ const { title, description, actions } = BoardHeader({
50
+ activeSprint,
51
+ filteredTasksCount: filteredTasks.length,
52
+ onNewTask: () => setIsCreateModalOpen(true),
53
+ });
54
+
55
+ return (
56
+ <>
57
+ <PageLayout
58
+ title={title}
59
+ description={description}
60
+ actions={actions}
61
+ contentClassName="flex flex-col"
62
+ >
63
+ {activeSprint != null && (
64
+ <div className="flex items-center justify-between gap-4 mb-6">
65
+ <BoardFilter
66
+ searchQuery={searchQuery}
67
+ onSearchChange={setSearchQuery}
68
+ priorityFilter={priorityFilter}
69
+ onPriorityChange={setPriorityFilter}
70
+ roleFilter={roleFilter}
71
+ onRoleChange={setRoleFilter}
72
+ />
73
+
74
+ <div className="flex items-center bg-muted/50 p-1 rounded-lg border">
75
+ <Button
76
+ variant={view === "board" ? "secondary" : "ghost"}
77
+ size="sm"
78
+ className="gap-2"
79
+ onClick={() => setView("board")}
80
+ >
81
+ <LayoutGrid className="w-4 h-4" />
82
+ Board
83
+ </Button>
84
+ <Button
85
+ variant={view === "mindmap" ? "secondary" : "ghost"}
86
+ size="sm"
87
+ className="gap-2"
88
+ onClick={() => setView("mindmap")}
89
+ >
90
+ <MapIcon className="w-4 h-4" />
91
+ Mindmap
92
+ </Button>
93
+ </div>
94
+ </div>
95
+ )}
96
+
97
+ {view === "board" ? (
98
+ <BoardContent
99
+ filteredTasks={filteredTasks}
100
+ tasksByStatus={tasksByStatus}
101
+ shouldShowEmptyState={shouldShowEmptyState}
102
+ activeTask={activeTask}
103
+ sensors={sensors}
104
+ onDragStart={handleDragStart}
105
+ onDragEnd={handleDragEnd}
106
+ onTaskClick={setSelectedTaskId}
107
+ onTaskDelete={handleDeleteTask}
108
+ onNewTask={() => setIsCreateModalOpen(true)}
109
+ />
110
+ ) : (
111
+ <SprintMindmap mindmap={activeSprint?.mindmap || null} />
112
+ )}
113
+ </PageLayout>
114
+
115
+ {/* Modals */}
116
+ <TaskCreateModal
117
+ isOpen={isCreateModalOpen}
118
+ onClose={() => setIsCreateModalOpen(false)}
119
+ onCreated={() => {
120
+ refetch();
121
+ setIsCreateModalOpen(false);
122
+ }}
123
+ defaultSprintId={activeSprint?.id}
124
+ />
125
+
126
+ {selectedTaskId && (
127
+ <TaskPanel
128
+ taskId={selectedTaskId}
129
+ onClose={() => setSelectedTaskId(null)}
130
+ onUpdated={() => {
131
+ refetch();
132
+ }}
133
+ onDeleted={() => {
134
+ refetch();
135
+ setSelectedTaskId(null);
136
+ }}
137
+ />
138
+ )}
139
+ </>
140
+ );
141
+ }
@@ -0,0 +1,32 @@
1
+ "use client";
2
+
3
+ import { Sidebar, WorkspaceProtected } from "@/components";
4
+ import { LoadingSkeleton } from "@/components/ui";
5
+ import { useDashboardLayout } from "@/hooks/useDashboardLayout";
6
+
7
+ export default function DashboardLayout({
8
+ children,
9
+ }: {
10
+ children: React.ReactNode;
11
+ }) {
12
+ const { isLoading, isAuthenticated, shouldShowUI } = useDashboardLayout();
13
+
14
+ // Show loading skeleton while authenticating
15
+ if (isLoading) {
16
+ return <LoadingSkeleton />;
17
+ }
18
+
19
+ // Don't render anything if not authenticated (redirect happens in hook)
20
+ if (!shouldShowUI) {
21
+ return null;
22
+ }
23
+
24
+ return (
25
+ <div className="flex h-screen overflow-hidden bg-background">
26
+ {isAuthenticated && <Sidebar />}
27
+ <main className="flex-1 overflow-auto bg-background p-6">
28
+ <WorkspaceProtected>{children}</WorkspaceProtected>
29
+ </main>
30
+ </div>
31
+ );
32
+ }
@@ -0,0 +1,14 @@
1
+ "use client";
2
+
3
+ import dynamic from "next/dynamic";
4
+
5
+ const Dashboard = dynamic(
6
+ () => import("@/views/Dashboard").then((mod) => mod.Dashboard),
7
+ {
8
+ ssr: false,
9
+ }
10
+ );
11
+
12
+ export default function Home() {
13
+ return <Dashboard />;
14
+ }
@@ -0,0 +1,161 @@
1
+ "use client";
2
+
3
+ import { ChevronRight, Trash2, Users } from "lucide-react";
4
+ import Link from "next/link";
5
+ import { useRouter } from "next/navigation";
6
+ import { useState } from "react";
7
+ import { toast } from "sonner";
8
+ import { PageLayout } from "@/components/PageLayout";
9
+ import { ApiKeysSettings } from "@/components/settings/ApiKeysSettings";
10
+ import { SettingItem } from "@/components/settings/SettingItem";
11
+ import { SettingSection } from "@/components/settings/SettingSection";
12
+ import { Button, Input, Modal } from "@/components/ui";
13
+ import { useAuth } from "@/context";
14
+ import { useAuthenticatedUser, useOrganizationQuery } from "@/hooks";
15
+ import { locusClient } from "@/lib/api-client";
16
+
17
+ export default function SettingsPage() {
18
+ const user = useAuthenticatedUser();
19
+ const { logout } = useAuth();
20
+ const router = useRouter();
21
+ const { data: organization } = useOrganizationQuery();
22
+ const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false);
23
+ const [deleteConfirmation, setDeleteConfirmation] = useState("");
24
+ const [isDeleting, setIsDeleting] = useState(false);
25
+
26
+ const orgName = organization?.name || "organization";
27
+
28
+ const handleDeleteOrganization = async () => {
29
+ if (!user?.orgId) return;
30
+
31
+ const expectedConfirmation = `delete ${orgName}`.toLowerCase();
32
+ if (deleteConfirmation.toLowerCase() !== expectedConfirmation) {
33
+ toast.error(`Please type "delete ${orgName}" to confirm`);
34
+ return;
35
+ }
36
+
37
+ setIsDeleting(true);
38
+ try {
39
+ await locusClient.organizations.delete(user.orgId);
40
+ toast.success("Organization deleted");
41
+
42
+ // Logout the user
43
+ logout();
44
+
45
+ // Redirect to login
46
+ router.push("/login");
47
+ } catch (error) {
48
+ toast.error(
49
+ error instanceof Error ? error.message : "Failed to delete organization"
50
+ );
51
+ } finally {
52
+ setIsDeleting(false);
53
+ }
54
+ };
55
+
56
+ return (
57
+ <PageLayout
58
+ title="Settings"
59
+ description="Manage your workspace preferences and configuration."
60
+ >
61
+ <div className="max-w-5xl space-y-8">
62
+ {/* Organization Section */}
63
+ <SettingSection title="Organization">
64
+ <Link href="/settings/team">
65
+ <SettingItem
66
+ icon={<Users size={18} />}
67
+ title="Team"
68
+ description="Invite and manage organization members"
69
+ >
70
+ <div className="text-muted-foreground">
71
+ <ChevronRight size={20} />
72
+ </div>
73
+ </SettingItem>
74
+ </Link>
75
+ </SettingSection>
76
+
77
+ {/* API Keys Section */}
78
+ <ApiKeysSettings />
79
+
80
+ {/* Danger Zone */}
81
+ <div>
82
+ <h3 className="text-xs font-bold uppercase tracking-widest text-destructive mb-4 px-4">
83
+ Danger Zone
84
+ </h3>
85
+ <div className="bg-destructive/5 border border-destructive/20 rounded-2xl p-6">
86
+ <div className="flex items-center justify-between">
87
+ <div>
88
+ <h4 className="font-medium text-foreground">
89
+ Delete Organization
90
+ </h4>
91
+ <p className="text-sm text-muted-foreground mt-0.5">
92
+ Permanently delete this organization and all its data
93
+ </p>
94
+ </div>
95
+ <Button
96
+ variant="danger"
97
+ size="sm"
98
+ onClick={() => setIsDeleteModalOpen(true)}
99
+ >
100
+ <Trash2 size={18} />
101
+ Delete
102
+ </Button>
103
+ </div>
104
+ </div>
105
+ </div>
106
+ </div>
107
+
108
+ {/* Delete Organization Modal */}
109
+ <Modal
110
+ isOpen={isDeleteModalOpen}
111
+ onClose={() => setIsDeleteModalOpen(false)}
112
+ >
113
+ <div className="space-y-4">
114
+ <div>
115
+ <h2 className="text-xl font-bold text-foreground">
116
+ Delete Organization
117
+ </h2>
118
+ <p className="text-sm text-muted-foreground mt-1">
119
+ This action cannot be undone. All organization data will be
120
+ permanently deleted.
121
+ </p>
122
+ </div>
123
+
124
+ <div className="space-y-2">
125
+ <label className="text-sm font-medium text-foreground">
126
+ Type "delete {orgName}" to confirm
127
+ </label>
128
+ <Input
129
+ placeholder={`delete ${orgName}`}
130
+ value={deleteConfirmation}
131
+ onChange={(e) => setDeleteConfirmation(e.target.value)}
132
+ disabled={isDeleting}
133
+ />
134
+ </div>
135
+
136
+ <div className="flex gap-3 justify-end pt-4">
137
+ <Button
138
+ variant="secondary"
139
+ onClick={() => setIsDeleteModalOpen(false)}
140
+ disabled={isDeleting}
141
+ >
142
+ Cancel
143
+ </Button>
144
+ <Button
145
+ variant="danger"
146
+ onClick={handleDeleteOrganization}
147
+ disabled={
148
+ isDeleting ||
149
+ deleteConfirmation.toLowerCase() !==
150
+ `delete ${orgName}`.toLowerCase()
151
+ }
152
+ isLoading={isDeleting}
153
+ >
154
+ Delete Organization
155
+ </Button>
156
+ </div>
157
+ </div>
158
+ </Modal>
159
+ </PageLayout>
160
+ );
161
+ }
@@ -0,0 +1,75 @@
1
+ "use client";
2
+
3
+ import { UserPlus } from "lucide-react";
4
+ import { PageLayout } from "@/components";
5
+ import { InviteMemberModal } from "@/components/settings";
6
+ import { TeamInvitationsList } from "@/components/settings/TeamInvitationsList";
7
+ import { TeamMembersList } from "@/components/settings/TeamMembersList";
8
+ import { Button } from "@/components/ui";
9
+ import { useTeamManagement } from "@/hooks/useTeamManagement";
10
+
11
+ export default function TeamPage() {
12
+ const {
13
+ currentUser,
14
+ members,
15
+ invitations,
16
+ isLoading,
17
+ canManage,
18
+ isInviteModalOpen,
19
+ setIsInviteModalOpen,
20
+ handleRemoveMember,
21
+ handleRevokeInvitation,
22
+ handleCopyLink,
23
+ } = useTeamManagement();
24
+
25
+ return (
26
+ <PageLayout
27
+ title="Team Management"
28
+ description="Manage your organization members and invitations."
29
+ actions={
30
+ canManage ? (
31
+ <Button onClick={() => setIsInviteModalOpen(true)}>
32
+ <UserPlus size={18} />
33
+ Invite Member
34
+ </Button>
35
+ ) : undefined
36
+ }
37
+ >
38
+ <div className="space-y-8">
39
+ {/* Members List */}
40
+ <section className="space-y-4">
41
+ <div className="flex items-center justify-between px-1">
42
+ <h3 className="text-sm font-semibold text-muted-foreground uppercase tracking-wider">
43
+ Members ({members.length})
44
+ </h3>
45
+ </div>
46
+
47
+ <div className="bg-card/50 border border-secondary/20 rounded-2xl overflow-hidden">
48
+ <TeamMembersList
49
+ members={members}
50
+ currentUserId={currentUser.id}
51
+ canManage={canManage}
52
+ isLoading={isLoading}
53
+ onRemoveMember={handleRemoveMember}
54
+ />
55
+ </div>
56
+ </section>
57
+
58
+ {/* Pending Invitations */}
59
+ {!isLoading && (
60
+ <TeamInvitationsList
61
+ invitations={invitations}
62
+ canManage={canManage}
63
+ onCopyLink={handleCopyLink}
64
+ onRevokeInvitation={handleRevokeInvitation}
65
+ />
66
+ )}
67
+ </div>
68
+
69
+ <InviteMemberModal
70
+ isOpen={isInviteModalOpen}
71
+ onClose={() => setIsInviteModalOpen(false)}
72
+ />
73
+ </PageLayout>
74
+ );
75
+ }