create-blitzpack 0.1.0 → 0.1.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.
Files changed (259) hide show
  1. package/dist/index.js +35 -77
  2. package/package.json +5 -6
  3. package/template/.dockerignore +0 -59
  4. package/template/.github/workflows/ci.yml +0 -157
  5. package/template/.husky/pre-commit +0 -1
  6. package/template/.husky/pre-push +0 -1
  7. package/template/.lintstagedrc.cjs +0 -4
  8. package/template/.nvmrc +0 -1
  9. package/template/.prettierrc +0 -9
  10. package/template/.vscode/settings.json +0 -13
  11. package/template/CLAUDE.md +0 -175
  12. package/template/CONTRIBUTING.md +0 -32
  13. package/template/Dockerfile +0 -90
  14. package/template/GETTING_STARTED.md +0 -35
  15. package/template/LICENSE +0 -21
  16. package/template/README.md +0 -116
  17. package/template/apps/api/.dockerignore +0 -51
  18. package/template/apps/api/.env.local.example +0 -62
  19. package/template/apps/api/emails/account-deleted-email.tsx +0 -69
  20. package/template/apps/api/emails/components/email-layout.tsx +0 -154
  21. package/template/apps/api/emails/config.ts +0 -22
  22. package/template/apps/api/emails/password-changed-email.tsx +0 -88
  23. package/template/apps/api/emails/password-reset-email.tsx +0 -86
  24. package/template/apps/api/emails/verification-email.tsx +0 -85
  25. package/template/apps/api/emails/welcome-email.tsx +0 -70
  26. package/template/apps/api/package.json +0 -84
  27. package/template/apps/api/prisma/migrations/20251012111439_init/migration.sql +0 -13
  28. package/template/apps/api/prisma/migrations/20251018162629_add_better_auth_fields/migration.sql +0 -67
  29. package/template/apps/api/prisma/migrations/20251019142208_add_user_role_enum/migration.sql +0 -5
  30. package/template/apps/api/prisma/migrations/20251019182151_user_auth/migration.sql +0 -7
  31. package/template/apps/api/prisma/migrations/20251019211416_faster_session_lookup/migration.sql +0 -2
  32. package/template/apps/api/prisma/migrations/20251119124337_add_upload_model/migration.sql +0 -26
  33. package/template/apps/api/prisma/migrations/20251120071241_add_scope_to_account/migration.sql +0 -2
  34. package/template/apps/api/prisma/migrations/20251120072608_add_oauth_token_expiration_fields/migration.sql +0 -10
  35. package/template/apps/api/prisma/migrations/20251120144705_add_audit_logs/migration.sql +0 -29
  36. package/template/apps/api/prisma/migrations/20251127123614_remove_impersonated_by/migration.sql +0 -8
  37. package/template/apps/api/prisma/migrations/20251127125630_remove_audit_logs/migration.sql +0 -11
  38. package/template/apps/api/prisma/migrations/migration_lock.toml +0 -3
  39. package/template/apps/api/prisma/schema.prisma +0 -116
  40. package/template/apps/api/prisma/seed.ts +0 -159
  41. package/template/apps/api/prisma.config.ts +0 -14
  42. package/template/apps/api/src/app.ts +0 -377
  43. package/template/apps/api/src/common/logger.service.ts +0 -227
  44. package/template/apps/api/src/config/env.ts +0 -60
  45. package/template/apps/api/src/config/rate-limit.ts +0 -29
  46. package/template/apps/api/src/hooks/auth.ts +0 -122
  47. package/template/apps/api/src/plugins/auth.ts +0 -198
  48. package/template/apps/api/src/plugins/database.ts +0 -45
  49. package/template/apps/api/src/plugins/logger.ts +0 -33
  50. package/template/apps/api/src/plugins/multipart.ts +0 -16
  51. package/template/apps/api/src/plugins/scalar.ts +0 -20
  52. package/template/apps/api/src/plugins/schedule.ts +0 -52
  53. package/template/apps/api/src/plugins/services.ts +0 -66
  54. package/template/apps/api/src/plugins/swagger.ts +0 -56
  55. package/template/apps/api/src/routes/accounts.ts +0 -91
  56. package/template/apps/api/src/routes/admin-sessions.ts +0 -92
  57. package/template/apps/api/src/routes/metrics.ts +0 -71
  58. package/template/apps/api/src/routes/password.ts +0 -46
  59. package/template/apps/api/src/routes/sessions.ts +0 -53
  60. package/template/apps/api/src/routes/stats.ts +0 -38
  61. package/template/apps/api/src/routes/uploads-serve.ts +0 -27
  62. package/template/apps/api/src/routes/uploads.ts +0 -154
  63. package/template/apps/api/src/routes/users.ts +0 -114
  64. package/template/apps/api/src/routes/verification.ts +0 -90
  65. package/template/apps/api/src/server.ts +0 -34
  66. package/template/apps/api/src/services/accounts.service.ts +0 -125
  67. package/template/apps/api/src/services/authorization.service.ts +0 -162
  68. package/template/apps/api/src/services/email.service.ts +0 -170
  69. package/template/apps/api/src/services/file-storage.service.ts +0 -267
  70. package/template/apps/api/src/services/metrics.service.ts +0 -175
  71. package/template/apps/api/src/services/password.service.ts +0 -56
  72. package/template/apps/api/src/services/sessions.service.spec.ts +0 -134
  73. package/template/apps/api/src/services/sessions.service.ts +0 -276
  74. package/template/apps/api/src/services/stats.service.ts +0 -273
  75. package/template/apps/api/src/services/uploads.service.ts +0 -163
  76. package/template/apps/api/src/services/users.service.spec.ts +0 -249
  77. package/template/apps/api/src/services/users.service.ts +0 -198
  78. package/template/apps/api/src/utils/file-validation.ts +0 -108
  79. package/template/apps/api/start.sh +0 -33
  80. package/template/apps/api/test/helpers/fastify-app.ts +0 -24
  81. package/template/apps/api/test/helpers/mock-authorization.ts +0 -16
  82. package/template/apps/api/test/helpers/mock-logger.ts +0 -28
  83. package/template/apps/api/test/helpers/mock-prisma.ts +0 -30
  84. package/template/apps/api/test/helpers/test-db.ts +0 -125
  85. package/template/apps/api/test/integration/auth-flow.integration.spec.ts +0 -449
  86. package/template/apps/api/test/integration/password.integration.spec.ts +0 -427
  87. package/template/apps/api/test/integration/rate-limit.integration.spec.ts +0 -51
  88. package/template/apps/api/test/integration/sessions.integration.spec.ts +0 -445
  89. package/template/apps/api/test/integration/users.integration.spec.ts +0 -211
  90. package/template/apps/api/test/setup.ts +0 -31
  91. package/template/apps/api/tsconfig.json +0 -26
  92. package/template/apps/api/vitest.config.ts +0 -35
  93. package/template/apps/web/.env.local.example +0 -11
  94. package/template/apps/web/components.json +0 -24
  95. package/template/apps/web/next.config.ts +0 -22
  96. package/template/apps/web/package.json +0 -56
  97. package/template/apps/web/postcss.config.js +0 -5
  98. package/template/apps/web/public/apple-icon.png +0 -0
  99. package/template/apps/web/public/icon.png +0 -0
  100. package/template/apps/web/public/robots.txt +0 -3
  101. package/template/apps/web/src/app/(admin)/admin/layout.tsx +0 -222
  102. package/template/apps/web/src/app/(admin)/admin/page.tsx +0 -157
  103. package/template/apps/web/src/app/(admin)/admin/sessions/page.tsx +0 -18
  104. package/template/apps/web/src/app/(admin)/admin/users/page.tsx +0 -20
  105. package/template/apps/web/src/app/(auth)/forgot-password/page.tsx +0 -177
  106. package/template/apps/web/src/app/(auth)/login/page.tsx +0 -159
  107. package/template/apps/web/src/app/(auth)/reset-password/page.tsx +0 -245
  108. package/template/apps/web/src/app/(auth)/signup/page.tsx +0 -153
  109. package/template/apps/web/src/app/dashboard/change-password/page.tsx +0 -255
  110. package/template/apps/web/src/app/dashboard/page.tsx +0 -296
  111. package/template/apps/web/src/app/error.tsx +0 -32
  112. package/template/apps/web/src/app/examples/file-upload/page.tsx +0 -200
  113. package/template/apps/web/src/app/favicon.ico +0 -0
  114. package/template/apps/web/src/app/global-error.tsx +0 -96
  115. package/template/apps/web/src/app/globals.css +0 -22
  116. package/template/apps/web/src/app/icon.png +0 -0
  117. package/template/apps/web/src/app/layout.tsx +0 -34
  118. package/template/apps/web/src/app/not-found.tsx +0 -28
  119. package/template/apps/web/src/app/page.tsx +0 -192
  120. package/template/apps/web/src/components/admin/activity-feed.tsx +0 -101
  121. package/template/apps/web/src/components/admin/charts/auth-breakdown-chart.tsx +0 -114
  122. package/template/apps/web/src/components/admin/charts/chart-tooltip.tsx +0 -124
  123. package/template/apps/web/src/components/admin/charts/realtime-metrics-chart.tsx +0 -511
  124. package/template/apps/web/src/components/admin/charts/role-distribution-chart.tsx +0 -102
  125. package/template/apps/web/src/components/admin/charts/session-activity-chart.tsx +0 -90
  126. package/template/apps/web/src/components/admin/charts/user-growth-chart.tsx +0 -108
  127. package/template/apps/web/src/components/admin/health-indicator.tsx +0 -175
  128. package/template/apps/web/src/components/admin/refresh-control.tsx +0 -90
  129. package/template/apps/web/src/components/admin/session-revoke-all-dialog.tsx +0 -79
  130. package/template/apps/web/src/components/admin/session-revoke-dialog.tsx +0 -74
  131. package/template/apps/web/src/components/admin/sessions-management-table.tsx +0 -372
  132. package/template/apps/web/src/components/admin/stat-card.tsx +0 -137
  133. package/template/apps/web/src/components/admin/user-create-dialog.tsx +0 -152
  134. package/template/apps/web/src/components/admin/user-delete-dialog.tsx +0 -73
  135. package/template/apps/web/src/components/admin/user-edit-dialog.tsx +0 -170
  136. package/template/apps/web/src/components/admin/users-management-table.tsx +0 -285
  137. package/template/apps/web/src/components/auth/email-verification-banner.tsx +0 -85
  138. package/template/apps/web/src/components/auth/github-button.tsx +0 -40
  139. package/template/apps/web/src/components/auth/google-button.tsx +0 -54
  140. package/template/apps/web/src/components/auth/protected-route.tsx +0 -66
  141. package/template/apps/web/src/components/auth/redirect-if-authenticated.tsx +0 -31
  142. package/template/apps/web/src/components/auth/with-auth.tsx +0 -30
  143. package/template/apps/web/src/components/error/error-card.tsx +0 -47
  144. package/template/apps/web/src/components/error/forbidden.tsx +0 -25
  145. package/template/apps/web/src/components/landing/command-block.tsx +0 -64
  146. package/template/apps/web/src/components/landing/feature-card.tsx +0 -60
  147. package/template/apps/web/src/components/landing/included-feature-card.tsx +0 -63
  148. package/template/apps/web/src/components/landing/logo.tsx +0 -41
  149. package/template/apps/web/src/components/landing/tech-badge.tsx +0 -11
  150. package/template/apps/web/src/components/layout/auth-nav.tsx +0 -58
  151. package/template/apps/web/src/components/layout/footer.tsx +0 -3
  152. package/template/apps/web/src/config/landing-data.ts +0 -152
  153. package/template/apps/web/src/config/site.ts +0 -5
  154. package/template/apps/web/src/hooks/api/__tests__/use-users.test.tsx +0 -181
  155. package/template/apps/web/src/hooks/api/use-admin-sessions.ts +0 -75
  156. package/template/apps/web/src/hooks/api/use-admin-stats.ts +0 -33
  157. package/template/apps/web/src/hooks/api/use-sessions.ts +0 -52
  158. package/template/apps/web/src/hooks/api/use-uploads.ts +0 -156
  159. package/template/apps/web/src/hooks/api/use-users.ts +0 -149
  160. package/template/apps/web/src/hooks/use-mobile.ts +0 -21
  161. package/template/apps/web/src/hooks/use-realtime-metrics.ts +0 -120
  162. package/template/apps/web/src/lib/__tests__/utils.test.ts +0 -29
  163. package/template/apps/web/src/lib/api.ts +0 -151
  164. package/template/apps/web/src/lib/auth.ts +0 -13
  165. package/template/apps/web/src/lib/env.ts +0 -52
  166. package/template/apps/web/src/lib/form-utils.ts +0 -11
  167. package/template/apps/web/src/lib/utils.ts +0 -1
  168. package/template/apps/web/src/providers.tsx +0 -34
  169. package/template/apps/web/src/store/atoms.ts +0 -15
  170. package/template/apps/web/src/test/helpers/test-utils.tsx +0 -44
  171. package/template/apps/web/src/test/setup.ts +0 -8
  172. package/template/apps/web/tailwind.config.ts +0 -5
  173. package/template/apps/web/tsconfig.json +0 -26
  174. package/template/apps/web/vitest.config.ts +0 -32
  175. package/template/assets/logo-512.png +0 -0
  176. package/template/assets/logo.svg +0 -4
  177. package/template/docker-compose.prod.yml +0 -66
  178. package/template/docker-compose.yml +0 -36
  179. package/template/eslint.config.ts +0 -119
  180. package/template/package.json +0 -77
  181. package/template/packages/tailwind-config/package.json +0 -9
  182. package/template/packages/tailwind-config/theme.css +0 -179
  183. package/template/packages/types/package.json +0 -29
  184. package/template/packages/types/src/__tests__/schemas.test.ts +0 -255
  185. package/template/packages/types/src/api-response.ts +0 -53
  186. package/template/packages/types/src/health-check.ts +0 -11
  187. package/template/packages/types/src/pagination.ts +0 -41
  188. package/template/packages/types/src/role.ts +0 -5
  189. package/template/packages/types/src/session.ts +0 -48
  190. package/template/packages/types/src/stats.ts +0 -113
  191. package/template/packages/types/src/upload.ts +0 -51
  192. package/template/packages/types/src/user.ts +0 -36
  193. package/template/packages/types/tsconfig.json +0 -5
  194. package/template/packages/types/vitest.config.ts +0 -21
  195. package/template/packages/ui/components.json +0 -21
  196. package/template/packages/ui/package.json +0 -108
  197. package/template/packages/ui/src/__tests__/button.test.tsx +0 -70
  198. package/template/packages/ui/src/alert-dialog.tsx +0 -141
  199. package/template/packages/ui/src/alert.tsx +0 -66
  200. package/template/packages/ui/src/animated-theme-toggler.tsx +0 -167
  201. package/template/packages/ui/src/avatar.tsx +0 -53
  202. package/template/packages/ui/src/badge.tsx +0 -36
  203. package/template/packages/ui/src/button.tsx +0 -84
  204. package/template/packages/ui/src/card.tsx +0 -92
  205. package/template/packages/ui/src/checkbox.tsx +0 -32
  206. package/template/packages/ui/src/data-table/data-table-column-header.tsx +0 -68
  207. package/template/packages/ui/src/data-table/data-table-pagination.tsx +0 -99
  208. package/template/packages/ui/src/data-table/data-table-toolbar.tsx +0 -55
  209. package/template/packages/ui/src/data-table/data-table-view-options.tsx +0 -63
  210. package/template/packages/ui/src/data-table/data-table.tsx +0 -167
  211. package/template/packages/ui/src/dialog.tsx +0 -143
  212. package/template/packages/ui/src/dropdown-menu.tsx +0 -257
  213. package/template/packages/ui/src/empty-state.tsx +0 -52
  214. package/template/packages/ui/src/file-upload-input.tsx +0 -202
  215. package/template/packages/ui/src/form.tsx +0 -168
  216. package/template/packages/ui/src/hooks/use-mobile.ts +0 -19
  217. package/template/packages/ui/src/icons/brand-icons.tsx +0 -16
  218. package/template/packages/ui/src/input.tsx +0 -21
  219. package/template/packages/ui/src/label.tsx +0 -24
  220. package/template/packages/ui/src/lib/utils.ts +0 -6
  221. package/template/packages/ui/src/password-input.tsx +0 -102
  222. package/template/packages/ui/src/popover.tsx +0 -48
  223. package/template/packages/ui/src/radio-group.tsx +0 -45
  224. package/template/packages/ui/src/scroll-area.tsx +0 -58
  225. package/template/packages/ui/src/select.tsx +0 -187
  226. package/template/packages/ui/src/separator.tsx +0 -28
  227. package/template/packages/ui/src/sheet.tsx +0 -139
  228. package/template/packages/ui/src/sidebar.tsx +0 -726
  229. package/template/packages/ui/src/skeleton-variants.tsx +0 -87
  230. package/template/packages/ui/src/skeleton.tsx +0 -13
  231. package/template/packages/ui/src/slider.tsx +0 -63
  232. package/template/packages/ui/src/sonner.tsx +0 -25
  233. package/template/packages/ui/src/spinner.tsx +0 -16
  234. package/template/packages/ui/src/switch.tsx +0 -31
  235. package/template/packages/ui/src/table.tsx +0 -116
  236. package/template/packages/ui/src/tabs.tsx +0 -66
  237. package/template/packages/ui/src/textarea.tsx +0 -18
  238. package/template/packages/ui/src/tooltip.tsx +0 -61
  239. package/template/packages/ui/src/user-avatar.tsx +0 -97
  240. package/template/packages/ui/test-config.js +0 -3
  241. package/template/packages/ui/tsconfig.json +0 -12
  242. package/template/packages/ui/turbo.json +0 -18
  243. package/template/packages/ui/vitest.config.ts +0 -17
  244. package/template/packages/ui/vitest.setup.ts +0 -1
  245. package/template/packages/utils/package.json +0 -23
  246. package/template/packages/utils/src/__tests__/utils.test.ts +0 -223
  247. package/template/packages/utils/src/array.ts +0 -18
  248. package/template/packages/utils/src/async.ts +0 -3
  249. package/template/packages/utils/src/date.ts +0 -77
  250. package/template/packages/utils/src/errors.ts +0 -73
  251. package/template/packages/utils/src/number.ts +0 -11
  252. package/template/packages/utils/src/string.ts +0 -13
  253. package/template/packages/utils/tsconfig.json +0 -5
  254. package/template/packages/utils/vitest.config.ts +0 -21
  255. package/template/pnpm-workspace.yaml +0 -4
  256. package/template/tsconfig.base.json +0 -32
  257. package/template/turbo.json +0 -133
  258. package/template/vitest.shared.ts +0 -26
  259. package/template/vitest.workspace.ts +0 -9
@@ -1,108 +0,0 @@
1
- 'use client';
2
-
3
- import type { UserGrowthPoint } from '@repo/packages-types/stats';
4
- import { Skeleton } from '@repo/packages-ui/skeleton';
5
- import {
6
- Area,
7
- AreaChart,
8
- CartesianGrid,
9
- ResponsiveContainer,
10
- Tooltip,
11
- XAxis,
12
- YAxis,
13
- } from 'recharts';
14
-
15
- import { ChartTooltip } from './chart-tooltip';
16
-
17
- interface UserGrowthChartProps {
18
- data: UserGrowthPoint[];
19
- }
20
-
21
- function formatDate(dateStr: string) {
22
- const date = new Date(dateStr);
23
- return date.toLocaleDateString('en-US', { month: 'short', day: 'numeric' });
24
- }
25
-
26
- export function UserGrowthChart({ data }: UserGrowthChartProps) {
27
- return (
28
- <div className="bg-card rounded-xl border p-5">
29
- <div className="mb-4">
30
- <h3 className="text-sm font-semibold">User Growth</h3>
31
- <p className="text-muted-foreground text-xs">
32
- New signups and cumulative users (30 days)
33
- </p>
34
- </div>
35
- <div className="h-[240px]">
36
- <ResponsiveContainer width="100%" height="100%">
37
- <AreaChart
38
- data={data}
39
- margin={{ top: 5, right: 5, left: -20, bottom: 0 }}
40
- >
41
- <defs>
42
- <linearGradient id="colorCumulative" x1="0" y1="0" x2="0" y2="1">
43
- <stop offset="5%" stopColor="#6366f1" stopOpacity={0.3} />
44
- <stop offset="95%" stopColor="#6366f1" stopOpacity={0} />
45
- </linearGradient>
46
- <linearGradient id="colorNew" x1="0" y1="0" x2="0" y2="1">
47
- <stop offset="5%" stopColor="#10b981" stopOpacity={0.3} />
48
- <stop offset="95%" stopColor="#10b981" stopOpacity={0} />
49
- </linearGradient>
50
- </defs>
51
- <CartesianGrid
52
- strokeDasharray="3 3"
53
- vertical={false}
54
- className="stroke-zinc-200 dark:stroke-zinc-700"
55
- />
56
- <XAxis
57
- dataKey="date"
58
- tickFormatter={formatDate}
59
- tick={{ fontSize: 11 }}
60
- tickLine={false}
61
- axisLine={false}
62
- interval="preserveStartEnd"
63
- className="text-zinc-500 dark:text-zinc-400"
64
- />
65
- <YAxis
66
- tick={{ fontSize: 11 }}
67
- tickLine={false}
68
- axisLine={false}
69
- className="text-zinc-500 dark:text-zinc-400"
70
- />
71
- <Tooltip
72
- content={<ChartTooltip labelFormatter={formatDate} />}
73
- cursor={{ stroke: 'rgba(99, 102, 241, 0.3)', strokeWidth: 1 }}
74
- />
75
- <Area
76
- type="monotone"
77
- dataKey="cumulative"
78
- name="Total Users"
79
- stroke="#6366f1"
80
- strokeWidth={2}
81
- fill="url(#colorCumulative)"
82
- />
83
- <Area
84
- type="monotone"
85
- dataKey="count"
86
- name="New Users"
87
- stroke="#10b981"
88
- strokeWidth={2}
89
- fill="url(#colorNew)"
90
- />
91
- </AreaChart>
92
- </ResponsiveContainer>
93
- </div>
94
- </div>
95
- );
96
- }
97
-
98
- export function UserGrowthChartSkeleton() {
99
- return (
100
- <div className="bg-card rounded-xl border p-5">
101
- <div className="mb-4 space-y-1">
102
- <Skeleton className="h-4 w-24" />
103
- <Skeleton className="h-3 w-48" />
104
- </div>
105
- <Skeleton className="h-[240px] w-full" />
106
- </div>
107
- );
108
- }
@@ -1,175 +0,0 @@
1
- 'use client';
2
-
3
- import type { SystemHealth } from '@repo/packages-types/stats';
4
- import { cn } from '@repo/packages-ui/lib/utils';
5
- import { Skeleton } from '@repo/packages-ui/skeleton';
6
- import { motion } from 'framer-motion';
7
- import { Activity, Clock, Database } from 'lucide-react';
8
-
9
- interface HealthIndicatorProps {
10
- health: SystemHealth;
11
- }
12
-
13
- function formatUptime(seconds: number) {
14
- const days = Math.floor(seconds / 86400);
15
- const hours = Math.floor((seconds % 86400) / 3600);
16
- const mins = Math.floor((seconds % 3600) / 60);
17
-
18
- if (days > 0) return `${days}d ${hours}h`;
19
- if (hours > 0) return `${hours}h ${mins}m`;
20
- return `${mins}m`;
21
- }
22
-
23
- const STATUS_CONFIG = {
24
- connected: {
25
- label: 'Healthy',
26
- color: 'bg-emerald-500',
27
- textColor: 'text-emerald-600 dark:text-emerald-400',
28
- bgColor: 'bg-emerald-500/10',
29
- },
30
- degraded: {
31
- label: 'Degraded',
32
- color: 'bg-amber-500',
33
- textColor: 'text-amber-600 dark:text-amber-400',
34
- bgColor: 'bg-amber-500/10',
35
- },
36
- disconnected: {
37
- label: 'Offline',
38
- color: 'bg-rose-500',
39
- textColor: 'text-rose-600 dark:text-rose-400',
40
- bgColor: 'bg-rose-500/10',
41
- },
42
- };
43
-
44
- function PulseDot({
45
- status,
46
- }: {
47
- status: 'connected' | 'degraded' | 'disconnected';
48
- }) {
49
- const config = STATUS_CONFIG[status];
50
-
51
- return (
52
- <span className="relative flex size-3">
53
- <motion.span
54
- className={cn(
55
- 'absolute inline-flex h-full w-full rounded-full opacity-75',
56
- config.color
57
- )}
58
- animate={{ scale: [1, 1.5, 1], opacity: [0.75, 0, 0.75] }}
59
- transition={{ duration: 2, repeat: Infinity, ease: 'easeInOut' }}
60
- />
61
- <span
62
- className={cn('relative inline-flex size-3 rounded-full', config.color)}
63
- />
64
- </span>
65
- );
66
- }
67
-
68
- export function HealthIndicator({ health }: HealthIndicatorProps) {
69
- const dbStatus = STATUS_CONFIG[health.database];
70
-
71
- return (
72
- <div className="bg-card rounded-xl border p-5">
73
- <div className="mb-4 flex items-center justify-between">
74
- <div>
75
- <h3 className="text-sm font-semibold">System Health</h3>
76
- <p className="text-muted-foreground text-xs">Real-time status</p>
77
- </div>
78
- <div
79
- className={cn(
80
- 'flex items-center gap-2 rounded-full px-3 py-1',
81
- dbStatus.bgColor
82
- )}
83
- >
84
- <PulseDot status={health.database} />
85
- <span className={cn('text-xs font-medium', dbStatus.textColor)}>
86
- {dbStatus.label}
87
- </span>
88
- </div>
89
- </div>
90
-
91
- <div className="space-y-4">
92
- <div className="flex items-center justify-between rounded-lg border p-3">
93
- <div className="flex items-center gap-3">
94
- <div className="rounded-lg bg-blue-500/10 p-2">
95
- <Database className="size-4 text-blue-500" />
96
- </div>
97
- <div>
98
- <p className="text-sm font-medium">Database</p>
99
- <p className="text-muted-foreground text-xs">PostgreSQL</p>
100
- </div>
101
- </div>
102
- <div className="text-right">
103
- <p className={cn('text-sm font-medium', dbStatus.textColor)}>
104
- {dbStatus.label}
105
- </p>
106
- {health.dbLatencyMs !== undefined && (
107
- <p className="text-muted-foreground text-xs">
108
- {health.dbLatencyMs}ms latency
109
- </p>
110
- )}
111
- </div>
112
- </div>
113
-
114
- <div className="flex items-center justify-between rounded-lg border p-3">
115
- <div className="flex items-center gap-3">
116
- <div className="rounded-lg bg-violet-500/10 p-2">
117
- <Clock className="size-4 text-violet-500" />
118
- </div>
119
- <div>
120
- <p className="text-sm font-medium">Uptime</p>
121
- <p className="text-muted-foreground text-xs">API Server</p>
122
- </div>
123
- </div>
124
- <p className="text-sm font-medium">{formatUptime(health.uptime)}</p>
125
- </div>
126
-
127
- <div className="flex items-center justify-between rounded-lg border p-3">
128
- <div className="flex items-center gap-3">
129
- <div className="rounded-lg bg-emerald-500/10 p-2">
130
- <Activity className="size-4 text-emerald-500" />
131
- </div>
132
- <div>
133
- <p className="text-sm font-medium">Last Check</p>
134
- <p className="text-muted-foreground text-xs">Health check</p>
135
- </div>
136
- </div>
137
- <p className="text-muted-foreground text-xs">
138
- {new Date(health.lastChecked).toLocaleTimeString()}
139
- </p>
140
- </div>
141
- </div>
142
- </div>
143
- );
144
- }
145
-
146
- export function HealthIndicatorSkeleton() {
147
- return (
148
- <div className="bg-card rounded-xl border p-5">
149
- <div className="mb-4 flex items-center justify-between">
150
- <div className="space-y-1">
151
- <Skeleton className="h-4 w-24" />
152
- <Skeleton className="h-3 w-20" />
153
- </div>
154
- <Skeleton className="h-6 w-20 rounded-full" />
155
- </div>
156
- <div className="space-y-4">
157
- {Array.from({ length: 3 }).map((_, i) => (
158
- <div
159
- key={i}
160
- className="flex items-center justify-between rounded-lg border p-3"
161
- >
162
- <div className="flex items-center gap-3">
163
- <Skeleton className="size-8 rounded-lg" />
164
- <div className="space-y-1">
165
- <Skeleton className="h-3 w-16" />
166
- <Skeleton className="h-2 w-12" />
167
- </div>
168
- </div>
169
- <Skeleton className="h-4 w-14" />
170
- </div>
171
- ))}
172
- </div>
173
- </div>
174
- );
175
- }
@@ -1,90 +0,0 @@
1
- 'use client';
2
-
3
- import { Button } from '@repo/packages-ui/button';
4
- import {
5
- Select,
6
- SelectContent,
7
- SelectItem,
8
- SelectTrigger,
9
- SelectValue,
10
- } from '@repo/packages-ui/select';
11
- import { motion } from 'framer-motion';
12
- import { RefreshCw } from 'lucide-react';
13
-
14
- interface RefreshControlProps {
15
- interval: number | null;
16
- onIntervalChange: (interval: number | null) => void;
17
- onRefresh: () => void;
18
- isRefreshing: boolean;
19
- lastUpdated: Date | null;
20
- }
21
-
22
- const INTERVALS = [
23
- { value: '5000', label: '5s' },
24
- { value: '15000', label: '15s' },
25
- { value: '30000', label: '30s' },
26
- { value: '60000', label: '1m' },
27
- { value: 'off', label: 'Off' },
28
- ];
29
-
30
- export function RefreshControl({
31
- interval,
32
- onIntervalChange,
33
- onRefresh,
34
- isRefreshing,
35
- lastUpdated,
36
- }: RefreshControlProps) {
37
- const handleIntervalChange = (value: string) => {
38
- if (value === 'off') {
39
- onIntervalChange(null);
40
- } else {
41
- onIntervalChange(parseInt(value, 10));
42
- }
43
- };
44
-
45
- return (
46
- <div className="flex items-center gap-3">
47
- {lastUpdated && (
48
- <span className="text-muted-foreground text-xs">
49
- Updated {lastUpdated.toLocaleTimeString()}
50
- </span>
51
- )}
52
- <div className="flex items-center gap-2">
53
- <Select
54
- value={interval?.toString() ?? 'off'}
55
- onValueChange={handleIntervalChange}
56
- >
57
- <SelectTrigger className="h-8 w-[80px] text-xs">
58
- <SelectValue placeholder="Auto" />
59
- </SelectTrigger>
60
- <SelectContent>
61
- {INTERVALS.map((opt) => (
62
- <SelectItem key={opt.value} value={opt.value} className="text-xs">
63
- {opt.label}
64
- </SelectItem>
65
- ))}
66
- </SelectContent>
67
- </Select>
68
- <Button
69
- variant="outline"
70
- size="sm"
71
- onClick={onRefresh}
72
- disabled={isRefreshing}
73
- className="h-8 gap-1.5 px-2.5"
74
- >
75
- <motion.div
76
- animate={isRefreshing ? { rotate: 360 } : { rotate: 0 }}
77
- transition={
78
- isRefreshing
79
- ? { duration: 1, repeat: Infinity, ease: 'linear' }
80
- : { duration: 0 }
81
- }
82
- >
83
- <RefreshCw className="size-3.5" />
84
- </motion.div>
85
- <span className="text-xs">Refresh</span>
86
- </Button>
87
- </div>
88
- </div>
89
- );
90
- }
@@ -1,79 +0,0 @@
1
- 'use client';
2
-
3
- import {
4
- AlertDialog,
5
- AlertDialogAction,
6
- AlertDialogCancel,
7
- AlertDialogContent,
8
- AlertDialogDescription,
9
- AlertDialogFooter,
10
- AlertDialogHeader,
11
- AlertDialogTitle,
12
- AlertDialogTrigger,
13
- } from '@repo/packages-ui/alert-dialog';
14
- import { Button } from '@repo/packages-ui/button';
15
- import { LogOut } from 'lucide-react';
16
- import * as React from 'react';
17
- import { toast } from 'sonner';
18
-
19
- import { useRevokeUserSessions } from '@/hooks/api/use-admin-sessions';
20
-
21
- interface SessionRevokeAllDialogProps {
22
- userId: string;
23
- userName: string;
24
- userEmail: string;
25
- }
26
-
27
- export function SessionRevokeAllDialog({
28
- userId,
29
- userName,
30
- userEmail,
31
- }: SessionRevokeAllDialogProps) {
32
- const [open, setOpen] = React.useState(false);
33
- const { mutate: revokeUserSessions, isPending } = useRevokeUserSessions();
34
-
35
- const handleRevoke = () => {
36
- revokeUserSessions(userId, {
37
- onSuccess: () => {
38
- toast.success('All sessions revoked successfully');
39
- setOpen(false);
40
- },
41
- onError: (error) => {
42
- toast.error(error.message || 'Failed to revoke sessions');
43
- },
44
- });
45
- };
46
-
47
- return (
48
- <AlertDialog open={open} onOpenChange={setOpen}>
49
- <AlertDialogTrigger asChild>
50
- <Button variant="outline" size="sm" className="text-destructive">
51
- <LogOut className="mr-2 h-4 w-4" />
52
- Revoke All
53
- </Button>
54
- </AlertDialogTrigger>
55
- <AlertDialogContent>
56
- <AlertDialogHeader>
57
- <AlertDialogTitle>
58
- Revoke all sessions for this user?
59
- </AlertDialogTitle>
60
- <AlertDialogDescription>
61
- This will immediately log out{' '}
62
- <span className="font-semibold">{userName || userEmail}</span> from
63
- all devices. They will need to sign in again on each device.
64
- </AlertDialogDescription>
65
- </AlertDialogHeader>
66
- <AlertDialogFooter>
67
- <AlertDialogCancel disabled={isPending}>Cancel</AlertDialogCancel>
68
- <AlertDialogAction
69
- onClick={handleRevoke}
70
- disabled={isPending}
71
- className="bg-destructive text-destructive-foreground hover:bg-destructive/90"
72
- >
73
- {isPending ? 'Revoking...' : 'Revoke All Sessions'}
74
- </AlertDialogAction>
75
- </AlertDialogFooter>
76
- </AlertDialogContent>
77
- </AlertDialog>
78
- );
79
- }
@@ -1,74 +0,0 @@
1
- 'use client';
2
-
3
- import type { AdminSession } from '@repo/packages-types/session';
4
- import {
5
- AlertDialog,
6
- AlertDialogAction,
7
- AlertDialogCancel,
8
- AlertDialogContent,
9
- AlertDialogDescription,
10
- AlertDialogFooter,
11
- AlertDialogHeader,
12
- AlertDialogTitle,
13
- AlertDialogTrigger,
14
- } from '@repo/packages-ui/alert-dialog';
15
- import { Button } from '@repo/packages-ui/button';
16
- import { LogOut } from 'lucide-react';
17
- import * as React from 'react';
18
- import { toast } from 'sonner';
19
-
20
- import { useRevokeSession } from '@/hooks/api/use-admin-sessions';
21
-
22
- interface SessionRevokeDialogProps {
23
- session: AdminSession;
24
- }
25
-
26
- export function SessionRevokeDialog({ session }: SessionRevokeDialogProps) {
27
- const [open, setOpen] = React.useState(false);
28
- const { mutate: revokeSession, isPending } = useRevokeSession();
29
-
30
- const handleRevoke = () => {
31
- revokeSession(session.id, {
32
- onSuccess: () => {
33
- toast.success('Session revoked successfully');
34
- setOpen(false);
35
- },
36
- onError: (error) => {
37
- toast.error(error.message || 'Failed to revoke session');
38
- },
39
- });
40
- };
41
-
42
- return (
43
- <AlertDialog open={open} onOpenChange={setOpen}>
44
- <AlertDialogTrigger asChild>
45
- <Button variant="ghost" size="sm" className="text-destructive">
46
- <LogOut className="mr-2 h-4 w-4" />
47
- Revoke
48
- </Button>
49
- </AlertDialogTrigger>
50
- <AlertDialogContent>
51
- <AlertDialogHeader>
52
- <AlertDialogTitle>Revoke this session?</AlertDialogTitle>
53
- <AlertDialogDescription>
54
- This will immediately log out{' '}
55
- <span className="font-semibold">
56
- {session.user.name || session.user.email}
57
- </span>{' '}
58
- from this device. They will need to sign in again to continue.
59
- </AlertDialogDescription>
60
- </AlertDialogHeader>
61
- <AlertDialogFooter>
62
- <AlertDialogCancel disabled={isPending}>Cancel</AlertDialogCancel>
63
- <AlertDialogAction
64
- onClick={handleRevoke}
65
- disabled={isPending}
66
- className="bg-destructive text-destructive-foreground hover:bg-destructive/90"
67
- >
68
- {isPending ? 'Revoking...' : 'Revoke Session'}
69
- </AlertDialogAction>
70
- </AlertDialogFooter>
71
- </AlertDialogContent>
72
- </AlertDialog>
73
- );
74
- }