Commit ·
c2c654e
1
Parent(s): 53be399
added env example and refactor frontend
Browse files- .env.example +19 -0
- .gitignore +2 -1
- Frontend/app/admin/issues/page.tsx +1 -1
- Frontend/app/layout.tsx +1 -1
- Frontend/app/page.tsx +1 -1
- Frontend/components/DashboardSidebar.tsx +1 -1
- Frontend/hooks/useCachedFetch.ts +1 -1
- Frontend/lib/api.ts +2 -2
.env.example
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
DATABASE_URL=
|
| 2 |
+
SUPABASE_URL=
|
| 3 |
+
SUPABASE_KEY=
|
| 4 |
+
SUPABASE_BUCKET=
|
| 5 |
+
SUPABASE_S3_ENDPOINT=
|
| 6 |
+
SUPABASE_S3_REGION=
|
| 7 |
+
SUPABASE_S3_ACCESS_KEY=
|
| 8 |
+
SUPABASE_S3_SECRET_KEY=
|
| 9 |
+
SUPABASE_JWT_SECRET=
|
| 10 |
+
GOOGLE_CLIENT_ID=
|
| 11 |
+
PROJECT_ID=
|
| 12 |
+
GOOGLE_CLIENT_SECRET=
|
| 13 |
+
SENDER_EMAIL=
|
| 14 |
+
ADMIN_EMAIL=
|
| 15 |
+
RESEND_API_KEY=
|
| 16 |
+
GEMINI_API_KEY=
|
| 17 |
+
EXPO_PUBLIC_API_BASE_URL=
|
| 18 |
+
EXPO_PUBLIC_SUPABASE_URL=
|
| 19 |
+
EXPO_PUBLIC_SUPABASE_ANON_KEY=
|
.gitignore
CHANGED
|
@@ -18,4 +18,5 @@ User/android/local.properties
|
|
| 18 |
User/android/app/release/
|
| 19 |
User/android/app/debug/
|
| 20 |
|
| 21 |
-
.vscode
|
|
|
|
|
|
| 18 |
User/android/app/release/
|
| 19 |
User/android/app/debug/
|
| 20 |
|
| 21 |
+
.vscode
|
| 22 |
+
node_modules/
|
Frontend/app/admin/issues/page.tsx
CHANGED
|
@@ -59,7 +59,7 @@ export default function IssuesPage() {
|
|
| 59 |
useEffect(() => {
|
| 60 |
const handler = setTimeout(() => {
|
| 61 |
setDebouncedSearch(search);
|
| 62 |
-
},
|
| 63 |
return () => clearTimeout(handler);
|
| 64 |
}, [search]);
|
| 65 |
|
|
|
|
| 59 |
useEffect(() => {
|
| 60 |
const handler = setTimeout(() => {
|
| 61 |
setDebouncedSearch(search);
|
| 62 |
+
}, 1500);
|
| 63 |
return () => clearTimeout(handler);
|
| 64 |
}, [search]);
|
| 65 |
|
Frontend/app/layout.tsx
CHANGED
|
@@ -17,7 +17,7 @@ const firaCode = Fira_Code({
|
|
| 17 |
});
|
| 18 |
|
| 19 |
export const metadata: Metadata = {
|
| 20 |
-
title: "
|
| 21 |
description: "Smart city issue tracking and resolution dashboard",
|
| 22 |
};
|
| 23 |
|
|
|
|
| 17 |
});
|
| 18 |
|
| 19 |
export const metadata: Metadata = {
|
| 20 |
+
title: "CityTracker - City Issue Reporter",
|
| 21 |
description: "Smart city issue tracking and resolution dashboard",
|
| 22 |
};
|
| 23 |
|
Frontend/app/page.tsx
CHANGED
|
@@ -187,7 +187,7 @@ export default function LandingPage() {
|
|
| 187 |
<div className="max-w-7xl mx-auto px-4 text-center">
|
| 188 |
<div className="flex justify-center items-center gap-2 mb-8 opacity-75 hover:opacity-100 transition-opacity">
|
| 189 |
<div className="w-6 h-6 bg-slate-900 rounded-md flex items-center justify-center text-xs font-bold font-mono text-white">U</div>
|
| 190 |
-
<span className="text-sm font-bold tracking-wide text-slate-900">
|
| 191 |
</div>
|
| 192 |
<p className="text-slate-500 text-sm">
|
| 193 |
© 2026 Dept. of Public Works. Secure. Efficient. Transparent.
|
|
|
|
| 187 |
<div className="max-w-7xl mx-auto px-4 text-center">
|
| 188 |
<div className="flex justify-center items-center gap-2 mb-8 opacity-75 hover:opacity-100 transition-opacity">
|
| 189 |
<div className="w-6 h-6 bg-slate-900 rounded-md flex items-center justify-center text-xs font-bold font-mono text-white">U</div>
|
| 190 |
+
<span className="text-sm font-bold tracking-wide text-slate-900">CityTracker SYSTEMS</span>
|
| 191 |
</div>
|
| 192 |
<p className="text-slate-500 text-sm">
|
| 193 |
© 2026 Dept. of Public Works. Secure. Efficient. Transparent.
|
Frontend/components/DashboardSidebar.tsx
CHANGED
|
@@ -62,7 +62,7 @@ export default function DashboardSidebar({
|
|
| 62 |
|
| 63 |
<aside
|
| 64 |
className={cn(
|
| 65 |
-
"fixed inset-y-0 left-0 z-50 bg-white/80 backdrop-blur-xl border-r border-slate-200/60 transition-all duration-300 ease-in-out shadow-urban-lg",
|
| 66 |
"lg:relative lg:translate-x-0 lg:shadow-none",
|
| 67 |
mobileOpen ? "translate-x-0" : "-translate-x-full",
|
| 68 |
desktopOpen ? "lg:w-72" : "lg:w-0 lg:overflow-hidden lg:border-r-0"
|
|
|
|
| 62 |
|
| 63 |
<aside
|
| 64 |
className={cn(
|
| 65 |
+
"fixed inset-y-0 left-0 z-50 bg-white/80 backdrop-blur-xl border-r border-slate-200/60 transition-all duration-300 ease-in-out shadow-urban-lg",
|
| 66 |
"lg:relative lg:translate-x-0 lg:shadow-none",
|
| 67 |
mobileOpen ? "translate-x-0" : "-translate-x-full",
|
| 68 |
desktopOpen ? "lg:w-72" : "lg:w-0 lg:overflow-hidden lg:border-r-0"
|
Frontend/hooks/useCachedFetch.ts
CHANGED
|
@@ -4,7 +4,7 @@ import { useState, useEffect, useCallback } from "react";
|
|
| 4 |
|
| 5 |
const cache = new Map<string, { data: any; timestamp: number }>();
|
| 6 |
const CACHE_TTL = 5 * 60 * 1000; // 5 minutes
|
| 7 |
-
const CACHE_KEY_PREFIX = "
|
| 8 |
|
| 9 |
// Helper to get full URL (duplicated logic, but safe for synchronous init)
|
| 10 |
const getFullUrl = (url: string) => {
|
|
|
|
| 4 |
|
| 5 |
const cache = new Map<string, { data: any; timestamp: number }>();
|
| 6 |
const CACHE_TTL = 5 * 60 * 1000; // 5 minutes
|
| 7 |
+
const CACHE_KEY_PREFIX = "citytracker_cache_";
|
| 8 |
|
| 9 |
// Helper to get full URL (duplicated logic, but safe for synchronous init)
|
| 10 |
const getFullUrl = (url: string) => {
|
Frontend/lib/api.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
| 1 |
"use client";
|
| 2 |
|
| 3 |
const API_URL = process.env.NEXT_PUBLIC_API_URL || "";
|
| 4 |
-
const REQUEST_TIMEOUT_MS =
|
| 5 |
-
const MAX_RETRIES =
|
| 6 |
|
| 7 |
class ApiError extends Error {
|
| 8 |
status: number;
|
|
|
|
| 1 |
"use client";
|
| 2 |
|
| 3 |
const API_URL = process.env.NEXT_PUBLIC_API_URL || "";
|
| 4 |
+
const REQUEST_TIMEOUT_MS = 35000;
|
| 5 |
+
const MAX_RETRIES = 3;
|
| 6 |
|
| 7 |
class ApiError extends Error {
|
| 8 |
status: number;
|