diff --git a/.github/workflows/firebasedeploy.yml b/.github/workflows/firebasedeploy.yml new file mode 100644 index 0000000..788605b --- /dev/null +++ b/.github/workflows/firebasedeploy.yml @@ -0,0 +1,45 @@ +name: Deploy MainWeb to Firebase Hosting + +on: + push: + branches: + - main + pull_request: + +permissions: + contents: read + pull-requests: write + checks: write + +jobs: + build_and_deploy: + runs-on: ubuntu-latest + defaults: + run: + working-directory: sites/mainweb + + steps: + - uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v3 + with: + node-version: 20 + + - name: Install pnpm + run: npm install -g pnpm + + - name: Install dependencies + run: pnpm install + + - name: Build + run: pnpm build + + - name: Deploy to Firebase Hosting + uses: FirebaseExtended/action-hosting-deploy@v0 + with: + repoToken: ${{ secrets.GITHUB_TOKEN }} + firebaseServiceAccount: ${{ secrets.FIREBASE_SERVICE_ACCOUNT_DSGT }} + projectId: dsgt-website + channelId: ${{ github.event_name == 'pull_request' && format('pr-{0}', github.event.pull_request.number) || 'live' }} + entryPoint: sites/mainweb diff --git a/package.json b/package.json index adc3bc4..5ba2ff3 100644 --- a/package.json +++ b/package.json @@ -51,6 +51,7 @@ } }, "dependencies": { + "@tanstack/react-router": "^1.141.2", "autoprefixer": "^10.4.22", "chart.js": "^4.5.1", "postcss": "^8.5.6" diff --git a/packages/api/src/client.ts b/packages/api/src/client.ts deleted file mode 100644 index 19ac0b2..0000000 --- a/packages/api/src/client.ts +++ /dev/null @@ -1,2 +0,0 @@ -// Client-only types for trpc. Keep this file type-only to avoid pulling server code into bundles. -export type { AppRouter } from './index'; diff --git a/packages/api/src/index.ts b/packages/api/src/index.ts index 086ff94..cf9a5ab 100644 --- a/packages/api/src/index.ts +++ b/packages/api/src/index.ts @@ -1,31 +1,4 @@ -import { z } from 'zod'; - -import { createTRPCRouter, publicProcedure } from './trpc-server'; - -const portalRouter = createTRPCRouter({ - getDashboard: publicProcedure.query(() => ({ - title: 'Demo Dashboard', - widgets: [], - stats: { - users: 1234, - revenue: 9876, - growth: 12, - }, - })), - - updateProfile: publicProcedure - .input(z.object({ name: z.string(), email: z.string() })) - .mutation(({ input }) => { - // No-op mutation for demo purposes - return { success: true, input }; - }), -}); - -export const appRouter = createTRPCRouter({ - health: publicProcedure.query(() => ({ ok: true })), - portal: portalRouter, -}); - -export type AppRouter = typeof appRouter; - -export default appRouter; +// packages/api/src/index.ts +export { appRouter, createContext } from './root'; +export type { AppRouter, Context } from './root'; +export { trpc, createTRPCRouter, publicProcedure } from './trpc'; \ No newline at end of file diff --git a/packages/api/src/middleware.ts b/packages/api/src/middleware.ts deleted file mode 100644 index c38955b..0000000 --- a/packages/api/src/middleware.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { TRPCError } from '@trpc/server'; -import { db } from '@query/db'; -import { roles, users } from '@query/db/schema'; - -export async function requireAdmin(ctx: any) { - if (!ctx.user) throw new TRPCError({ code: 'UNAUTHORIZED' }); - - const u = await db.select().from(users).where(users.id.eq(ctx.user.id)).then(r => r[0]); - if (!u) throw new TRPCError({ code: 'UNAUTHORIZED' }); - - const r = await db.select().from(roles).where(roles.id.eq(u.role_id)).then(r => r[0]); - if (!r || r.name !== 'admin') throw new TRPCError({ code: 'FORBIDDEN' }); - - return true; -} diff --git a/packages/api/src/root.ts b/packages/api/src/root.ts new file mode 100644 index 0000000..7e13f9e --- /dev/null +++ b/packages/api/src/root.ts @@ -0,0 +1,18 @@ +import { createTRPCRouter } from './trpc'; +import { helloRouter } from './routers/hello'; + +// Context type +export type Context = {}; + +// Context creator +export const createContext = async (): Promise => { + return {}; +}; + +// Root app router +export const appRouter = createTRPCRouter({ + hello: helloRouter, +}); + +// Export API type +export type AppRouter = typeof appRouter; \ No newline at end of file diff --git a/packages/api/src/routers/hello.ts b/packages/api/src/routers/hello.ts new file mode 100644 index 0000000..2a397cd --- /dev/null +++ b/packages/api/src/routers/hello.ts @@ -0,0 +1,7 @@ +import { createTRPCRouter, publicProcedure } from '../trpc'; + +export const helloRouter = createTRPCRouter()({ + sayHello: publicProcedure.query(() => { + return { message: 'Hello, world!' }; + }), +}); \ No newline at end of file diff --git a/packages/api/src/trpc.ts b/packages/api/src/trpc.ts index 33171dd..6d23403 100644 --- a/packages/api/src/trpc.ts +++ b/packages/api/src/trpc.ts @@ -1,17 +1,9 @@ -import { createTRPCReact } from '@trpc/react-query'; -import type { AppRouter } from './index'; -import { httpBatchLink } from '@trpc/client'; +// packages/api/src/trpc.ts +import { initTRPC } from '@trpc/server'; +import { Context } from './root'; -export const trpc = createTRPCReact(); +export const t = initTRPC.context().create(); -export function createTrpcClient(baseUrl = '') { - return trpc.createClient({ - links: [ - httpBatchLink({ - url: `${baseUrl || ''}/api/trpc`, - }), - ], - }); -} +export const createTRPCRouter = t.router; -export type Trpc = typeof trpc; +export const publicProcedure = t.procedure; \ No newline at end of file diff --git a/packages/auth/src/hooks.ts b/packages/auth/src/hooks.ts deleted file mode 100644 index 7553edb..0000000 --- a/packages/auth/src/hooks.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { useQuery } from '@tanstack/react-query'; - -export function fetchSession() { - return fetch('/api/auth/me').then(r => r.json()).then((j) => j.user ?? null); -} - -export function useSession() { - return useQuery({ queryKey: ['session'], queryFn: fetchSession, staleTime: 1000 * 60 * 1 }); -} - -export default useSession; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e34ece7..97c06ad 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -15,6 +15,9 @@ importers: .: dependencies: + '@tanstack/react-router': + specifier: ^1.141.2 + version: 1.141.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1) autoprefixer: specifier: ^10.4.22 version: 10.4.22(postcss@8.5.6) @@ -284,6 +287,18 @@ importers: '@tanstack/react-query': specifier: ^5.90.12 version: 5.90.12(react@18.3.1) + '@trpc/client': + specifier: ^11.7.2 + version: 11.7.2(@trpc/server@11.7.2(typescript@5.9.3))(typescript@5.9.3) + '@trpc/next': + specifier: ^11.7.2 + version: 11.7.2(@tanstack/react-query@5.90.12(react@18.3.1))(@trpc/client@11.7.2(@trpc/server@11.7.2(typescript@5.9.3))(typescript@5.9.3))(@trpc/react-query@11.7.2(@tanstack/react-query@5.90.12(react@18.3.1))(@trpc/client@11.7.2(@trpc/server@11.7.2(typescript@5.9.3))(typescript@5.9.3))(@trpc/server@11.7.2(typescript@5.9.3))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.3))(@trpc/server@11.7.2(typescript@5.9.3))(next@16.0.10(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.96.0))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.3) + '@trpc/react-query': + specifier: ^11.7.2 + version: 11.7.2(@tanstack/react-query@5.90.12(react@18.3.1))(@trpc/client@11.7.2(@trpc/server@11.7.2(typescript@5.9.3))(typescript@5.9.3))(@trpc/server@11.7.2(typescript@5.9.3))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.3) + '@trpc/server': + specifier: ^11.7.2 + version: 11.7.2(typescript@5.9.3) next: specifier: ^16.0.10 version: 16.0.10(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.96.0) @@ -293,6 +308,9 @@ importers: react-dom: specifier: ^18.3.1 version: 18.3.1(react@18.3.1) + superjson: + specifier: ^2.2.6 + version: 2.2.6 devDependencies: '@query/eslint-config': specifier: workspace:* @@ -988,6 +1006,10 @@ packages: '@tailwindcss/postcss@4.1.18': resolution: {integrity: sha512-Ce0GFnzAOuPyfV5SxjXGn0CubwGcuDB0zcdaPuCSzAa/2vII24JTkH+I6jcbXLb1ctjZMZZI6OjDaLPJQL1S0g==} + '@tanstack/history@1.141.0': + resolution: {integrity: sha512-LS54XNyxyTs5m/pl1lkwlg7uZM3lvsv2FIIV1rsJgnfwVCnI+n4ZGZ2CcjNT13BPu/3hPP+iHmliBSscJxW5FQ==} + engines: {node: '>=12'} + '@tanstack/query-core@5.90.12': resolution: {integrity: sha512-T1/8t5DhV/SisWjDnaiU2drl6ySvsHj1bHBCWNXd+/T+Hh1cf6JodyEYMd5sgwm+b/mETT4EV3H+zCVczCU5hg==} @@ -996,6 +1018,26 @@ packages: peerDependencies: react: ^18.3.1 + '@tanstack/react-router@1.141.2': + resolution: {integrity: sha512-inPEgxYuGPNJvd7wo9BYVKW/BP9GwZO0EaZLBE7+l0RtPcIqAQQLqYhYwb2xikuQg6ueZectj7LObAGivkBpSw==} + engines: {node: '>=12'} + peerDependencies: + react: ^18.3.1 + react-dom: ^18.3.1 + + '@tanstack/react-store@0.8.0': + resolution: {integrity: sha512-1vG9beLIuB7q69skxK9r5xiLN3ztzIPfSQSs0GfeqWGO2tGIyInZx0x1COhpx97RKaONSoAb8C3dxacWksm1ow==} + peerDependencies: + react: ^18.3.1 + react-dom: ^18.3.1 + + '@tanstack/router-core@1.141.2': + resolution: {integrity: sha512-6fJSQ+Xcqy6xvB+CTEJljynf5wxQXC/YbtvxAc7wkzBLQwXvwoYrkmUTzqWHFtDZVGKr0cxA+Tg1FikSAZOiQQ==} + engines: {node: '>=12'} + + '@tanstack/store@0.8.0': + resolution: {integrity: sha512-Om+BO0YfMZe//X2z0uLF2j+75nQga6TpTJgLJQBiq85aOyZNIhkCgleNcud2KQg4k4v9Y9l+Uhru3qWMPGTOzQ==} + '@tootallnate/quickjs-emscripten@0.23.0': resolution: {integrity: sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA==} @@ -1417,6 +1459,9 @@ packages: constant-case@2.0.0: resolution: {integrity: sha512-eS0N9WwmjTqrOmR3o83F5vW8Z+9R1HnVz3xmzT2PMFug9ly+Au/fxRWlEBSb6LcZwspSsEn9Xs1uw9YgzAg1EQ==} + cookie-es@2.0.0: + resolution: {integrity: sha512-RAj4E421UYRgqokKUmotqAwuplYw15qtdXfY+hGzgCJ/MBjCVZcSoHK/kH9kocfjRjcDME7IiDWR/1WX1TM2Pg==} + copy-anything@4.0.5: resolution: {integrity: sha512-7Vv6asjS4gMOuILabD3l739tsaxFQmC+a7pLZm02zyvs8p977bL3zEgq3yDk5rn9B0PbYgIv++jmHcuUab4RhA==} engines: {node: '>=18'} @@ -2209,6 +2254,10 @@ packages: resolution: {integrity: sha512-iHrqe5shvBUcFbmZq9zOQHBoeOhZJu6RQGrDpBgenUm/Am+F3JM2MgQj+rK3Z601fzrL5gLZWtAPH2OBaSVcyw==} engines: {node: '>= 8.0.0'} + isbot@5.1.32: + resolution: {integrity: sha512-VNfjM73zz2IBZmdShMfAUg10prm6t7HFUQmNAEOAVS4YH92ZrZcvkMcGX6cIgBJAzWDzPent/EeAtYEHNPNPBQ==} + engines: {node: '>=18'} + isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} @@ -2900,6 +2949,16 @@ packages: sentence-case@2.1.1: resolution: {integrity: sha512-ENl7cYHaK/Ktwk5OTD+aDbQ3uC8IByu/6Bkg+HDv8Mm+XnBnppVNalcfJTNsp1ibstKh030/JKQQWglDvtKwEQ==} + seroval-plugins@1.4.0: + resolution: {integrity: sha512-zir1aWzoiax6pbBVjoYVd0O1QQXgIL3eVGBMsBsNmM8Ukq90yGaWlfx0AB9dTS8GPqrOrbXn79vmItCUP9U3BQ==} + engines: {node: '>=10'} + peerDependencies: + seroval: ^1.0 + + seroval@1.4.0: + resolution: {integrity: sha512-BdrNXdzlofomLTiRnwJTSEAaGKyHHZkbMXIywOh7zlzp4uZnXErEwl9XZ+N1hJSNpeTtNxWvVwN0wUzAIQ4Hpg==} + engines: {node: '>=10'} + set-function-length@1.2.2: resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} engines: {node: '>= 0.4'} @@ -3074,6 +3133,12 @@ packages: through@2.3.8: resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==} + tiny-invariant@1.3.3: + resolution: {integrity: sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==} + + tiny-warning@1.0.3: + resolution: {integrity: sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==} + tinycolor2@1.6.0: resolution: {integrity: sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw==} @@ -3225,6 +3290,11 @@ packages: uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + use-sync-external-store@1.6.0: + resolution: {integrity: sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==} + peerDependencies: + react: ^18.3.1 + util-deprecate@1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} @@ -3777,6 +3847,8 @@ snapshots: postcss: 8.5.6 tailwindcss: 4.1.18 + '@tanstack/history@1.141.0': {} + '@tanstack/query-core@5.90.12': {} '@tanstack/react-query@5.90.12(react@18.3.1)': @@ -3784,6 +3856,36 @@ snapshots: '@tanstack/query-core': 5.90.12 react: 18.3.1 + '@tanstack/react-router@1.141.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@tanstack/history': 1.141.0 + '@tanstack/react-store': 0.8.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@tanstack/router-core': 1.141.2 + isbot: 5.1.32 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + tiny-invariant: 1.3.3 + tiny-warning: 1.0.3 + + '@tanstack/react-store@0.8.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@tanstack/store': 0.8.0 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + use-sync-external-store: 1.6.0(react@18.3.1) + + '@tanstack/router-core@1.141.2': + dependencies: + '@tanstack/history': 1.141.0 + '@tanstack/store': 0.8.0 + cookie-es: 2.0.0 + seroval: 1.4.0 + seroval-plugins: 1.4.0(seroval@1.4.0) + tiny-invariant: 1.3.3 + tiny-warning: 1.0.3 + + '@tanstack/store@0.8.0': {} + '@tootallnate/quickjs-emscripten@0.23.0': {} '@trpc/client@11.7.2(@trpc/server@11.7.2(typescript@5.9.3))(typescript@5.9.3)': @@ -4296,6 +4398,8 @@ snapshots: snake-case: 2.1.0 upper-case: 1.1.3 + cookie-es@2.0.0: {} + copy-anything@4.0.5: dependencies: is-what: 5.5.0 @@ -5169,6 +5273,8 @@ snapshots: isbinaryfile@4.0.10: {} + isbot@5.1.32: {} + isexe@2.0.0: {} iterator.prototype@1.1.5: @@ -5817,6 +5923,12 @@ snapshots: no-case: 2.3.2 upper-case-first: 1.1.2 + seroval-plugins@1.4.0(seroval@1.4.0): + dependencies: + seroval: 1.4.0 + + seroval@1.4.0: {} + set-function-length@1.2.2: dependencies: define-data-property: 1.1.4 @@ -6047,6 +6159,10 @@ snapshots: through@2.3.8: {} + tiny-invariant@1.3.3: {} + + tiny-warning@1.0.3: {} + tinycolor2@1.6.0: {} tinyglobby@0.2.15: @@ -6210,6 +6326,10 @@ snapshots: dependencies: punycode: 2.3.1 + use-sync-external-store@1.6.0(react@18.3.1): + dependencies: + react: 18.3.1 + util-deprecate@1.0.2: {} uuid@9.0.1: {} diff --git a/sites/mainweb/.firebase/hosting.b3V0.cache b/sites/mainweb/.firebase/hosting.b3V0.cache new file mode 100644 index 0000000..9451eaf --- /dev/null +++ b/sites/mainweb/.firebase/hosting.b3V0.cache @@ -0,0 +1,131 @@ +vercel.svg,1765491604610,41e95a86eeec887b8b898097594cf4c4bc5da8f58faf05830e1229d7dcbeea59 +turborepo.svg,1765491604608,c61399e6b6aeeb4fa161d66d2be2a3f1d85339367fffe448e8b75b98b94ce760 +robots.txt,1765491604605,f3e941454ab0fb4c830fbaa94823bb95ec1f2dc6370a8f333984aefbcbf729c7 +next.svg,1765491604477,0665b9ab4493aa9d7e988b57024e28772ae543e804b8cf6b0a3633854b7c3c7f +manifest.json,1765769085200,a683f0cd827b000a28a4dbbbe3d336394e1650b811b03d8d1af094a2b3add866 +logo512.png,1765491604474,54e168ed5dcdc6fdc61bbac8c99342f016c185708d8d04efe3f0b063fb691315 +logo196.png,1765491604455,d785daa440354422616e9889f35616604710e9dd70313c6915b06fdd630b5b5a +logo128.png,1765491604339,b7909633f01379164dde11e53e42af2d12f7ad104762e36ebb5c8e05af0707f6 +favicon-32x32.png,1765491604335,1c59159f4c69cb8812c8e0b6963252b011a634f2613024785f340890175b68e0 +favicon-16x16.png,1765491604319,96e40605151630d7b4ef81deb967a1175580f4bb9c5fb332960c92af95efcc9a +circles.svg,1765491604317,b9a5fe10a2e645705abe338dea75c070a577193a1876d1b55f42407071bb2563 +background-design-1.png,1765491604314,b65b749e62adb599e8ccd10dd31d9077ae8cd9614ee215a0467d8e3dc969a153 +__next.__PAGE__.txt,1765919579761,629097e7213b287cd804231cf5981903be23aad6a39201b5b2e9069442aafb5c +__next._head.txt,1765919579762,44979ab28cad20d69d0d2fb4153417b1567a34cf23d86d2fae0f7edfbd489c74 +__next._tree.txt,1765919579760,ce5a4f65af85280c44931719e502d2f61f0d8696804ff7edd26a274175683b12 +__next._index.txt,1765919579762,ad6f1cc3cc6ca52576dc243df91381330b6c84e3bb1b4490db7c2f766678adb3 +__next._full.txt,1765919579760,47d52bf1a36d795173590860d856017816219e7dbbf41189e5d9bc1f858a7db4 +index.txt,1765919579787,47d52bf1a36d795173590860d856017816219e7dbbf41189e5d9bc1f858a7db4 +_not-found/__next._tree.txt,1765919579757,e4852bfa042050deda73daf18227493ebcea7bf6a6ab8d6d2c4c0d9fa22f3af8 +_not-found/__next._not-found.txt,1765919579759,15db576af193830c3e5863c8568226ce7d4f86cfbd89be6090a49a13344cb80d +_not-found/__next._index.txt,1765919579759,ad6f1cc3cc6ca52576dc243df91381330b6c84e3bb1b4490db7c2f766678adb3 +_not-found/__next._full.txt,1765919579757,9a30a853da099331b4a0be5fb2a2ea4b6e075c4370a65f17e5d1bc58e61b863a +_not-found/index.txt,1765919579767,9a30a853da099331b4a0be5fb2a2ea4b6e075c4370a65f17e5d1bc58e61b863a +_not-found/__next._not-found/__PAGE__.txt,1765919579795,477eed1114b5172a51199a2469fd5c888b18f1cbdb4ca9d8f238e4d2c7dd99af +_not-found/__next._head.txt,1765919579759,03d3a960ccdefeb829be129f8b9e61dc2f0a93c0e5b38be562ddd9f17ea91f09 +favicon.ico,1765919579720,9960c28b7d6ac352cf1ba11369584c8247271cb77e217561c647620d67872eea +_next/static/media/small-header--export.55654138.svg,1765919570841,331cbb87a266899507468acf1aa9ce8b2049625b448d30e5ad913d6f0b604327 +404.html,1765919579767,2e21667fe9e853f42bb51858646bc75ab3d42c9369796511f494ca8c113f34f1 +index.html,1765919579784,3db253d00c6cfcb6b80cf444179376e6b0250e6b89887ed15c20f5d974cd078c +_not-found/index.html,1765919579767,2e21667fe9e853f42bb51858646bc75ab3d42c9369796511f494ca8c113f34f1 +_next/static/media/sarvesh.7b29c81f.jpg,1765919570964,a77413f06c21341769a37ca9d32aeb01ef72d15f487ac71501989c7e13299786 +_next/static/media/hero2-mobile--export.05f476f3.svg,1765919570902,ca13110d1441ee47f227f1e412533caed21be8665c61dc492432ad1744327cf8 +_next/static/media/hero3--export.9fa9144e.svg,1765919570904,2a9b7e91560af95d37664651cd1814cdccc1b55422da8b50f93e36f8537003d3 +_next/static/media/Geist_UltraLight-s.p.618ca1e8.woff2,1765919571188,b8717e8eb60d08dcfba18cae79eeb20be95d9cbfd40667041074b210b19d3036 +_next/static/media/Geist_UltraBlack-s.p.83921453.woff2,1765919570948,5f07aee36dbc4e16a91aee45a14789d35a5dc6bf70574e90b5aec569041b173b +_next/static/media/Geist_SemiBold-s.p.1e9785bc.woff2,1765919571181,6fb115d592dd310235d18c4a3a705f2479fbdb337125b6e9657e7b7e32b7d7d5 +_next/static/media/Geist_Regular-s.p.d4cb610a.woff2,1765919571162,8b34795dc5ab55699dbac35ade3c3bdc2abbee61828ae7b0048215286c57783f +_next/static/media/Geist_Medium-s.p.0e2406be.woff2,1765919570944,2beb4c5a53ddd5120a6179a6973bf8f68a362dbcf04ded082243904a381f19ed +_next/static/media/Geist_Light-s.p.32f638d4.woff2,1765919571002,ea5007c3e87efaef4c594433d50344107847559b704a986ed19aa40cfe7d44fd +_next/static/media/Geist_Bold-s.p.ec10ca61.woff2,1765919571146,4d57ef2b25f85cfc72aa89a350aa17081f5b4204134268004284ac3840a4ae73 +_next/static/media/Geist_Black-s.p.1a53d763.woff2,1765919571134,b515dd90e543b7d58f6deba32c34d6895dcf3d5e3e3d5551279db1b2fc01c8b8 +_next/static/media/GeistMono_UltraLight.p.4c7d3b1f.woff2,1765919570999,56a7ed1c7604f2cfad35bea5c33a72898dab050c4b4cf4f6b0d9ecbcdcda3b58 +_next/static/media/GeistMono_Regular.p.c18b7e71.woff2,1765919570978,cffdb9897db53cb2b2eb88cae82a6f60826ae39bbbe9e9e25fb28798c0694863 +_next/static/media/GeistMono_UltraBlack.p.daa943a2.woff2,1765919571183,c6659da5b890353b05830ccb798be06955ff7b54ce373fda3e47c4f61a00fba8 +_next/static/media/GeistMono_SemiBold.p.20204b0d.woff2,1765919570984,a27724d1679dc02fbafe2895542a9cd144f579fb997c6dd6788373b82c264d3f +_next/static/media/GeistMono_Thin.p.e736dcca.woff2,1765919571182,ba4574a042d8dd5fb294d93fd1074fb47aaf9ec5002370d72f71ca41c9d3daca +_next/static/media/Geist_Thin-s.p.efc51e30.woff2,1765919571011,a49cfd8fbbac9317a0ac77278a7297578cc2ef9882b276378033380ddec9b661 +_next/static/media/GeistMono_Medium.p.5f165be8.woff2,1765919571182,df86e307ace4e9dc4d0bbd4455b3ab510ad7ee5b0305d8fad0fb545af47197d5 +_next/static/media/GeistMono_Bold.p.ebb42981.woff2,1765919570846,c2b783736b2280a4caf39dffbff10f1f7e8fc128b57825f76ea620c5ec297664 +_next/static/media/gtaa.89323d96.png,1765919571152,615cfea20fb380d6528b2a63fab185030efc89273855b1f3202f4a301b45ceba +_next/static/media/GeistMono_Light.p.80098253.woff2,1765919571160,1022b6f49b0a6cb7773bbeac2e0ae4783a7a82901d63dd9fab9d2c8ba929ef29 +_next/static/media/footer-mobile2--export.e0f99493.svg,1765919571000,c2e4aff114075836bbc2cb9f5ac305b36a007a33d22b873c49668ddc7197e17a +_next/static/media/footer--export.b9a17393.svg,1765919571143,3fcf9834eafbf752571acfff0600d275520ffe53f4329e14409c46ba226fbd80 +_next/static/media/favicon.a95ed13d.ico,1765919570996,9960c28b7d6ac352cf1ba11369584c8247271cb77e217561c647620d67872eea +_next/static/media/blueconduit.3962d94d.png,1765919570876,726e598bbc52b99c907087d2ddced839c61df4ab32bf95d5aa00cccd3bfd140a +_next/static/lqFHgu9hHn-nu3xdaq8u4/_ssgManifest.js,1765919579938,dc28a4dc92fe352ed5d2201bd3972ce47691bc8e89e0400a68d1541d0567c6d5 +_next/static/lqFHgu9hHn-nu3xdaq8u4/_clientMiddlewareManifest.json,1765919571836,61663fde99b3394d71653f41c19fe91269442622a4a6695f8352a70fbf5ca4c1 +_next/static/lqFHgu9hHn-nu3xdaq8u4/_buildManifest.js,1765919571829,dcbe1c9b9159ca21caea98e1bad364012ae284e9551375ca62b83d2811efac91 +_next/static/media/GeistMono_Black.p.bfd10e20.woff2,1765919570924,9d09d0dd38814ecb1af5e8f50657fc42b7ee79105a23b6bb2ebe3b0ffe050e80 +_next/static/media/apple-touch-icon.eed7d9d8.png,1765919571015,d60615679e857bfba6b5e33b60dd6b92f06af5a1b51c1ecb18aac24efec1e51d +_next/static/chunks/c412742eea0f5049.js,1765919570689,d1357441a3d65506509b5cb579246d3295dbeb4e8f0ac0a8a7fc6d6ada660241 +_next/static/chunks/f61486d49dd641b3.js,1765919570738,41bf24904f35dd5c4182ff52e56bfe93cc380fe83eb44c362a372e2f2598b5df +_next/static/chunks/turbopack-7b361e286cc0f325.js,1765919570695,95a46f15d4dc9d4ef5dfa47c9cbe789cb788e8520d485228992ad33ee5d3aa4e +_next/static/chunks/a536fe47eff8e4cb.js,1765919570795,d94db7d9994300ec54d4466777f87c6f2306081ded2f554a369b83b24f6e5d31 +_next/static/chunks/85f5bf30eea4a739.js,1765919570713,d238f5643e2afcaacded66dc50d52771bf946630a76d5b3949d07ee05eda62d9 +_next/static/chunks/86975727d825dc99.js,1765919570958,677fc1b23036e42feccb30fee06c632e00e4f08ec345b6ada1af3f86fcd5feae +_next/static/chunks/70ee7a359818d64d.css,1765919570755,6eef88e22437766fefa65cb3f18e65bc9d24aab5208af0b0a479f1c19bb996f8 +_next/static/chunks/6fff09fa62410a72.js,1765919570699,d26b10875111ad3b7c318d4e98826702bd167c188da4bb88b8344264e14fa2ad +_next/static/chunks/29e0737f437429dc.js,1765919570840,57992e2c6d16a8458f5ae008396712ef1b808994312ff888ee0971bffb0c5f84 +_next/static/chunks/f121244d1c17b88f.js,1765919570906,5ffb99a2a6b5091196a5ba436e6cc45880d78256f4ea37776dfeca16dd05121e +_next/static/chunks/02224c9ea0e5e629.js,1765919570772,f0229d6d7104f4e28979caf5a3326856b81e1bc89559fdc2691d243715eb4e3b +_next/static/media/square-logo.f757536d.png,1765919571180,5af85cd153427f89d01c1109e64d5110163bf32b6d199ea1817bd41048d106ed +_next/static/media/slide7.39d18fda.jpg,1765919571176,a41caad5bdf1dbd5b6e87fd7864b14df9e8564ac1d96a89bc23bbaeec654f0b2 +_next/static/chunks/1af65342bf6da70c.js,1765919570695,defc0dcb657fa60628664d868b67ab3eecd64c74859b0ef98ad3c7611e1b35d8 +team/__next._index.txt,1765919579765,ad6f1cc3cc6ca52576dc243df91381330b6c84e3bb1b4490db7c2f766678adb3 +team/__next._head.txt,1765919579764,44979ab28cad20d69d0d2fb4153417b1567a34cf23d86d2fae0f7edfbd489c74 +team/__next._tree.txt,1765919579763,c5ffe43ddc23dd9938160edf35b09f14111c1ee068de457721f5cd4fa48a2303 +team/__next.team.txt,1765919579764,15db576af193830c3e5863c8568226ce7d4f86cfbd89be6090a49a13344cb80d +team/__next._full.txt,1765919579763,f924b74645971f3a9c1404f676378748d03fd69463fd9bc94da7d6f12202e86b +_next/static/chunks/7a3d62a9d14a31c8.js,1765919570878,14b5723a1d0d8109bb4208f0201999352086ba3d90a07120b90add79104bfe85 +team/index.txt,1765919579791,f924b74645971f3a9c1404f676378748d03fd69463fd9bc94da7d6f12202e86b +tbd/__next._tree.txt,1765919579762,52cb13234c3990e99151efc4af7da62db8ca16d705820818e361149e3fe2542e +team/__next.team/__PAGE__.txt,1765919579802,6216b06107c363dd811846e784bf8748227cdf8c24404567cb4ca23b2f8c18aa +tbd/__next._index.txt,1765919579763,ad6f1cc3cc6ca52576dc243df91381330b6c84e3bb1b4490db7c2f766678adb3 +_next/static/chunks/a6dad97d9634a72d.js,1765919570690,18e28d3214eda45048d80d3925ea7627b809e69ad2e95f7f98459e9146a61c3d +_next/static/chunks/565602ed0dc136be.js,1765919570692,fd92b8281e5167206bb070a79b26c5e83938bce953e6eefbf83227fdb82e2caf +_next/static/chunks/077019085113a077.js,1765919570813,8e716b861376cbf4fc52bcc4c26e0b4e12d32b81ef2641ff2fe53d9a8a418796 +_next/static/media/furnichanter.f3557e02.png,1765919570992,156f59d5d1dfd47a3d57212c16846f3ce0848e7268dabba3971873f685d2caf0 +tbd/__next._head.txt,1765919579763,44979ab28cad20d69d0d2fb4153417b1567a34cf23d86d2fae0f7edfbd489c74 +_next/static/media/alysha.4c0aa460.png,1765919571133,76d2d5ccb459d41e819df9528f9f55d8c32158cb2a5f054077ef651ff35aab55 +tbd/__next.tbd.txt,1765919579763,15db576af193830c3e5863c8568226ce7d4f86cfbd89be6090a49a13344cb80d +tbd/__next._full.txt,1765919579762,31bf79abfa976a9628cced28e451bbe285430713c93e133b470693e5f61bbb63 +tbd/index.txt,1765919579787,31bf79abfa976a9628cced28e451bbe285430713c93e133b470693e5f61bbb63 +tbd/__next.tbd/__PAGE__.txt,1765919579799,a4d2391efa4abcd4f53314692a37fcb52203f36fc647188d4d89c158c584ee77 +projects/__next._tree.txt,1765919579765,a3bb7ea563b6c7483b8e0f9c1b27a4ced13eaec8014d881085f1fd5e57cad70a +projects/__next._index.txt,1765919579765,ad6f1cc3cc6ca52576dc243df91381330b6c84e3bb1b4490db7c2f766678adb3 +projects/__next._head.txt,1765919579766,44979ab28cad20d69d0d2fb4153417b1567a34cf23d86d2fae0f7edfbd489c74 +projects/__next._full.txt,1765919579764,2a30049b9dda5be6dcb9024983adebbcfd9c6e085bfdd0b1c9ac724946ba28ed +projects/__next.projects.txt,1765919579765,15db576af193830c3e5863c8568226ce7d4f86cfbd89be6090a49a13344cb80d +_next/static/media/slide1.ad45d428.jpg,1765919571036,a4efbbc9c3b91bd3fc2825f9cca88b2f26f1bc3c101c61e0d8dbf35f69e72fe7 +projects/index.txt,1765919579793,2a30049b9dda5be6dcb9024983adebbcfd9c6e085bfdd0b1c9ac724946ba28ed +_next/static/chunks/e77ef383f0c30b7b.js,1765919570696,9a1f91841d9e35cc42c7484773292448ea5ded37ae9a7bdef8f5adda3c5997da +_next/static/media/arc-logo-v3.d5981609.png,1765919571075,7d0f48acde15ea2c9dd41653ddc8a52e2b0937df99fd0f501edec6686acb9e68 +team/index.html,1765919579791,f443ed5a408cc2d78852c6918f1e3dda57469d47a00bb92cef8102c0e637f6c8 +projects/__next.projects/__PAGE__.txt,1765919579799,6102a6a327915897653eaa30fd822dad23af2d87b2be6b57a5939f13ee8f655e +bootcamp/__next._tree.txt,1765919579759,39dc2cf21bddcac0cb28c5d30a81f8378ec5370e7d6d2518b497d1da62f76662 +bootcamp/__next._index.txt,1765919579760,ad6f1cc3cc6ca52576dc243df91381330b6c84e3bb1b4490db7c2f766678adb3 +bootcamp/__next._head.txt,1765919579760,44979ab28cad20d69d0d2fb4153417b1567a34cf23d86d2fae0f7edfbd489c74 +tbd/index.html,1765919579790,470b2ff0c3ebee97396863e6b801eee12a9a0ab8183df11b3ae9ce6df5a5787a +bootcamp/__next.bootcamp.txt,1765919579760,15db576af193830c3e5863c8568226ce7d4f86cfbd89be6090a49a13344cb80d +bootcamp/__next._full.txt,1765919579759,db4efe53e751465d9bebc37d4ed6165635a3648fedc25117b780d9147b52aef3 +bootcamp/index.txt,1765919579770,db4efe53e751465d9bebc37d4ed6165635a3648fedc25117b780d9147b52aef3 +bootcamp/__next.bootcamp/__PAGE__.txt,1765919579759,e840a5fdce679427c4c312102e4253745d5fcb6838404fe269c9cee5e6ce9f9c +projects/index.html,1765919579792,d5df6ba95ac69b589a4de3bbdc0e0c04cf49525f1a3dcabf8efdbac16c5c4dce +_next/static/chunks/0dbc6fd1725ef39b.js,1765919570760,366a25587c3c8b2253a2da19ce83b51c7635c8219bd3d9c5388ba38eb5d0f0b9 +_next/static/media/vidhi.d57eb8e4.jpeg,1765919571018,49cad84fd0da2e2153012f6d84c21c082960f9c77f704235bb88f5d9e8a86338 +_next/static/media/glenne.024028bc.png,1765919570843,3bbf2bc89221e96c0692271b78e920ac61e41782214e83b8c7293ba06c9ab4ca +bootcamp/index.html,1765919579769,e0e4ec0743526e4860e9b4cb140072c17c52499aafc094069a8a0fb7b134b8ec +404/index.html,1765919579767,2e21667fe9e853f42bb51858646bc75ab3d42c9369796511f494ca8c113f34f1 +_next/static/media/aryan.96244433.jpeg,1765919570974,9a52fccffd26cd4450758c86ef9fa9038a36bbe4408e1d2ba187dead318816d9 +_next/static/media/anika.bbbc6f00.jpg,1765919571188,2ecf43df467962740bfee3d4542b533d44078b5d7e3622992b494ef03eb2c50d +_next/static/media/nitika.0f7200f9.jpg,1765919571146,a78a264b1092a2d0ad221e38dc05b3c41f7570f1ef8f6268320a64f7a6376798 +_next/static/media/stock.db898f7a.png,1765919571023,305debac9897de35133db980e481ed646355f3af8c84aa111e5e78e12d9edee4 +_next/static/media/slide8.de56424b.jpg,1765919571009,ed80c71a51a4804a8213f05a7c702d1af7188a644004b948f27895683b8b0b7d +_next/static/media/aamogh.6e87f5ad.png,1765919571131,635d4527701ec0d20f20b07553f822973404318cef573172178ff177f157fb09 +_next/static/media/anushka.cae1c007.jpg,1765919570887,a00e0c86a798d053352b2f75c39da92557743a9addd0206f1de7c68d4721c565 +_next/static/media/squad.345b2a57.jpg,1765919571142,4f80fded3e892e7066dce70fd331dfbbc05b9f35fb478dcf16025b5670895a76 +_next/static/media/diya.d702a49e.jpeg,1765919571090,54f1ecd202837c6bf2baa160b495e7a6c994a9d953e8ab1f24e59e76d3067452 +_next/static/media/aditi.11e9e44a.jpg,1765919571117,bba26c574f86bf90a44f6558f369a08d91aeb4c5709da7f523f1370401989750 +_next/static/media/smera.42ac48ea.png,1765919570896,43a3f97edab937f3407546d41fd85dc254e964d2ab680d752a666e0e3d6bcc1f +_next/static/media/slide6.b94c9d09.jpg,1765919571069,b416386125adb61d55800836777af4e7c90eb8c557901b8411fb2305cd10545e diff --git a/sites/mainweb/.firebaserc b/sites/mainweb/.firebaserc new file mode 100644 index 0000000..103f458 --- /dev/null +++ b/sites/mainweb/.firebaserc @@ -0,0 +1,5 @@ +{ + "projects": { + "default": "dsgt-website" + } +} diff --git a/sites/mainweb/app/page.tsx b/sites/mainweb/app/page.tsx index e3a5ac5..8590e13 100644 --- a/sites/mainweb/app/page.tsx +++ b/sites/mainweb/app/page.tsx @@ -21,7 +21,7 @@ import dynamic from "next/dynamic"; import { ClassData, MajorData } from "@/assets/Data/demographics"; import slide1 from "@/assets/images/slides/slide1.jpg"; -import slide2 from "@/assets/images/slides/slide2.jpg"; +import squad from "@/assets/images/2025/squad.jpg"; import slide6 from "@/assets/images/slides/slide6.jpg"; import slide7 from "@/assets/images/slides/slide7.jpg"; import slide8 from "@/assets/images/slides/slide8.jpg"; @@ -107,9 +107,8 @@ const Home = () => {
-
The DSGT Executive Team in a group photo { Data Science
@ Georgia Tech -
- - -
- The largest student-run data science organization at Georgia Tech.
diff --git a/sites/mainweb/firebase.json b/sites/mainweb/firebase.json new file mode 100644 index 0000000..ef823af --- /dev/null +++ b/sites/mainweb/firebase.json @@ -0,0 +1,5 @@ +{ + "hosting": { + "public": "out" + } +} \ No newline at end of file diff --git a/sites/mainweb/next.config.mjs b/sites/mainweb/next.config.mjs index 71fe93c..24eb6e2 100644 --- a/sites/mainweb/next.config.mjs +++ b/sites/mainweb/next.config.mjs @@ -1,10 +1,11 @@ -// next.config.mjs +// next.config.mjs OR next.config.js (if type: module is in package.json) +/** @type {import('next').NextConfig} */ const nextConfig = { - reactStrictMode: true, - // Remove or comment out experimental.turbopack - // experimental: { - // turbopack: true, - // }, + output: 'export', + trailingSlash: true, + images: { + unoptimized: true, + }, }; -export default nextConfig; +export default nextConfig; // Change from module.exports \ No newline at end of file diff --git a/sites/mainweb/start.sh b/sites/mainweb/start.sh index 4479d36..3ea8d8c 100644 --- a/sites/mainweb/start.sh +++ b/sites/mainweb/start.sh @@ -1,20 +1,33 @@ #!/bin/bash - -# A simple script to build a project using pnpm turbo -# and then start the development server. - -# Exit immediately if a command exits with a non-zero status set -e echo "Starting project build with pnpm turbo build..." -# 1. Execute the build command pnpm turbo build -echo "Build complete. Starting development server with pnpm run dev..." -# 2. Execute the development server command -# This command is expected to run indefinitely (until manually stopped) -pnpm run dev +echo "Build complete." + +read -p "Do you want to deploy to Firebase Hosting now? (y/N): " DEPLOY_ANSWER + +if [[ "$DEPLOY_ANSWER" =~ ^[Yy]$ ]]; then + echo "Deploying to Firebase Hosting..." -# The script will only reach this point if the 'pnpm run dev' command -# exits for some reason (e.g., if it's not a continuous process) -echo "Development server process has ended." \ No newline at end of file + if ! command -v firebase &> /dev/null; then + echo "Firebase CLI not found. Installing..." + pnpm add -g firebase-tools + fi + + if ! firebase login:list | grep -q "Logged in"; then + echo "Logging into Firebase..." + firebase login + fi + + firebase deploy --only hosting --project dsgt-website + echo "Deployment complete!" +else + echo "Skipping Firebase deploy." +fi + +echo "Starting development server with pnpm run dev..." +pnpm run dev +n +echo "Development server process has ended." diff --git a/sites/portal/package.json b/sites/portal/package.json index c4cd77d..85fa9bd 100644 --- a/sites/portal/package.json +++ b/sites/portal/package.json @@ -16,6 +16,11 @@ "@query/db": "workspace:*", "@query/auth": "workspace:*", "@tanstack/react-query": "^5.90.12", + "@trpc/client": "^11.7.2", + "@trpc/react-query": "^11.7.2", + "@trpc/server": "^11.7.2", + "@trpc/next": "^11.7.2", + "superjson": "^2.2.6", "next": "^16.0.10", "react": "^19.2.1", "react-dom": "^19.2.1" @@ -33,4 +38,4 @@ "tailwindcss": "^4.1.5", "typescript": "5.9.3" } -} +} \ No newline at end of file diff --git a/sites/portal/src/app/api/auth/google/callback/route.ts b/sites/portal/src/app/api/auth/google/callback/route.ts deleted file mode 100644 index ea67dce..0000000 --- a/sites/portal/src/app/api/auth/google/callback/route.ts +++ /dev/null @@ -1,63 +0,0 @@ -import { NextResponse } from 'next/server'; -import { upsertUserFromGoogle, createSession } from '@query/auth'; - -async function exchangeCode(code: string, redirectUri: string) { - const params = new URLSearchParams({ - client_id: process.env.AUTH_GOOGLE_ID ?? '', - client_secret: process.env.AUTH_GOOGLE_SECRET ?? '', - code, - grant_type: 'authorization_code', - redirect_uri: redirectUri, - }); - - const res = await fetch('https://oauth2.googleapis.com/token', { - method: 'POST', - headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, - body: params.toString(), - }); - return res.json(); -} - -async function fetchProfile(accessToken: string) { - const res = await fetch('https://www.googleapis.com/oauth2/v3/userinfo', { - headers: { Authorization: `Bearer ${accessToken}` }, - }); - return res.json(); -} - -export async function GET(req: Request) { - const url = new URL(req.url); - const code = url.searchParams.get('code'); - const state = url.searchParams.get('state'); - if (!code) return NextResponse.json({ error: 'Missing code' }, { status: 400 }); - - // validate state against short-lived cookie - const cookies = req.headers.get('cookie') ?? ''; - const m = /(?:^|; )oauth_state=([^;]+)/.exec(cookies); - const cookieState = m?.[1]; - if (!state || !cookieState || state !== cookieState) { - return NextResponse.json({ error: 'Invalid or missing OAuth state' }, { status: 400 }); - } - - const redirectUri = `${process.env.NEXT_PUBLIC_APP_URL ?? process.env.AUTH_URL ?? 'http://localhost:3002'}/api/auth/google/callback`; - const tokenRes = await exchangeCode(code, redirectUri); - if (!tokenRes.access_token) return NextResponse.json({ error: 'Token exchange failed', details: tokenRes }, { status: 500 }); - - const profile = await fetchProfile(tokenRes.access_token); - const user = await upsertUserFromGoogle({ email: profile.email, name: profile.name, image: profile.picture, email_verified: profile.email_verified }); - - const session = await createSession(user.id); - - const res = NextResponse.redirect(process.env.NEXT_PUBLIC_APP_URL ?? '/'); - res.cookies.set('query_session', session.token, { - httpOnly: true, - path: '/', - maxAge: 60 * 60 * 24 * 30, - sameSite: 'lax', - secure: process.env.NODE_ENV === 'production', - }); - // clear oauth_state cookie - res.cookies.set('oauth_state', '', { path: '/api/auth/google/callback', maxAge: 0 }); - - return res; -} diff --git a/sites/portal/src/app/api/auth/google/start/route.ts b/sites/portal/src/app/api/auth/google/start/route.ts deleted file mode 100644 index 9365f35..0000000 --- a/sites/portal/src/app/api/auth/google/start/route.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { NextResponse } from 'next/server'; - -export async function GET() { - const clientId = process.env.AUTH_GOOGLE_ID; - const redirectUri = `${process.env.NEXT_PUBLIC_APP_URL ?? process.env.AUTH_URL ?? 'http://localhost:3002'}/api/auth/google/callback`; - const state = (globalThis.crypto && globalThis.crypto.randomUUID) ? globalThis.crypto.randomUUID() : String(Date.now()); - - const params = new URLSearchParams({ - client_id: clientId ?? '', - redirect_uri: redirectUri, - response_type: 'code', - scope: 'openid email profile', - access_type: 'offline', - prompt: 'consent', - state, - }); - - const res = NextResponse.redirect(`https://accounts.google.com/o/oauth2/v2/auth?${params.toString()}`); - // set short-lived state cookie to validate in callback (prevent CSRF) - res.cookies.set('oauth_state', state, { httpOnly: true, path: '/api/auth/google/callback', maxAge: 300, sameSite: 'lax', secure: process.env.NODE_ENV === 'production' }); - return res; -} diff --git a/sites/portal/src/app/api/auth/logout/route.ts b/sites/portal/src/app/api/auth/logout/route.ts deleted file mode 100644 index c1f7a6d..0000000 --- a/sites/portal/src/app/api/auth/logout/route.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { NextResponse } from 'next/server'; -import { deleteSessionByToken } from '@query/api/context'; - -export async function POST(req: Request) { - const cookies = req.headers.get('cookie') ?? ''; - const match = /(?:^|; )query_session=([^;]+)/.exec(cookies); - const token = match?.[1]; - if (token) { - await deleteSession(token).catch(() => {}); - } - - const res = NextResponse.json({ ok: true }); - res.cookies.set('query_session', '', { path: '/', maxAge: 0 }); - return res; -} diff --git a/sites/portal/src/app/api/auth/me/route.ts b/sites/portal/src/app/api/auth/me/route.ts deleted file mode 100644 index 02cf96c..0000000 --- a/sites/portal/src/app/api/auth/me/route.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { NextResponse } from 'next/server'; -import { getSessionFromRequest } from '@query/auth'; - -export async function GET(req: Request) { - const session = await getSessionFromRequest(req); - if (!session) return NextResponse.json({ user: null }); - return NextResponse.json({ user: session.user }); -} - diff --git a/sites/portal/src/app/api/trpc/[trpc].ts b/sites/portal/src/app/api/trpc/[trpc].ts new file mode 100644 index 0000000..7d5bf7f --- /dev/null +++ b/sites/portal/src/app/api/trpc/[trpc].ts @@ -0,0 +1,8 @@ +// sites/portal/pages/api/trpc/[trpc].ts +import { createNextApiHandler } from '@trpc/server/adapters/next'; +import { appRouter, createContext } from '@query/api'; + +export default createNextApiHandler({ + router: appRouter, + createContext, +}); \ No newline at end of file diff --git a/sites/portal/src/app/api/trpc/[trpc]/route.ts b/sites/portal/src/app/api/trpc/[trpc]/route.ts index 481aa75..cd83888 100644 --- a/sites/portal/src/app/api/trpc/[trpc]/route.ts +++ b/sites/portal/src/app/api/trpc/[trpc]/route.ts @@ -1,12 +1,13 @@ +// sites/portal/app/api/trpc/[trpc]/route.ts import { fetchRequestHandler } from '@trpc/server/adapters/fetch'; -import { appRouter } from '@query/api'; +import { appRouter, createContext } from '@query/api'; const handler = (req: Request) => fetchRequestHandler({ endpoint: '/api/trpc', req, router: appRouter, - createContext: (opts) => import('@query/api/trpc-server').then(m => m.createTRPCContext({ headers: opts.req.headers, req: opts.req })), + createContext, }); -export { handler as GET, handler as POST }; +export { handler as GET, handler as POST }; \ No newline at end of file diff --git a/sites/portal/src/app/layout.tsx b/sites/portal/src/app/layout.tsx index 686afce..211e645 100644 --- a/sites/portal/src/app/layout.tsx +++ b/sites/portal/src/app/layout.tsx @@ -1,13 +1,4 @@ import { Providers } from './providers'; -import '@query/ui/styles'; -import './globals.css'; - -export const metadata = { - title: 'Portal - Enigma', - description: 'Portal application', -}; - -import AuthHeader from '@/components/AuthHeader'; export default function RootLayout({ children, @@ -17,11 +8,8 @@ export default function RootLayout({ return ( - - - {children} - + {children} ); -} +} \ No newline at end of file diff --git a/sites/portal/src/app/page.tsx b/sites/portal/src/app/page.tsx index a962f94..453f1c7 100644 --- a/sites/portal/src/app/page.tsx +++ b/sites/portal/src/app/page.tsx @@ -1,87 +1,16 @@ - 'use client'; +'use client'; -import { trpc } from '@/utils/trpc'; -import { useEffect, useState } from 'react'; -import { useSession } from '@query/auth/hooks'; +import { trpc } from '../lib/trpc'; -export default function PortalHome() { - const { data, isLoading } = trpc.portal.getDashboard.useQuery(); - const utils = trpc.useContext(); - const updateProfile = trpc.portal.updateProfile.useMutation({ - onSuccess: () => { - utils.portal.getDashboard.invalidate(); - }, - }); - const { data: me } = useSession(); +export default function Home() { + const { data, isLoading } = trpc.hello.sayHello.useQuery(); - if (isLoading) { - return ( -
-
Loading...
-
- ); - } + if (isLoading) return
Loading...
; return ( -
-
-

- Portal Dashboard -

- - {data && ( -
-
-

Users

-

{data.stats.users}

-
- -
-

Revenue

-

${data.stats.revenue}

-
- -
-

Growth

-

{data.stats.growth}%

-
-
- )} - -
-

Authentication

- {me ? ( -
-

Signed in as {me.email}

-
{ - e.preventDefault(); - await updateProfile.mutateAsync({ name: me.name ?? '', email: me.email }); - }} - > - - -
-
- ) : ( - - Sign in with Google - - )} -
-
+
+

Portal

+

{data?.message}

); -} +} \ No newline at end of file diff --git a/sites/portal/src/app/providers.tsx b/sites/portal/src/app/providers.tsx index a80ce77..3cd9380 100644 --- a/sites/portal/src/app/providers.tsx +++ b/sites/portal/src/app/providers.tsx @@ -3,13 +3,7 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import { httpBatchLink } from '@trpc/client'; import { useState } from 'react'; -import { trpc } from '@/utils/trpc'; - -function getBaseUrl() { - if (typeof window !== 'undefined') return ''; - if (process.env.VERCEL_URL) return `https://${process.env.VERCEL_URL}`; - return 'http://localhost:3002'; -} +import { trpc } from '../lib/trpc'; export function Providers({ children }: { children: React.ReactNode }) { const [queryClient] = useState(() => new QueryClient()); @@ -17,7 +11,7 @@ export function Providers({ children }: { children: React.ReactNode }) { trpc.createClient({ links: [ httpBatchLink({ - url: `${getBaseUrl()}/api/trpc`, + url: '/api/trpc', }), ], }) @@ -25,7 +19,9 @@ export function Providers({ children }: { children: React.ReactNode }) { return ( - {children} + + {children} + ); -} +} \ No newline at end of file diff --git a/sites/portal/src/components/AuthHeader.tsx b/sites/portal/src/components/AuthHeader.tsx deleted file mode 100644 index 86bed91..0000000 --- a/sites/portal/src/components/AuthHeader.tsx +++ /dev/null @@ -1,40 +0,0 @@ -"use client"; -import React from "react"; -import { useSession } from "@query/auth/hooks"; - -export default function AuthHeader() { - const { data: user } = useSession(); - - return ( -
-
-
Portal
-
- {user ? ( -
- {user.name} - {user.name} - -
- ) : ( - - Sign in with Google - - )} -
-
-
- ); -} diff --git a/sites/portal/src/utils/trpc.ts b/sites/portal/src/lib/trpc.ts similarity index 60% rename from sites/portal/src/utils/trpc.ts rename to sites/portal/src/lib/trpc.ts index d59522e..b714b57 100644 --- a/sites/portal/src/utils/trpc.ts +++ b/sites/portal/src/lib/trpc.ts @@ -1,6 +1,4 @@ -'use client'; - import { createTRPCReact } from '@trpc/react-query'; import type { AppRouter } from '@query/api'; -export const trpc = createTRPCReact(); +export const trpc = createTRPCReact(); \ No newline at end of file diff --git a/sites/portal/tailwind.config.ts b/sites/portal/tailwind.config.ts deleted file mode 100644 index e309136..0000000 --- a/sites/portal/tailwind.config.ts +++ /dev/null @@ -1,12 +0,0 @@ -import type { Config } from 'tailwindcss'; -import sharedConfig from '@query/tailwind-config'; - -const config: Config = { - content: [ - './src/**/*.{js,ts,jsx,tsx,mdx}', - '../../packages/ui/src/**/*.{js,ts,jsx,tsx}', - ], - presets: [sharedConfig], -}; - -export default config; diff --git a/sites/portal/tsconfig.json b/sites/portal/tsconfig.json index d2600d2..3d9556d 100644 --- a/sites/portal/tsconfig.json +++ b/sites/portal/tsconfig.json @@ -4,7 +4,8 @@ "baseUrl": ".", "paths": { "@/*": ["./src/*"] - } + }, + "jsx": "react-jsx" // ← Add this line to enable JSX support }, "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"], "exclude": ["node_modules"]