diff --git a/apps/hub/app/_components/Badge/Badge.tsx b/apps/hub/app/_components/Badge/Badge.tsx
deleted file mode 100644
index 22917eaf..00000000
--- a/apps/hub/app/_components/Badge/Badge.tsx
+++ /dev/null
@@ -1,30 +0,0 @@
-import { BADGES } from "@repo/db";
-import P1 from "./p-1.png";
-import P2 from "./p-2.png";
-import P3 from "./p-3.png";
-import D1 from "./d-1.png";
-import D2 from "./d-2.png";
-import D3 from "./d-3.png";
-import DAY1 from "./day-1-member.png";
-import { cn } from "../../../helper/cn";
-
-const BadgeImage = {
- [BADGES.P1]: P1,
- [BADGES.P2]: P2,
- [BADGES.P3]: P3,
- [BADGES.D1]: D1,
- [BADGES.D2]: D2,
- [BADGES.D3]: D3,
- [BADGES.DAY1]: DAY1,
- [BADGES.V1Veteran]: DAY1,
-};
-
-export const Badge = ({ name, className }: { name: BADGES; className?: string }) => {
- const image = BadgeImage[name];
-
- return (
-
-
-
- );
-};
diff --git a/apps/hub/app/_components/Badge/d-1.png b/apps/hub/app/_components/Badge/d-1.png
deleted file mode 100644
index 8fa5ec32..00000000
Binary files a/apps/hub/app/_components/Badge/d-1.png and /dev/null differ
diff --git a/apps/hub/app/_components/Badge/d-2.png b/apps/hub/app/_components/Badge/d-2.png
deleted file mode 100644
index d65b164c..00000000
Binary files a/apps/hub/app/_components/Badge/d-2.png and /dev/null differ
diff --git a/apps/hub/app/_components/Badge/d-3.png b/apps/hub/app/_components/Badge/d-3.png
deleted file mode 100644
index e48113d7..00000000
Binary files a/apps/hub/app/_components/Badge/d-3.png and /dev/null differ
diff --git a/apps/hub/app/_components/Badge/day-1-member.png b/apps/hub/app/_components/Badge/day-1-member.png
deleted file mode 100644
index a0c383f8..00000000
Binary files a/apps/hub/app/_components/Badge/day-1-member.png and /dev/null differ
diff --git a/apps/hub/app/_components/Badge/p-1.png b/apps/hub/app/_components/Badge/p-1.png
deleted file mode 100644
index 1e979605..00000000
Binary files a/apps/hub/app/_components/Badge/p-1.png and /dev/null differ
diff --git a/apps/hub/app/_components/Badge/p-2.png b/apps/hub/app/_components/Badge/p-2.png
deleted file mode 100644
index 0ebe38bf..00000000
Binary files a/apps/hub/app/_components/Badge/p-2.png and /dev/null differ
diff --git a/apps/hub/app/_components/Badge/p-3.png b/apps/hub/app/_components/Badge/p-3.png
deleted file mode 100644
index d83d0db0..00000000
Binary files a/apps/hub/app/_components/Badge/p-3.png and /dev/null differ
diff --git a/apps/hub/app/(app)/_components/Penalty.tsx b/apps/hub/app/_components/Penalty.tsx
similarity index 96%
rename from apps/hub/app/(app)/_components/Penalty.tsx
rename to apps/hub/app/_components/Penalty.tsx
index 0e815df2..c4c8eaf4 100644
--- a/apps/hub/app/(app)/_components/Penalty.tsx
+++ b/apps/hub/app/_components/Penalty.tsx
@@ -1,6 +1,6 @@
import { getPublicUser, prisma } from "@repo/db";
import { TriangleAlert } from "lucide-react";
-import { PenaltyCountdown } from "./PenaltyCountdown";
+import { PenaltyCountdown } from "../(app)/_components/PenaltyCountdown";
import { getServerSession } from "api/auth/[...nextauth]/auth";
export const Penalty = async () => {
diff --git a/apps/hub/package.json b/apps/hub/package.json
index 5bfd9484..b18e147b 100644
--- a/apps/hub/package.json
+++ b/apps/hub/package.json
@@ -16,6 +16,7 @@
"@radix-ui/react-icons": "^1.3.2",
"@repo/db": "workspace:*",
"@repo/eslint-config": "workspace:*",
+ "@repo/shared-components": "workspace:*",
"@repo/typescript-config": "workspace:*",
"@tailwindcss/postcss": "^4.1.8",
"@tanstack/react-query": "^5.79.2",
diff --git a/apps/dispatch/app/_components/Badge/day-1-member.png b/apps/hub/public/badges/v1-veteran.png
similarity index 100%
rename from apps/dispatch/app/_components/Badge/day-1-member.png
rename to apps/hub/public/badges/v1-veteran.png
diff --git a/packages/shared-components/components/Badge.tsx b/packages/shared-components/components/Badge.tsx
new file mode 100644
index 00000000..8d529691
--- /dev/null
+++ b/packages/shared-components/components/Badge.tsx
@@ -0,0 +1,28 @@
+import { BADGES } from "@repo/db";
+import { cn } from "../../../apps/hub/helper/cn";
+import * as React from "react";
+
+const badgeImageMapping = {
+ [BADGES.P1]: "p-1.png",
+ [BADGES.P2]: "p-2.png",
+ [BADGES.P3]: "p-3.png",
+ [BADGES.D1]: "d-1.png",
+ [BADGES.D2]: "d-2.png",
+ [BADGES.D3]: "d-3.png",
+ [BADGES.DAY1]: "day-1-member.png",
+ [BADGES.V1Veteran]: "v1-veteran.png",
+};
+
+export const Badge = ({ badge, className }: { badge: BADGES; className?: string }) => {
+ return (
+
+
+
+ );
+};
diff --git a/apps/hub/app/(app)/admin/user/[id]/_components/AddPenaltyDropdown.tsx b/packages/shared-components/components/PenaltyDropdown.tsx
similarity index 98%
rename from apps/hub/app/(app)/admin/user/[id]/_components/AddPenaltyDropdown.tsx
rename to packages/shared-components/components/PenaltyDropdown.tsx
index 6e185081..eef50404 100644
--- a/apps/hub/app/(app)/admin/user/[id]/_components/AddPenaltyDropdown.tsx
+++ b/packages/shared-components/components/PenaltyDropdown.tsx
@@ -1,5 +1,6 @@
+"use client";
import { ReactNode, useState } from "react";
-import { cn } from "../../../../../../helper/cn";
+import { cn } from "../helper/cn";
export const PenaltyDropdown = ({
onClick,
diff --git a/packages/shared-components/components/index.ts b/packages/shared-components/components/index.ts
new file mode 100644
index 00000000..52ce020f
--- /dev/null
+++ b/packages/shared-components/components/index.ts
@@ -0,0 +1,2 @@
+export * from "./Badge";
+export * from "./PenaltyDropdown";
diff --git a/apps/dispatch/app/_helpers/cn.ts b/packages/shared-components/helper/cn.ts
similarity index 100%
rename from apps/dispatch/app/_helpers/cn.ts
rename to packages/shared-components/helper/cn.ts
diff --git a/packages/shared-components/helper/index.ts b/packages/shared-components/helper/index.ts
new file mode 100644
index 00000000..963c6b2f
--- /dev/null
+++ b/packages/shared-components/helper/index.ts
@@ -0,0 +1 @@
+export * from "./cn";
diff --git a/packages/shared-components/index.ts b/packages/shared-components/index.ts
new file mode 100644
index 00000000..a6fe3ef3
--- /dev/null
+++ b/packages/shared-components/index.ts
@@ -0,0 +1,2 @@
+export * from "./components";
+export * from "./helper";
diff --git a/packages/shared-components/package.json b/packages/shared-components/package.json
new file mode 100644
index 00000000..e057c9c3
--- /dev/null
+++ b/packages/shared-components/package.json
@@ -0,0 +1,22 @@
+{
+ "name": "@repo/shared-components",
+ "version": "0.1.0",
+ "type": "module",
+ "exports": {
+ ".": "./index.ts"
+ },
+ "main": "index.ts",
+ "dependencies": {
+ "@repo/db": "workspace:*",
+ "@repo/typescript-config": "workspace:*",
+ "@types/node": "^22.15.29",
+ "clsx": "^2.1.1",
+ "tailwind-merge": "^3.3.0"
+ },
+ "devDependencies": {
+ "@types/react": "^19.1.6",
+ "@types/react-dom": "^19.1.5",
+ "react": "^19.1.0",
+ "react-dom": "^19.1.0"
+ }
+}
diff --git a/packages/shared-components/tsconfig.json b/packages/shared-components/tsconfig.json
new file mode 100644
index 00000000..83490e14
--- /dev/null
+++ b/packages/shared-components/tsconfig.json
@@ -0,0 +1,10 @@
+{
+ "extends": "@repo/typescript-config/nextjs.json",
+ "compilerOptions": {
+ "baseUrl": ".",
+ "jsx": "react-jsx",
+ "types": ["node", "react"]
+ },
+ "include": ["."],
+ "exclude": ["node_modules"]
+}
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 0848b006..7ed5ef09 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -92,7 +92,7 @@ importers:
version: 0.5.7(@types/dom-mediacapture-transform@0.1.11)(livekit-client@2.13.3(@types/dom-mediacapture-record@1.0.22))
'@next-auth/prisma-adapter':
specifier: ^1.0.7
- version: 1.0.7(@prisma/client@6.8.2(prisma@6.8.2(typescript@5.8.3))(typescript@5.8.3))(next-auth@4.24.11(next@15.3.3(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react-dom@19.1.0(react@19.1.0))(react@19.1.0))
+ version: 1.0.7(@prisma/client@6.8.2(prisma@6.8.2(typescript@5.8.3))(typescript@5.8.3))(next-auth@4.24.11(next@15.3.3(@babel/core@7.27.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react-dom@19.1.0(react@19.1.0))(react@19.1.0))
'@radix-ui/react-icons':
specifier: ^1.3.2
version: 1.3.2(react@19.1.0)
@@ -102,6 +102,9 @@ importers:
'@repo/eslint-config':
specifier: workspace:*
version: link:../../packages/eslint-config
+ '@repo/shared-components':
+ specifier: workspace:*
+ version: link:../../packages/shared-components
'@repo/typescript-config':
specifier: workspace:*
version: link:../../packages/typescript-config
@@ -167,7 +170,7 @@ importers:
version: 15.3.3(@babel/core@7.27.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
next-auth:
specifier: ^4.24.11
- version: 4.24.11(next@15.3.3(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
+ version: 4.24.11(next@15.3.3(@babel/core@7.27.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
npm:
specifier: ^11.4.1
version: 11.4.1
@@ -325,7 +328,7 @@ importers:
version: 5.0.1(react-hook-form@7.57.0(react@19.1.0))
'@next-auth/prisma-adapter':
specifier: ^1.0.7
- version: 1.0.7(@prisma/client@6.8.2(prisma@6.8.2(typescript@5.8.3))(typescript@5.8.3))(next-auth@4.24.11(next@15.3.3(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react-dom@19.1.0(react@19.1.0))(react@19.1.0))
+ version: 1.0.7(@prisma/client@6.8.2(prisma@6.8.2(typescript@5.8.3))(typescript@5.8.3))(next-auth@4.24.11(next@15.3.3(@babel/core@7.27.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react-dom@19.1.0(react@19.1.0))(react@19.1.0))
'@radix-ui/react-icons':
specifier: ^1.3.2
version: 1.3.2(react@19.1.0)
@@ -335,6 +338,9 @@ importers:
'@repo/eslint-config':
specifier: workspace:*
version: link:../../packages/eslint-config
+ '@repo/shared-components':
+ specifier: workspace:*
+ version: link:../../packages/shared-components
'@repo/typescript-config':
specifier: workspace:*
version: link:../../packages/typescript-config
@@ -403,7 +409,7 @@ importers:
version: 15.3.3(@babel/core@7.27.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
next-auth:
specifier: ^4.24.11
- version: 4.24.11(next@15.3.3(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
+ version: 4.24.11(next@15.3.3(@babel/core@7.27.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
next-remove-imports:
specifier: ^1.0.12
version: 1.0.12(webpack@5.99.9)
@@ -458,6 +464,9 @@ importers:
'@repo/db':
specifier: workspace:*
version: link:../../packages/database
+ '@repo/shared-components':
+ specifier: workspace:*
+ version: link:../../packages/shared-components
'@repo/typescript-config':
specifier: workspace:*
version: link:../../packages/typescript-config
@@ -566,6 +575,37 @@ importers:
specifier: ^8.15.0
version: 8.33.1(eslint@9.28.0(jiti@2.4.2))(typescript@5.8.3)
+ packages/shared-components:
+ dependencies:
+ '@repo/db':
+ specifier: workspace:*
+ version: link:../database
+ '@repo/typescript-config':
+ specifier: workspace:*
+ version: link:../typescript-config
+ '@types/node':
+ specifier: ^22.15.29
+ version: 22.15.29
+ clsx:
+ specifier: ^2.1.1
+ version: 2.1.1
+ tailwind-merge:
+ specifier: ^3.3.0
+ version: 3.3.0
+ devDependencies:
+ '@types/react':
+ specifier: ^19.1.6
+ version: 19.1.6
+ '@types/react-dom':
+ specifier: ^19.1.5
+ version: 19.1.5(@types/react@19.1.6)
+ react:
+ specifier: ^19.1.0
+ version: 19.1.0
+ react-dom:
+ specifier: ^19.1.0
+ version: 19.1.0(react@19.1.0)
+
packages/typescript-config: {}
packages:
@@ -6596,10 +6636,10 @@ snapshots:
'@tybys/wasm-util': 0.9.0
optional: true
- '@next-auth/prisma-adapter@1.0.7(@prisma/client@6.8.2(prisma@6.8.2(typescript@5.8.3))(typescript@5.8.3))(next-auth@4.24.11(next@15.3.3(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react-dom@19.1.0(react@19.1.0))(react@19.1.0))':
+ '@next-auth/prisma-adapter@1.0.7(@prisma/client@6.8.2(prisma@6.8.2(typescript@5.8.3))(typescript@5.8.3))(next-auth@4.24.11(next@15.3.3(@babel/core@7.27.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react-dom@19.1.0(react@19.1.0))(react@19.1.0))':
dependencies:
'@prisma/client': 6.8.2(prisma@6.8.2(typescript@5.8.3))(typescript@5.8.3)
- next-auth: 4.24.11(next@15.3.3(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
+ next-auth: 4.24.11(next@15.3.3(@babel/core@7.27.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
'@next/env@15.3.3': {}
@@ -10945,7 +10985,7 @@ snapshots:
neo-async@2.6.2: {}
- next-auth@4.24.11(next@15.3.3(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react-dom@19.1.0(react@19.1.0))(react@19.1.0):
+ next-auth@4.24.11(next@15.3.3(@babel/core@7.27.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react-dom@19.1.0(react@19.1.0))(react@19.1.0):
dependencies:
'@babel/runtime': 7.27.4
'@panva/hkdf': 1.2.1