Skip to content

Commit ccab44b

Browse files
authored
Merge pull request #5 from CodeMeAPixel/dev
fix(stuff): create internal routes for external apis and more
2 parents 476f9f9 + ff560ee commit ccab44b

File tree

13 files changed

+129
-33
lines changed

13 files changed

+129
-33
lines changed

CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,19 +20,27 @@ For more information, see:
2020
- Middleware and Navbar now gate dashboard/tools access for unverified users; only Overview is accessible until email is verified.
2121
- NextAuth session callback now always includes emailVerified for reliable client checks.
2222
- Health check API endpoints for all tools: `/api/definer/health`, `/api/rephraser/health`, `/api/spellcheck/health`, `/api/tldr/health`.
23+
- Internal API routes for Ackee analytics: `/api/ackee/tracker.js` proxies the tracker script, `/api/ackee/collect` proxies tracking requests.
2324

2425
### Changed
2526

2627
- Navbar and middleware logic now use emailVerified as a date (not boolean) for verification checks.
2728
- Improved spellchecker result logic and user activity payload to include wordsFixed and issuesCount.
2829
- Settings page and API routes now properly handle user data directory in production.
30+
- StatusIndicator now uses the internal `/api/status` route and displays a user-friendly status label as a link.
31+
- Footer component updated: system status indicator moved beside social icons for improved UX.
32+
- All auth forms (sign-in, sign-up, reset, forgot) now open the keyboard immediately on mobile by removing `readOnly` and `onFocus` from input fields.
33+
- After login and email verification, the app now calls `router.refresh()` to ensure session and navbar state update instantly (fixes mobile redirect and UI issues).
34+
- Ackee analytics script in layout now uses internal API endpoints for improved privacy and CORS handling.
2935

3036
### Fixed
3137

3238
- Fixed Prisma errors for spellchecker: correct model name, user relation, and added missing wordsFixed field.
3339
- Fixed CORS error explanation for external analytics (Ackee): clarified that CORS must be set server-side, not in Next.js config.
3440
- Fixed email verification logic to match NextAuth's use of a date for emailVerified.
3541
- Fixed middleware to allow /auth/verify for logged-in users.
42+
- Mobile keyboard now reliably opens for all input fields in authentication forms.
43+
- Auth redirect and navbar state now update immediately after login and email verification, especially on mobile devices.
3644

3745
### Removed
3846

next.config.ts

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,17 @@ const nextConfig: NextConfig = {
1919
{
2020
source: "/:path*",
2121
headers: [
22+
{
23+
key: "Powered-By",
24+
value: "ByteBrush Studios <bytebrush.dev>",
25+
},
26+
{
27+
key: "X-Powered-By",
28+
value: "ByteBrush Studios <bytebrush.dev>",
29+
},
2230
{
2331
key: "Access-Control-Allow-Origin",
24-
value: "*", // Set your origin
32+
value: "*",
2533
},
2634
{
2735
key: "Access-Control-Allow-Methods",
@@ -31,6 +39,26 @@ const nextConfig: NextConfig = {
3139
key: "Access-Control-Allow-Headers",
3240
value: "Content-Type, Authorization",
3341
},
42+
{
43+
key: "X-DNS-Prefetch-Control",
44+
value: "on",
45+
},
46+
{
47+
key: "Strict-Transport-Policy",
48+
value: "max-age=63072000; includeSubDomains; preload",
49+
},
50+
{
51+
key: "X-Content-Type-Options",
52+
value: "nosniff",
53+
},
54+
{
55+
key: "X-XSS-Protection",
56+
value: "1; mode=block",
57+
},
58+
{
59+
key: "Referrer-Policy",
60+
value: "same-origin",
61+
},
3462
],
3563
},
3664
];

src/app/api/ackee/collect/route.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import { NextResponse } from "next/server";
2+
3+
const COLLECT_URL = "https://ackee.bytebrush.dev/api";
4+
5+
export async function POST(req: Request) {
6+
try {
7+
const body = await req.text();
8+
const res = await fetch(COLLECT_URL, {
9+
method: "POST",
10+
headers: {
11+
"Content-Type": req.headers.get("Content-Type") || "application/json",
12+
},
13+
body,
14+
});
15+
const data = await res.text();
16+
return new Response(data, {
17+
status: res.status,
18+
headers: {
19+
"Content-Type": res.headers.get("Content-Type") || "application/json",
20+
},
21+
});
22+
} catch (error) {
23+
return NextResponse.json(
24+
{ error: "Unable to proxy Ackee collect" },
25+
{ status: 500 },
26+
);
27+
}
28+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import { NextResponse } from "next/server";
2+
3+
const TRACKER_URL = "https://ackee.bytebrush.dev/tracker.js";
4+
5+
export async function GET() {
6+
try {
7+
const res = await fetch(TRACKER_URL);
8+
const js = await res.text();
9+
return new Response(js, {
10+
status: 200,
11+
headers: {
12+
"Content-Type": "application/javascript",
13+
"Cache-Control": "public, max-age=3600",
14+
},
15+
});
16+
} catch (error) {
17+
return NextResponse.json(
18+
{ error: "Unable to fetch Ackee tracker" },
19+
{ status: 500 },
20+
);
21+
}
22+
}

src/app/api/status/route.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import { NextResponse } from "next/server";
2+
3+
const STATUS_API_URL = "https://status.lexiapp.space/api/monitor";
4+
const STATUS_API_TOKEN = process.env.STATUS_API_TOKEN;
5+
6+
export async function GET() {
7+
try {
8+
const res = await fetch(STATUS_API_URL, {
9+
headers: STATUS_API_TOKEN
10+
? { Authorization: `Bearer ${STATUS_API_TOKEN}` }
11+
: {},
12+
next: { revalidate: 30 }, // cache for 30s
13+
});
14+
const data = await res.json();
15+
return NextResponse.json(data);
16+
} catch (error) {
17+
return NextResponse.json(
18+
{ error: "Unable to fetch status" },
19+
{ status: 500 },
20+
);
21+
}
22+
}

src/app/auth/forgot/page.tsx

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,8 +86,6 @@ export default function ForgotPage() {
8686
onChange={(e) => setEmail(e.target.value)}
8787
placeholder="you@example.com"
8888
autoComplete="off"
89-
readOnly
90-
onFocus={(e) => (e.currentTarget.readOnly = false)}
9189
/>
9290
</div>
9391

src/app/auth/reset/page.tsx

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -108,8 +108,6 @@ export default function ResetPage() {
108108
onChange={(e) => setCurrentPassword(e.target.value)}
109109
placeholder="Enter your current password"
110110
autoComplete="current-password"
111-
readOnly
112-
onFocus={(e) => (e.currentTarget.readOnly = false)}
113111
/>
114112
</div>
115113
)}
@@ -127,8 +125,6 @@ export default function ResetPage() {
127125
onChange={(e) => setPassword(e.target.value)}
128126
placeholder="At least 8 characters"
129127
autoComplete="new-password"
130-
readOnly
131-
onFocus={(e) => (e.currentTarget.readOnly = false)}
132128
/>
133129
</div>
134130

@@ -143,8 +139,6 @@ export default function ResetPage() {
143139
onChange={(e) => setConfirm(e.target.value)}
144140
placeholder="Confirm new password"
145141
autoComplete="new-password"
146-
readOnly
147-
onFocus={(e) => (e.currentTarget.readOnly = false)}
148142
/>
149143
</div>
150144

src/app/auth/signin/page.tsx

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ export default function SignInPage() {
2626
if (res?.ok) {
2727
toast.success("Signed in");
2828
router.push("/dashboard");
29+
router.refresh();
2930
} else {
3031
// next-auth returns an error string in res.error when redirect=false
3132
toast.error(res?.error || "Sign in failed");
@@ -87,8 +88,6 @@ export default function SignInPage() {
8788
placeholder="Enter your email"
8889
onChange={(e) => setEmail(e.target.value)}
8990
autoComplete="off"
90-
readOnly
91-
onFocus={(e) => (e.currentTarget.readOnly = false)}
9291
/>
9392
</div>
9493

@@ -105,8 +104,6 @@ export default function SignInPage() {
105104
placeholder="Enter your password"
106105
onChange={(e) => setPassword(e.target.value)}
107106
autoComplete="off"
108-
readOnly
109-
onFocus={(e) => (e.currentTarget.readOnly = false)}
110107
/>
111108
</div>
112109

src/app/auth/signup/page.tsx

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -125,8 +125,6 @@ export default function SignUpPage() {
125125
onChange={(e) => setEmail(e.target.value)}
126126
placeholder="you@example.com"
127127
autoComplete="off"
128-
readOnly
129-
onFocus={(e) => (e.currentTarget.readOnly = false)}
130128
/>
131129
</div>
132130

@@ -143,8 +141,6 @@ export default function SignUpPage() {
143141
onChange={(e) => setPassword(e.target.value)}
144142
placeholder="At least 8 characters"
145143
autoComplete="new-password"
146-
readOnly
147-
onFocus={(e) => (e.currentTarget.readOnly = false)}
148144
/>
149145
</div>
150146

src/app/auth/verify/page.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ export default function VerifyPage() {
5656
// Optionally redirect to dashboard after a short delay
5757
setTimeout(() => {
5858
router.push("/dashboard");
59+
router.refresh();
5960
}, 1400);
6061
} catch (err) {
6162
console.error(err);

0 commit comments

Comments
 (0)