Skip to content
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

Added Admin page & some UI Changes #819

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,7 @@ BOT_TOKEN = "123"
GUILD_ID = "123"
LOCAL_CMS_PROVIDER = true
CACHE_EXPIRE_S = 10

ADMINS = "Random,example@gmail.com"
ADMINS = "Random,example@gmail.com,test@gmail.com"
NEXT_PUBLIC_DISABLE_FEATURES = "featurea,featureb,featurec"
REDIS_URL=

Expand Down
209 changes: 209 additions & 0 deletions src/app/admin/add-course/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,209 @@
'use client';

import { Button } from '@/components/ui/button';
import {
Card,
CardContent,
CardDescription,
CardHeader,
CardTitle,
} from '@/components/ui/card';
import {
Form,
FormControl,
FormField,
FormItem,
FormLabel,
FormMessage,
} from '@/components/ui/form';
import { Input } from '@/components/ui/input';
import { Textarea } from '@/components/ui/textarea';
import axios from 'axios';
import { useRouter } from 'next/navigation';
import { useState } from 'react';
import { useForm } from 'react-hook-form';
import { toast } from 'sonner';
import { z } from 'zod';
import { zodResolver } from '@hookform/resolvers/zod';

const courseSchema = z.object({
title: z.string().min(5, {
message: 'Title must be at least 5 characters long.',
}),
imageUrl: z.string().url({
message: 'Invalid URL format for imageUrl.',
}),
description: z.string().min(8, {
message: 'Description must be at least of 8 characters long.',
}),
slug: z.string(),
id: z.string(),
adminSecret: z.string(),
appxCourseId: z.string(),
discordRoleId: z.string(),
});

export default function Courses() {
const [isLoading, setIsLoading] = useState<boolean>(false);
const router = useRouter();

const form = useForm<z.infer<typeof courseSchema>>({
resolver: zodResolver(courseSchema),
defaultValues: {
title: '',
imageUrl: '',
description: '',
slug: '',
id: '',
adminSecret: '',
appxCourseId: '',
discordRoleId: '',
},
});

const onSubmit = async (data: z.infer<typeof courseSchema>) => {
setIsLoading(true);
try {
await axios.post('/api/admin/course', data);
toast('course succesfully created');
router.push('/');
} catch (error: any) {
console.log(error);
toast(error.message);
} finally {
setIsLoading(false);
}
};

return (
<Card className="mx-auto w-full max-w-6xl overflow-y-auto lg:mt-10">
<CardHeader>
<CardTitle>Create a new course</CardTitle>
<CardDescription>Fill in the course details below</CardDescription>
</CardHeader>
<CardContent className="grid gap-4 p-4 pt-0">
<Form {...form}>
<form
onSubmit={form.handleSubmit(onSubmit)}
className="grid gap-4 lg:grid-cols-2"
>
<FormField
control={form.control}
name="title"
render={({ field }: { field: any }) => (
<FormItem>
<FormLabel>Title</FormLabel>
<FormControl>
<Input placeholder="Enter the Course name" {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="imageUrl"
render={({ field }: { field: any }) => (
<FormItem>
<FormLabel>Image url</FormLabel>
<FormControl>
<Input placeholder="Enter the url of Image" {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="description"
render={({ field }: { field: any }) => (
<FormItem>
<FormLabel>Description</FormLabel>
<FormControl>
<Textarea
placeholder="Enter the Description of course"
{...field}
/>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="slug"
render={({ field }: { field: any }) => (
<FormItem>
<FormLabel>Slug</FormLabel>
<FormControl>
<Input placeholder="Enter the Course slug" {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="id"
render={({ field }: { field: any }) => (
<FormItem>
<FormLabel>Id</FormLabel>
<FormControl>
<Input placeholder="Enter the Course ID" {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="adminSecret"
render={({ field }: { field: any }) => (
<FormItem>
<FormLabel>Admin Secret</FormLabel>
<FormControl>
<Input placeholder="Enter the Admin Secret" {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="appxCourseId"
render={({ field }: { field: any }) => (
<FormItem>
<FormLabel>app x course id</FormLabel>
<FormControl>
<Input placeholder="Enter the appx course ID" {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="discordRoleId"
render={({ field }: { field: any }) => (
<FormItem>
<FormLabel>Discord Role Id</FormLabel>
<FormControl>
<Input placeholder="Enter the Discord Role Id" {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<div className="lg:col-span-2">
{isLoading ? (
<Button>Loading...</Button>
) : (
<Button type="submit">Create</Button>
)}
</div>
</form>
</Form>
</CardContent>
</Card>
);
}
2 changes: 1 addition & 1 deletion src/app/admin/content/[...courseId]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ export default async function UpdateCourseContent({
return (
<div className="mx-auto max-w-screen-xl justify-between p-4 text-black dark:text-white">
{course?.title}
<div className="font-bold md:text-5xl lg:text-6xl">Content</div>
<div className="my-2 font-bold md:text-5xl lg:text-6xl">Content</div>
<AddContent
courseId={parseInt(courseId, 10)}
parentContentId={parseFloat(rest[rest.length - 1])}
Expand Down
72 changes: 1 addition & 71 deletions src/app/admin/page.tsx
Original file line number Diff line number Diff line change
@@ -1,82 +1,12 @@
'use client';

import { Button } from '@/components/ui/button';
import {
Card,
CardContent,
CardDescription,
CardHeader,
CardTitle,
} from '@/components/ui/card';
import {
Form,
FormControl,
FormField,
FormItem,
FormLabel,
FormMessage,
} from '@/components/ui/form';
import { Input } from '@/components/ui/input';
import { Textarea } from '@/components/ui/textarea';
import axios from 'axios';
import { useRouter } from 'next/navigation';
import { useState } from 'react';
import { useForm } from 'react-hook-form';
import { toast } from 'sonner';
import { z } from 'zod';
import { zodResolver } from '@hookform/resolvers/zod';

const courseSchema = z.object({
title: z.string().min(5, {
message: 'Title must be at least 5 characters long.',
}),
imageUrl: z.string().url({
message: 'Invalid URL format for imageUrl.',
}),
description: z.string().min(8, {
message: 'Description must be at least of 8 characters long.',
}),
slug: z.string(),
id: z.string(),
adminSecret: z.string(),
appxCourseId: z.string(),
discordRoleId: z.string(),
});

export default function Courses() {
const [isLoading, setIsLoading] = useState<boolean>(false);
export default function AdminPage() {
const router = useRouter();
const [email, setEmail] = useState('');
const [adminPassword, setAdminPassword] = useState('');

const form = useForm<z.infer<typeof courseSchema>>({
resolver: zodResolver(courseSchema),
defaultValues: {
title: '',
imageUrl: '',
description: '',
slug: '',
id: '',
adminSecret: '',
appxCourseId: '',
discordRoleId: '',
},
});

const onSubmit = async (data: z.infer<typeof courseSchema>) => {
setIsLoading(true);
try {
await axios.post('/api/admin/course', data);
toast('course succesfully created');
router.push('/');
} catch (error: any) {
console.log(error);
toast(error.message);
} finally {
setIsLoading(false);
}
};

return (
<div>
<Card className="mx-auto w-full max-w-6xl overflow-y-auto lg:mt-10">
Expand Down
3 changes: 1 addition & 2 deletions src/components/Appbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ export const Appbar = () => {
)}
<div className="mx-auto flex w-full items-center justify-between md:max-w-screen-2xl">
<Logo onFooter={false} />

{session?.user ? (
!isLoading && (
<>
Expand All @@ -46,7 +45,7 @@ export const Appbar = () => {
<div className="flex items-center space-x-2">
{/* Search Bar for smaller devices */}
<MobileScreenSearch />
<ProfileDropdown />
<ProfileDropdown Isession={session} />
</div>
</>
)
Expand Down
4 changes: 3 additions & 1 deletion src/components/admin/AddContent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import { useEffect, useState } from 'react';
import { AddNotionMetadata } from './AddNotionMetadata';
import { Input } from '../ui/input';
import { toast } from 'sonner';

export const AddContent = ({
courseId,
Expand Down Expand Up @@ -80,8 +81,9 @@ export const AddContent = ({
'Content-Type': 'application/json',
},
});
toast(`${type} successfully added!`);
}}
className="rounded bg-blue-500 px-4 py-2 font-bold text-white hover:bg-blue-700"
className="my-6 rounded bg-blue-500 px-4 py-2 font-bold text-white hover:bg-blue-700"
>
Submit
</button>
Expand Down
34 changes: 21 additions & 13 deletions src/components/admin/CourseContent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,20 +17,28 @@ export const AdminCourseContent = ({

return (
<div>
Course content
<h1 className="text-2xl font-bold">Course content</h1>
<div className="mx-auto grid max-w-screen-xl cursor-pointer grid-cols-1 justify-between gap-5 p-4 md:grid-cols-3">
{courseContent.map(
(content: { image: string; id: number; title: string }) => (
<ContentCard
type={'folder'}
title={content.title}
image={content.image || ''}
onClick={() => {
router.push(`/admin/content/${courseId}/${content.id}`);
}}
key={content.id}
/>
),
{courseContent && courseContent.length > 0 ? (
courseContent.map(
(content: { image: string; id: number; title: string }) => (
<ContentCard
type={'folder'}
title={content.title}
image={content.image || ''}
onClick={() => {
router.push(`/admin/content/${courseId}/${content.id}`);
}}
key={content.id}
/>
),
)
) : (
<div className="flex h-48 items-center justify-center rounded-lg bg-gray-100 shadow-md dark:bg-gray-800">
<p className="text-lg font-semibold text-gray-500 dark:text-gray-400">
No Content Added Here Yet
</p>
</div>
)}
</div>
</div>
Expand Down
Loading
Loading