Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
andrewtan2000 committed Sep 18, 2024
2 parents fcd392f + baf400a commit 1ba02d6
Show file tree
Hide file tree
Showing 9 changed files with 152 additions and 89 deletions.
11 changes: 11 additions & 0 deletions app/(main)/classes/details/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
'use client';

import { useSearchParams } from 'next/navigation';

const ClassDetails = () => {
const classId = useSearchParams().get('id');

return <div>{classId}</div>;
};

export default ClassDetails;
40 changes: 26 additions & 14 deletions app/(main)/classes/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ import { Dialog } from 'primereact/dialog';
import { InputText } from 'primereact/inputtext';
import React, { Fragment, useEffect, useRef, useState } from 'react';
import { UserService } from '@/service/UserService';
import AppMessages, {AppMessage} from '../../../components/AppMessages'
import AppMessages, { AppMessage } from '../../../components/AppMessages';
import Link from 'next/link';

import { useRouter } from 'next/navigation';

interface ClassMap {
descriptionName: string;
Expand All @@ -23,14 +23,14 @@ const Classes = () => {
const [addClass, setAddClass] = useState(false);
const [classId, setClassId] = useState<number>(0);
const [classes, setClasses] = useState<ClassResponse[]>([]);
const router = useRouter();

const appMsg = useRef<AppMessage>(null);

useEffect(() => {
fetchClasses();
}, []);


const useGenerateClassMap = (descriptionName: string, apiName: string, defaultValue = ''): ClassMap => {
const [value, setValue] = useState(defaultValue);
return { descriptionName, apiName, defaultValue, value, setValue };
Expand All @@ -54,11 +54,8 @@ const Classes = () => {
const selectedClass = classMapList.reduce((classFields, { apiName, value }) => ({ ...classFields, [apiName]: value }), {}) as Class;
console.log(selectedClass);

if (addClass) await UserService.addClass(selectedClass);

if (classId > 0) {
await UserService.updateClass(selectedClass);
}
if (classId > 0) await UserService.updateClass(selectedClass, classId);
else await UserService.addClass(selectedClass);

clearNewClass();
await fetchClasses();
Expand All @@ -69,8 +66,14 @@ const Classes = () => {
if (data !== null) {
setAddClass(true);
return;
}else{
appMsg.current?.showCustomWarning(<div>Please update your profile before adding a class. Click <Link href="/profile/edit">here</Link> to update profile.</div>);
} else {
appMsg.current?.showCustomWarning(
<div>
Please update your profile before adding a class. Click <Link href="/profile/edit">here</Link> to update profile.
</div>,
true,
10
);
}
});
//setAddClass(true)
Expand Down Expand Up @@ -100,13 +103,22 @@ const Classes = () => {
classMapList.forEach((classMap, index) => classMapList[index].setValue((selectedClass as any)[classMap.apiName]));
};

const EditButtonTemplate = (selectedClass: ClassResponse) => {
return <Button label="Edit" icon="pi pi-pencil" onClick={() => EditClass(selectedClass)} />;
const ViewDetails = (selectedClass: ClassResponse) => {
router.push(`/classes/details?id=${selectedClass.id}`);
};

const ActionColumnTemplate = (selectedClass: ClassResponse) => {
return (
<div className="flex align-items-center gap-2">
<Button label="Edit" icon="pi pi-pencil" onClick={() => EditClass(selectedClass)} />
<Button label="Details" icon="pi pi-book" onClick={() => ViewDetails(selectedClass)} />
</div>
);
};

return (
<div className="grid">
<AppMessages ref={appMsg} />
<AppMessages ref={appMsg} isAutoDismiss={true} />
<div className="col-12">
<div className="card">
<Fragment>
Expand All @@ -128,7 +140,7 @@ const Classes = () => {
/>
))}

<Column header="Action" body={EditButtonTemplate}></Column>
<Column header="Action" body={ActionColumnTemplate}></Column>
</DataTable>
</div>
</div>
Expand Down
91 changes: 56 additions & 35 deletions app/(main)/profile/edit/page.tsx
Original file line number Diff line number Diff line change
@@ -1,65 +1,86 @@
'use client'
'use client';

import { InputText} from 'primereact/inputtext';
import { InputText } from 'primereact/inputtext';
import { Button } from 'primereact/button';
import { useForm, Controller } from 'react-hook-form';
import { UserService } from '../../../../service/UserService';
import AppMessages, {AppMessage} from '../../../../components/AppMessages'
import AppMessages, { AppMessage } from '../../../../components/AppMessages';
import { useEffect, useRef } from 'react';

const EditProfile = () => {
const {control, formState: { errors, isDirty }, handleSubmit, reset} = useForm<Tutor>({ defaultValues: { firstName: '', lastName: '', educationLevel: '', tuitionCentre: '' } });
const {
control,
formState: { errors, isDirty },
handleSubmit,
reset
} = useForm<Tutor>({ defaultValues: { firstName: '', lastName: '', educationLevel: '', tuitionCentre: '' } });
const appMsg = useRef<AppMessage>(null);

useEffect(() => {
UserService.getTutorProfile().then((data) => {
if(data) reset(data);
})
},[]);
if (data) reset(data);
});
}, []);
const onSubmit = (data: Tutor) => {
UserService.updateTutorProfile(data).then((data) => {
console.log("Saved outout",data);
console.log('Saved outout', data);
reset(data);
appMsg.current?.showSuccess('Profile updated successfully');
});
}
};
return (
<div className="grid">
<AppMessages ref={appMsg} />
<h5 className='col-12'>Profile</h5>
<form onSubmit={handleSubmit(onSubmit)} className='col-12'>
<h5 className="col-12">Profile</h5>
<form onSubmit={handleSubmit(onSubmit)} className="col-12">
<div className="col-12">
<Controller
name="firstName"
control={control}
rules={{ required: 'First name is required', maxLength: { value: 100, message: 'Max length is 100' } }}
render={({ field, fieldState }) => <InputText id={field.name} {...field} autoFocus placeholder="First Name" size={50} />}
/>
</div>
<div className="col-12">
<span className="p-error">{errors.firstName?.message} </span>
</div>
<div className="col-12">
<Controller
name="lastName"
control={control}
rules={{ required: 'Last name is required', maxLength: { value: 100, message: 'Max length is 100' } }}
render={({ field, fieldState }) => <InputText id={field.name} {...field} placeholder="Last Name" size={50} />}
/>
</div>
<div className="col-12">
<span className="p-error">{errors.lastName?.message} </span>
</div>
<div className="col-12">
<Controller name="firstName" control={control} rules={{ required: 'First name is required', maxLength:{value:100, message: 'Max length is 100' }}}
render={({ field, fieldState }) =>
<InputText id={field.name} {...field} autoFocus placeholder="First Name" size={50} />}
/>
<Controller
name="tuitionCentre"
control={control}
rules={{ required: 'Tution Center is required', maxLength: { value: 100, message: 'Max length is 100' } }}
render={({ field, fieldState }) => <InputText id={field.name} {...field} placeholder="Tution Center" size={50} />}
/>
</div>
<div className="col-12"><span className='p-error'>{errors.firstName?.message} </span></div>
<div className="col-12">
<Controller name="lastName" control={control} rules={{ required: 'Last name is required', maxLength: {value:100, message: 'Max length is 100' }}}
render={({ field, fieldState }) =>
<InputText id={field.name} {...field} placeholder="Last Name" size={50}/>}
/>
<span className="p-error">{errors.tuitionCentre?.message} </span>
</div>
<div className="col-12"><span className='p-error'>{errors.lastName?.message} </span></div>
<div className="col-12">
<Controller name="tuitionCentre" control={control} rules={{required: 'Tution Center is required', maxLength: {value:100, message: 'Max length is 100'} }}
render={({ field, fieldState }) =>
<InputText id={field.name} {...field} placeholder="Tution Center" size={50} />}
/>
<Controller
name="educationLevel"
control={control}
rules={{ required: 'Education Level is required', maxLength: { value: 20, message: 'Max length is 20' } }}
render={({ field, fieldState }) => <InputText id={field.name} {...field} placeholder="Education Level" size={20} />}
/>
</div>
<div className="col-12"><span className='p-error'>{errors.tuitionCentre?.message} </span></div>
<div className="col-12">
<Controller name="educationLevel" control={control} rules={{ required: 'Education Level is required', maxLength: {value:20, message: 'Max length is 20'} }}
render={({ field, fieldState }) =>
<InputText id={field.name} {...field} placeholder="Education Level" size={20} />}
/>
<span className="p-error">{errors.educationLevel?.message} </span>
</div>
<div className="col-12"><span className='p-error'>{errors.educationLevel?.message} </span></div>
<Button type="submit" label="Save" className="mt-2" disabled={!isDirty} />
</form>
</form>
</div>
)
}
);
};

export default EditProfile;
export default EditProfile;
8 changes: 4 additions & 4 deletions app/(main)/questions/create/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import { TreeSelect, TreeSelectSelectionKeysType } from 'primereact/treeselect';
import { TreeNode } from 'primereact/treenode';
import { useRouter } from 'next/navigation';
import { ProgressSpinner } from 'primereact/progressspinner';
import AppMessages, {AppMessage} from '../../../../components/AppMessages'
import AppMessages, { AppMessage } from '../../../../components/AppMessages';

const EditQuestion = () => {
const router = useRouter();
Expand Down Expand Up @@ -198,12 +198,12 @@ const EditQuestion = () => {
//TODO: call generate question API
console.log('Invoking handleOnGenerateQuestion');
var updateQuestion = (data: Genai.MCQ) => {
var index =1
if(data.options && data.options.map ){
var index = 1;
if (data.options && data.options.map) {
data.options.map((item: Genai.Option) => {
item.no = index;
index++;
})
});
}
setStem(data.stem);
setAddedOptions(data.options);
Expand Down
70 changes: 50 additions & 20 deletions components/AppMessages.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,43 +3,73 @@ import { forwardRef, ReactNode, useImperativeHandle, useRef } from 'react';


//showInfomation(messageContent)
export type AppMessage = {
showSuccess: (messageContent: string) => void,
showInformation: (messageContent: string) => void,
showError: (messageContent: string) => void,
showWarning: (messageContent: string) => void,

showCustomSuccess: (messageContent: ReactNode) => void,
showCustomInformation: (messageContent: ReactNode) => void,
showCustomWarning: (messageContent: ReactNode) => void
export type AppMessage = {
showSuccess: (messageContent: string, isAutoDismiss?: boolean, dismissTimerInSeconds?: number) => void,
showInformation: (messageContent: string, isAutoDismiss?: boolean, dismissTimerInSeconds?: number) => void,
showError: (messageContent: string, isAutoDismiss?: boolean, dismissTimerInSeconds?: number) => void,
showWarning: (messageContent: string, isAutoDismiss?: boolean, dismissTimerInSeconds?: number) => void,

showCustomSuccess: (messageContent: ReactNode, isAutoDismiss?: boolean, dismissTimerInSeconds?: number) => void,
showCustomInformation: (messageContent: ReactNode, isAutoDismiss?: boolean, dismissTimerInSeconds?: number) => void,
showCustomWarning: (messageContent: ReactNode, isAutoDismiss?: boolean, dismissTimerInSeconds?: number) => void
}
type Props = {};

type Props = {
isAutoDismiss?: boolean | undefined;
dismissTimerInSeconds?: number | undefined;
};

const AppMessages = forwardRef<AppMessage, Props>((props, ref) =>{
const msgs = useRef<Messages>(null);

useImperativeHandle(ref, () => ({
showSuccess(messageContent: string){
useImperativeHandle(ref, () => ({
showSuccess(messageContent: string, isAutoDismiss?: boolean, dismissTimerInSeconds?: number){
msgs.current?.show([{ severity: 'success', summary: '', detail: messageContent, closable: true, sticky: true }]);
this.clearMessagesIfAutoDismiss(isAutoDismiss, dismissTimerInSeconds);
},
showCustomSuccess(messageContent: ReactNode){
showCustomSuccess(messageContent: ReactNode, isAutoDismiss?: boolean, dismissTimerInSeconds?: number){
msgs.current?.show([{ severity: 'success', summary: '', content: messageContent, closable: true, sticky: true }]);
this.clearMessagesIfAutoDismiss(isAutoDismiss, dismissTimerInSeconds);
},
showInformation(messageContent: string){
showInformation(messageContent: string, isAutoDismiss?: boolean, dismissTimerInSeconds?: number){
msgs.current?.show([{ severity: 'info', summary: '', icon: 'pi pi-send', detail: messageContent, closable: true, sticky: true }]);
this.clearMessagesIfAutoDismiss(isAutoDismiss, dismissTimerInSeconds);
},
showCustomInformation(messageContent: ReactNode){
showCustomInformation(messageContent: ReactNode, isAutoDismiss?: boolean, dismissTimerInSeconds?: number){
msgs.current?.show([{ severity: 'info', summary: '', icon: 'pi pi-send', content: messageContent, closable: true, sticky: true }]);
this.clearMessagesIfAutoDismiss(isAutoDismiss, dismissTimerInSeconds);
},

showError(messageContent: string){
showError(messageContent: string, isAutoDismiss?: boolean, dismissTimerInSeconds?: number){
msgs.current?.show([{ severity: 'error', summary: '', icon: 'pi pi-error', detail: messageContent, closable: true, sticky: true }]);
this.clearMessagesIfAutoDismiss(isAutoDismiss, dismissTimerInSeconds);
},
showWarning(messageContent: string, life: number = 10000){
msgs.current?.show([{ severity: 'warn', summary: '', icon: 'pi pi-warning', detail: messageContent, closable: true, sticky: true, life: life }]);
showWarning(messageContent: string, isAutoDismiss?: boolean, dismissTimerInSeconds?: number){
msgs.current?.show([{ severity: 'warn', summary: '', icon: 'pi pi-warning', detail: messageContent, closable: true, sticky: true }]);
this.clearMessagesIfAutoDismiss(isAutoDismiss, dismissTimerInSeconds);
},
showCustomWarning(messageContent: ReactNode){
showCustomWarning(messageContent: ReactNode, isAutoDismiss?: boolean, dismissTimerInSeconds?: number){
msgs.current?.show([{ severity: 'warn', summary: '', icon: 'pi pi-warning', content: messageContent, closable: true, sticky: true }]);
this.clearMessagesIfAutoDismiss(isAutoDismiss, dismissTimerInSeconds);
},
getDismissTimer(isAutoDismiss?: boolean | undefined, dismissTimerInSeconds?: number | undefined) {
let displayTimer = undefined;

// default dismiss timer is 3 sec
if (isAutoDismiss) {
if (dismissTimerInSeconds && dismissTimerInSeconds > 0) {
displayTimer = dismissTimerInSeconds * 1000;
} else {
displayTimer = 3000;
}
}

return displayTimer;
},
clearMessagesIfAutoDismiss(isAutoDismiss?: boolean, dismissTimerInSeconds?: number) {
const displayTimer = this.getDismissTimer(isAutoDismiss, dismissTimerInSeconds);
displayTimer && setTimeout(() => msgs.current?.clear(), displayTimer);
}
}));
return (
<div className='col-12'>
Expand All @@ -49,4 +79,4 @@ const AppMessages = forwardRef<AppMessage, Props>((props, ref) =>{
});
AppMessages.displayName = 'AppMessages';

export default AppMessages;
export default AppMessages;
2 changes: 1 addition & 1 deletion layout/AppTopbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ const AppTopbar = forwardRef<AppTopbarRef>((props, ref) => {

const overlayMenuItems = [
{
label: 'View Profile',
label: 'View Profile',
command: () => {
router.push('/profile/edit');
}
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"version": "1.0.0",
"private": true,
"scripts": {
"dev": "next lint && next dev",
"dev": "npm run format && next lint && next dev",
"build": "next build",
"start": "npx serve@latest dist",
"format": "prettier --write \"{app,demo,layout,types}/**/*.{js,ts,tsx,d.ts}\"",
Expand Down
16 changes: 3 additions & 13 deletions service/UserService.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,21 +10,11 @@ import api from "./ConnectionService"

export const UserService = {
async addClass(data: Class) {
const res = await api<UserServiceResponseDto>({ url: classUrl, body: JSON.stringify(data), method: "POST" });
//console.log('res', res);
// const res = await fetch(classUrl, {
// method: 'POST',
// headers: {
// 'Content-Type': 'application/json',
// },
// credentials: 'include',
// body: JSON.stringify(data)
// });
return res;
return await api<UserServiceResponseDto>({ url: classUrl, body: JSON.stringify(data), method: "POST" });
},

async updateClass(data: Class) {
return (await api<UserServiceResponse<ClassResponse[]>>({ url: classUrl, body: JSON.stringify(data), method: "PUT" })).payload;
async updateClass(data: Class, classId: number) {
return (await api<UserServiceResponse<ClassResponse[]>>({ url: classUrl, body: JSON.stringify({...data, id: classId}), method: "PUT" })).payload;
},

async getClasses() {
Expand Down
Loading

0 comments on commit 1ba02d6

Please sign in to comment.