Skip to content

Commit 83914f5

Browse files
fix profile page
1 parent 568a77c commit 83914f5

File tree

10 files changed

+411
-71
lines changed

10 files changed

+411
-71
lines changed

next.config.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ const withPWA = require("next-pwa")({
33
dest: "public",
44
disable: process.env.NODE_ENV === "development",
55
register: true,
6+
skipWaiting: true,
67
runtimeCaching: require("next-pwa/cache"),
78
buildExcludes: [
89
/middleware-manifest\.json$/,
@@ -11,6 +12,9 @@ const withPWA = require("next-pwa")({
1112
/^.+\\_middleware\.js$/,
1213
],
1314
publicExcludes: ["!robots.txt"],
15+
fallbacks: {
16+
document: "/_offline",
17+
},
1418
});
1519

1620
const nextConfig = {

prisma/dev.db

0 Bytes
Binary file not shown.

public/manifest.json

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,30 @@
11
{
22
"name": "Vets Who Code",
33
"short_name": "Vets Who Code",
4-
"theme_color": "#696969",
5-
"background_color": "#20AD96",
4+
"theme_color": "#c5203e",
5+
"background_color": "#091f40",
66
"display": "standalone",
77
"orientation": "portrait",
88
"start_url": "/",
99
"scope": "/",
1010
"icons": [
1111
{
12-
"src": "https://res.cloudinary.com/vetswhocode/image/upload/v1656268751/favicon_dpiacy.png",
12+
"src": "/favicon.ico",
13+
"sizes": "48x48",
14+
"type": "image/x-icon"
15+
},
16+
{
17+
"src": "/images/favicon.png",
1318
"sizes": "192x192",
1419
"type": "image/png"
1520
},
1621
{
17-
"src": "https://res.cloudinary.com/vetswhocode/image/upload/v1656268751/favicon_dpiacy.png",
22+
"src": "/images/favicon.png",
1823
"sizes": "512x512",
1924
"type": "image/png"
2025
},
2126
{
22-
"src": "https://res.cloudinary.com/vetswhocode/image/upload/v1656268751/favicon_dpiacy.png",
27+
"src": "/images/favicon.png",
2328
"sizes": "512x512",
2429
"type": "image/png",
2530
"purpose": "maskable"

src/pages/_document.tsx

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,17 @@ export default class MyDocument extends Document {
1010
return (
1111
<Html lang="en">
1212
<Head>
13+
{/* PWA Meta Tags */}
14+
<meta name="mobile-web-app-capable" content="yes" />
15+
<meta name="apple-mobile-web-app-capable" content="yes" />
16+
<meta name="apple-mobile-web-app-status-bar-style" content="default" />
17+
<meta name="apple-mobile-web-app-title" content="Vets Who Code" />
18+
<meta name="theme-color" content="#c5203e" />
19+
20+
{/* Favicon and Icons */}
21+
<link rel="icon" href="/favicon.ico" />
22+
<link rel="apple-touch-icon" href="/images/favicon.png" />
23+
1324
<link
1425
rel="stylesheet"
1526
href="https://pro.fontawesome.com/releases/v5.15.4/css/all.css"

src/pages/_offline.tsx

Lines changed: 90 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,90 @@
1-
export default () => (
2-
<>
3-
<h1>This is offline fallback page</h1>
4-
<h2>When offline, any page route will fallback to this page</h2>
5-
</>
6-
);
1+
import React from "react";
2+
import Layout01 from "@layout/layout-01";
3+
import type { GetStaticProps, NextPage } from "next";
4+
import SEO from "@components/seo/page-seo";
5+
6+
type PageWithLayout = NextPage & {
7+
Layout?: typeof Layout01;
8+
};
9+
10+
const OfflinePage: PageWithLayout = () => {
11+
return (
12+
<>
13+
<SEO
14+
title="Offline - Vets Who Code"
15+
description="You are currently offline. Please check your internet connection."
16+
/>
17+
<div className="tw-flex tw-min-h-screen tw-items-center tw-justify-center tw-bg-gray-50">
18+
<div className="tw-mx-auto tw-max-w-md tw-p-8 tw-text-center">
19+
<div className="tw-mb-8">
20+
<svg
21+
className="tw-mx-auto tw-h-24 tw-w-24 tw-text-gray-400"
22+
fill="none"
23+
viewBox="0 0 24 24"
24+
stroke="currentColor"
25+
>
26+
<path
27+
strokeLinecap="round"
28+
strokeLinejoin="round"
29+
strokeWidth={1.5}
30+
d="M8.111 16.404a5.5 5.5 0 017.778 0M12 20h.01m-7.08-7.071c3.904-3.905 10.236-3.905 14.141 0M1.394 9.393c5.857-5.857 15.355-5.857 21.213 0"
31+
/>
32+
<path
33+
strokeLinecap="round"
34+
strokeLinejoin="round"
35+
strokeWidth={2}
36+
d="M6 18L18 6M6 6l12 12"
37+
/>
38+
</svg>
39+
</div>
40+
41+
<h1 className="tw-mb-4 tw-text-3xl tw-font-bold tw-text-gray-900">
42+
You're Offline
43+
</h1>
44+
45+
<p className="tw-mb-8 tw-text-lg tw-text-gray-600">
46+
No internet connection found. Please check your connection and try again.
47+
</p>
48+
49+
<div className="tw-space-y-4">
50+
<button
51+
type="button"
52+
onClick={() => window.location.reload()}
53+
className="tw-w-full tw-rounded-lg tw-bg-primary tw-px-6 tw-py-3 tw-font-medium tw-text-white tw-transition-colors hover:tw-bg-primary/90"
54+
>
55+
Try Again
56+
</button>
57+
58+
<button
59+
type="button"
60+
onClick={() => window.history.back()}
61+
className="tw-w-full tw-rounded-lg tw-bg-gray-200 tw-px-6 tw-py-3 tw-font-medium tw-text-gray-800 tw-transition-colors hover:tw-bg-gray-300"
62+
>
63+
Go Back
64+
</button>
65+
</div>
66+
67+
<div className="tw-mt-8 tw-text-sm tw-text-gray-500">
68+
<p>When you're back online, this page will automatically refresh.</p>
69+
</div>
70+
</div>
71+
</div>
72+
</>
73+
);
74+
};
75+
76+
OfflinePage.Layout = Layout01;
77+
78+
export const getStaticProps: GetStaticProps = () => {
79+
return {
80+
props: {
81+
layout: {
82+
headerShadow: true,
83+
headerFluid: false,
84+
footerMode: "light",
85+
},
86+
},
87+
};
88+
};
89+
90+
export default OfflinePage;

src/pages/api/dev/init-user.ts

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import { NextApiRequest, NextApiResponse } from "next";
2+
import prisma from "@/lib/prisma";
3+
4+
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
5+
if (req.method !== "POST") {
6+
return res.status(405).json({ error: "Method not allowed" });
7+
}
8+
9+
try {
10+
const { id, name, email, image } = req.body;
11+
12+
// Check if user exists
13+
let user = await prisma.user.findUnique({
14+
where: { id },
15+
});
16+
17+
if (!user) {
18+
// Create the user if they don't exist
19+
user = await prisma.user.create({
20+
data: {
21+
id,
22+
name,
23+
email,
24+
image,
25+
},
26+
});
27+
}
28+
29+
return res.status(200).json(user);
30+
} catch (error) {
31+
console.error("Error initializing dev user:", error);
32+
return res.status(500).json({ error: "Internal server error" });
33+
}
34+
}

src/pages/api/user/profile.ts

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -94,12 +94,21 @@ async function handleUpdateProfile(userId: string, body: UpdateProfileBody, res:
9494
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
9595
const session = await getSession({ req });
9696

97-
if (!session?.user?.id) {
97+
// Support dev mode: check for dev-user-id header
98+
const devUserId = req.headers["x-dev-user-id"] as string;
99+
100+
let userId: string;
101+
102+
if (devUserId) {
103+
// Dev mode - use the provided dev user ID
104+
userId = devUserId;
105+
} else if (session?.user?.id) {
106+
// Production mode - use NextAuth session
107+
userId = session.user.id;
108+
} else {
98109
return res.status(401).json({ error: "Unauthorized" });
99110
}
100111

101-
const userId = session.user.id;
102-
103112
if (req.method === "GET") {
104113
return handleGetProfile(userId, res);
105114
}

src/pages/login.tsx

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,33 @@ const Login: PageWithLayout = () => {
5252
}
5353
}, []);
5454

55+
// Dev-only login for Jerome
56+
const handleDevLogin = useCallback(async () => {
57+
if (typeof window !== "undefined") {
58+
try {
59+
const devUser = {
60+
id: "dev-jerome",
61+
name: "Jerome Hardaway",
62+
63+
image: "https://github.com/jeromehardaway.png",
64+
};
65+
66+
// Initialize user in database
67+
await fetch("/api/dev/init-user", {
68+
method: "POST",
69+
headers: { "Content-Type": "application/json" },
70+
body: JSON.stringify(devUser),
71+
});
72+
73+
localStorage.setItem("dev-session", JSON.stringify(devUser));
74+
router.replace("/profile");
75+
} catch (error) {
76+
console.error("Dev login error:", error);
77+
setErrorMessage("Failed to initialize dev session");
78+
}
79+
}
80+
}, [router]);
81+
5582
if (!mounted || status === "loading") {
5683
return (
5784
<div className="tw-fixed tw-top-0 tw-z-50 tw-flex tw-h-screen tw-w-screen tw-items-center tw-justify-center tw-bg-white">
@@ -77,7 +104,7 @@ const Login: PageWithLayout = () => {
77104
</div>
78105
)}
79106
</div>
80-
<div className="tw-p-6">
107+
<div className="tw-p-6 tw-space-y-3">
81108
<button
82109
type="button"
83110
onClick={handleSignIn}
@@ -87,6 +114,27 @@ const Login: PageWithLayout = () => {
87114
<i className="fab fa-github" />
88115
Sign in with GitHub
89116
</button>
117+
118+
{/* Dev Login - Only for local development */}
119+
<div className="tw-relative">
120+
<div className="tw-absolute tw-inset-0 tw-flex tw-items-center">
121+
<div className="tw-w-full tw-border-t tw-border-gray-300" />
122+
</div>
123+
<div className="tw-relative tw-flex tw-justify-center tw-text-sm">
124+
<span className="tw-bg-white tw-px-2 tw-text-gray-500">
125+
Dev Mode
126+
</span>
127+
</div>
128+
</div>
129+
130+
<button
131+
type="button"
132+
onClick={handleDevLogin}
133+
className="tw-flex tw-w-full tw-items-center tw-justify-center tw-gap-2 tw-rounded-md tw-bg-secondary tw-px-4 tw-py-3 tw-text-sm tw-font-medium tw-text-white tw-transition-colors hover:tw-opacity-90"
134+
>
135+
<i className="fas fa-user-shield" />
136+
Dev Login (Jerome Only)
137+
</button>
90138
</div>
91139
<div className="tw-px-8 tw-pb-8">
92140
<p className="tw-text-center tw-text-sm tw-text-secondary">

0 commit comments

Comments
 (0)