-
Notifications
You must be signed in to change notification settings - Fork 21
feature: Admin Page and Announcements #39
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
bec06a7
20430d0
f794915
b549c4e
d91f6b1
496ad0a
e4ee826
5bc0a76
f97243e
9f6a441
7770295
d97c308
36dff72
9e958be
bfc8f7f
a43799d
d2a0094
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,2 +1,16 @@ | ||
| #MOSQUE_API_ENDPOINT=https://api.mosque.tech/mosque-data/1o9dngtGJbfkFGZK_M7xdlo2PtRuQknGEQU3FxpiPVbg # Google sheets version | ||
| MOSQUE_API_ENDPOINT=http://localhost:3000/api/example-mosque | ||
|
|
||
| # Add your brand colors | ||
| THEME_COLOR_HIGHLIGHT=#29B0EA | ||
| THEME_COLOR_PRIMARY=#003750 | ||
| THEME_COLOR_PRIMARY_ALT=#086182 | ||
|
|
||
| # Admin Screen config | ||
| ADMIN_GOOGLE_SA_PRIVATE_KEY="-----BEGIN PRIVATE KEY-----\n******\n-----END PRIVATE KEY-----\n" | ||
| ADMIN_GOOGLE_SA_EMAIL=XXXX@XXXX-XXXX.iam.gserviceaccount.com | ||
| SPREADSHEET_ID=1o9dngtGJbfkFGZK_M7xdlo2PtRuQknGEQU3FxpiPVbg | ||
|
|
||
| AUTH_USERNAME=myuser | ||
| AUTH_PASSWORD=secret | ||
| AUTH_SECRET=some-long-random-string |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -18,6 +18,7 @@ | |
| # misc | ||
| .DS_Store | ||
| *.pem | ||
| /.idea | ||
|
|
||
| # debug | ||
| npm-debug.log* | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| "use client" | ||
|
|
||
| import { SessionProvider } from "next-auth/react" | ||
|
|
||
| /** | ||
| * So that we don't have to wrap the whole app in a session provider and keep | ||
| * @param children | ||
| * @constructor | ||
| */ | ||
| export default function SessionProviderWrapper({ children } : {children: React.ReactNode}) { | ||
| return <SessionProvider>{children}</SessionProvider> | ||
| } |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,57 @@ | ||||||||||||||||||||||||||||||
| import { getMetaData } from "@/services/MosqueDataService" | ||||||||||||||||||||||||||||||
| import { MosqueMetadataType } from "@/types/MosqueDataType" | ||||||||||||||||||||||||||||||
| import { Metadata } from "next" | ||||||||||||||||||||||||||||||
| import AdminPage from '@/components/Admin/AdminPage' | ||||||||||||||||||||||||||||||
| import SessionProviderWrapper from '@/app/admin/SessionProviderWrapper' | ||||||||||||||||||||||||||||||
| import { getSession, isAdminInterfaceEnabled } from '@/app/auth' | ||||||||||||||||||||||||||||||
| import { redirect } from 'next/navigation' | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| export const metadata = { | ||||||||||||||||||||||||||||||
| title: "Admin", | ||||||||||||||||||||||||||||||
| description: "Admin interface for MosqueScreen Project by MosqueOS", | ||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| export default async function AdminServerPage() { | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| return ( | ||||||||||||||||||||||||||||||
| <SessionProviderWrapper> | ||||||||||||||||||||||||||||||
| <AdminPageWrapper /> | ||||||||||||||||||||||||||||||
| </SessionProviderWrapper> | ||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| async function AdminPageWrapper() { | ||||||||||||||||||||||||||||||
| const isAdminEnabled = isAdminInterfaceEnabled() | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| if (!isAdminEnabled) { | ||||||||||||||||||||||||||||||
| return ( | ||||||||||||||||||||||||||||||
| <div className="min-h-screen flex items-center justify-center bg-mosqueBrand-primary px-6"> | ||||||||||||||||||||||||||||||
| <div className="text-center text-mosqueBrand-onPrimary"> | ||||||||||||||||||||||||||||||
| <div className="text-4xl mb-3">⚠️</div> | ||||||||||||||||||||||||||||||
| <h1 className="text-2xl font-semibold mb-2">Admin Interface Disabled</h1> | ||||||||||||||||||||||||||||||
| <p className="text-sm opacity-80 max-w-sm mx-auto"> | ||||||||||||||||||||||||||||||
| Please contact the system administrator. | ||||||||||||||||||||||||||||||
| </p> | ||||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| const session = await getSession() | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| if (!session) { | ||||||||||||||||||||||||||||||
| redirect("/api/auth/signin") | ||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| const mosqueMetadata: MosqueMetadataType = await getMetaData() | ||||||||||||||||||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add error handling for metadata fetch. The Wrap the fetch in a try-catch block: + let mosqueMetadata: MosqueMetadataType
+ try {
+ mosqueMetadata = await getMetaData()
+ } catch (error) {
+ return (
+ <div className="min-h-screen flex items-center justify-center bg-red-50 px-6">
+ <div className="text-center">
+ <h1 className="text-2xl font-semibold mb-2 text-red-700">Error Loading Data</h1>
+ <p className="text-sm text-red-600">Unable to fetch mosque metadata. Please try again later.</p>
+ </div>
+ </div>
+ )
+ }
- const mosqueMetadata: MosqueMetadataType = await getMetaData()
return (📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| return ( | ||||||||||||||||||||||||||||||
| <div className="bg-white min-w-full min-h-screen"> | ||||||||||||||||||||||||||||||
| <AdminPage metadata={mosqueMetadata} /> | ||||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| import { authOptions } from "@/app/auth" | ||
| import NextAuth from "next-auth" | ||
|
|
||
| const handler = NextAuth(authOptions) | ||
|
|
||
| export { handler as GET, handler as POST } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,20 @@ | ||
| import { sheetsGetAnnouncement, isSheetsClientReady } from '@/services/GoogleSheetsService'; | ||
| import { | ||
| getAnnouncement, | ||
| } from '@/services/MosqueDataService' | ||
|
|
||
| import { type NextRequest } from 'next/server' | ||
|
|
||
| export async function GET(request: NextRequest,) { | ||
| try { | ||
| let announcement = null; | ||
| // call the sheets API if we are connected, saves having to call external API | ||
| if (await isSheetsClientReady()) { | ||
| announcement = await sheetsGetAnnouncement() | ||
| } else { | ||
| announcement = await getAnnouncement() | ||
| } | ||
| return Response.json({ announcement }) | ||
| } catch (error: any) { | ||
| return Response.json({ error: error?.message ?? "Unknown error" }, { status: 400 }); } | ||
| } |
Uh oh!
There was an error while loading. Please reload this page.