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

Feat/id numbers #150

Merged
merged 9 commits into from
Dec 19, 2024
Merged
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
-- DropForeignKey
ALTER TABLE "Application" DROP CONSTRAINT "Application_applicationPeriodId_fkey";

-- AddForeignKey
ALTER TABLE "Application" ADD CONSTRAINT "Application_applicationPeriodId_fkey" FOREIGN KEY ("applicationPeriodId") REFERENCES "ApplicationPeriod"("id") ON DELETE CASCADE ON UPDATE CASCADE;
2 changes: 1 addition & 1 deletion apps/backend/prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ model Application {
id Int @id @default(autoincrement())
user User @relation(fields: [userId], references: [authSchId])
userId String
applicationPeriod ApplicationPeriod @relation(fields: [applicationPeriodId], references: [id])
applicationPeriod ApplicationPeriod @relation(fields: [applicationPeriodId], references: [id], onDelete: Cascade)
applicationPeriodId Int
status ApplicationStatus @default(SUBMITTED)
createdAt DateTime @default(now())
Expand Down
8 changes: 4 additions & 4 deletions apps/backend/src/user/dto/update-user-admin.dto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,11 @@ export class UpdateUserAdminDto {
@IsOptional()
publicDesc: string;

@IsEnum(Role)
@IsOptional()
role: Role;

@IsString()
@IsOptional()
idNumber: string;

@IsEnum(Role)
@IsOptional()
role: Role;
}
4 changes: 4 additions & 0 deletions apps/backend/src/user/dto/update-user.dto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,8 @@ export class UpdateUserDto {
@IsString()
@IsOptional()
publicDesc: string;

@IsString()
@IsOptional()
idNumber: string;
}
18 changes: 14 additions & 4 deletions apps/frontend/src/app/application-form/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,26 @@ import { redirect } from 'next/navigation';

import Th1 from '@/components/typography/typography';
import ApplicationForm from '@/components/ui/ApplicationForm';
import LoadingCard from '@/components/ui/LoadingCard';
import useCurrentApplication from '@/hooks/useCurrentApplication';
import { useCurrentPeriod } from '@/hooks/usePeriod';

export default function Page() {
const { data: currentPeriod } = useCurrentPeriod();
const application = useCurrentApplication();
const { data: currentPeriod, isLoading: isPeriodLoading } = useCurrentPeriod();
const { data: application, isLoading: isApplicationLoading } = useCurrentApplication();

if (!currentPeriod || application.data !== undefined) {
return redirect('/unauthorized');
if (isPeriodLoading || isApplicationLoading) {
return <LoadingCard />;
}

if (!currentPeriod) {
return redirect('/');
}

if (application !== undefined) {
return redirect('/profile');
}

return (
<>
<Th1>
Expand Down
29 changes: 18 additions & 11 deletions apps/frontend/src/components/ui/ApplicationForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import { zodResolver } from '@hookform/resolvers/zod';
import Link from 'next/link';
import { useRouter } from 'next/navigation';
import { redirect, useRouter } from 'next/navigation';
import { useEffect, useRef } from 'react';
import { useForm } from 'react-hook-form';
import { mutate } from 'swr';
Expand All @@ -20,9 +20,10 @@ import useProfile from '@/hooks/useProfile';
import { useToast } from '@/lib/use-toast';
import { ApplicationPeriodEntity } from '@/types/application-period-entity';
import { ApplicationFormSchema } from '@/zod-form-schemas/ApplicationFormSchema';
import LoadingCard from './LoadingCard';

export default function ApplicationForm({ currentPeriod }: { currentPeriod: ApplicationPeriodEntity }) {
const user = useProfile();
const { data: userData, isLoading } = useProfile();
const { toast } = useToast();
const effectCalledRef = useRef(false);
const router = useRouter();
Expand All @@ -39,15 +40,15 @@ export default function ApplicationForm({ currentPeriod }: { currentPeriod: Appl

const { reset } = form;
useEffect(() => {
if (user.data && !effectCalledRef.current) {
if (userData && !effectCalledRef.current) {
reset({
nickName: user.data.nickName || '',
email: user.data.email || '',
isSchResident: user.data.isSchResident || false,
roomNumber: user.data.roomNumber || 0,
nickName: userData.nickName || '',
email: userData.email || '',
isSchResident: userData.isSchResident || false,
roomNumber: userData.roomNumber || 0,
});
}
}, [user.data, reset]);
}, [userData, reset]);

// eslint-disable-next-line @typescript-eslint/no-unused-vars
async function onSubmit({ terms, ...values }: z.infer<typeof ApplicationFormSchema>) {
Expand Down Expand Up @@ -87,7 +88,13 @@ export default function ApplicationForm({ currentPeriod }: { currentPeriod: Appl
}
}

if (!user.data) return null;
if (isLoading) {
return <LoadingCard />;
}

if (!userData) {
return redirect('/');
}

return (
<Form {...form}>
Expand All @@ -100,12 +107,12 @@ export default function ApplicationForm({ currentPeriod }: { currentPeriod: Appl
<CardContent className='md:grid-cols-4 grid gap-4'>
<FormItem>
<FormLabel>Név</FormLabel>
<Input disabled value={user.data.fullName} />
<Input disabled value={userData.fullName} />
</FormItem>
<FormItem>
<FormLabel>NEPTUN</FormLabel>
<FormControl>
<Input disabled value={user.data.neptun} />
<Input disabled value={userData.neptun} />
</FormControl>
<FormMessage />
</FormItem>
Expand Down
2 changes: 1 addition & 1 deletion apps/frontend/src/components/ui/BodyMemberTile.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export function BodyMemberTile({ userEntity, simple }: Props) {
className='h-36 rounded'
onError={({ currentTarget }) => {
currentTarget.onerror = null; // prevents looping
currentTarget.src = 'default_pfp.jpg';
currentTarget.src = '/default_pfp.jpg';
}}
/>
<div className='flex flex-col gap-4 ml-4 mt-2'>
Expand Down
1 change: 1 addition & 0 deletions apps/frontend/src/components/ui/MemberProfileData.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ export default function MemberProfileData({
canHelpNoobs: boolean;
nickName: string;
email: string;
idNumber: string;
publicDesc?: string | undefined;
isSchResident?: boolean | undefined;
roomNumber?: number | null | undefined;
Expand Down
62 changes: 50 additions & 12 deletions apps/frontend/src/components/ui/ProfileForm.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
'use client';

import { zodResolver } from '@hookform/resolvers/zod';
import React, { useEffect } from 'react';
import { useEffect, useState } from 'react';
import { useForm } from 'react-hook-form';
import { LuBuilding2, LuFileEdit } from 'react-icons/lu';
import { LuBuilding2, LuFileUp } from 'react-icons/lu';
import { z } from 'zod';

import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
Expand All @@ -14,14 +14,20 @@ import { Switch } from '@/components/ui/switch';
import UserProfileBanner from '@/components/ui/UserProfileBanner';
import useProfile from '@/hooks/useProfile';
import { useToast } from '@/lib/use-toast';
import { ApplicationEntityWithPeriod, ApplicationStatus } from '@/types/application-entity';
import { ProfileFormSchema } from '@/zod-form-schemas/ProfileFormSchema';

import api from '../network/apiSetup';
import MemberProfileData from './MemberProfileData';

// Custom hook or API call to fetch user's applications
async function fetchUserApplications() {
// Replace with an actual API call
return await api.get<ApplicationEntityWithPeriod[]>('/users/me/applications');
}

export default function ProfileForm() {
const { toast } = useToast();

const form = useForm<z.infer<typeof ProfileFormSchema>>({
resolver: zodResolver(ProfileFormSchema),
defaultValues: {
Expand All @@ -31,22 +37,40 @@ export default function ProfileForm() {
roomNumber: 0,
canHelpNoobs: false,
publicDesc: '',
idNumber: '',
},
});

const { data: user, error, isLoading, mutate } = useProfile();
const [isIdFieldDisabled, setIsIdFieldDisabled] = useState(false);
const [editingIsOn, setEditingIsOn] = useState(false);

async function onSubmit({ roomNumber, ...values }: z.infer<typeof ProfileFormSchema>) {
useEffect(() => {
async function checkApplicationStatus() {
try {
const applications = await fetchUserApplications();
const hasRestrictedStatus = applications.data.some(
(app: ApplicationEntityWithPeriod) =>
app.status === ApplicationStatus.DISTRIBUTED || app.status === ApplicationStatus.WAITING_FOR_OPS
);
setIsIdFieldDisabled(hasRestrictedStatus);
} catch (error) {
console.error('Failed to fetch applications:', error);
}
}

checkApplicationStatus();
}, []);

const onSubmit = async ({ roomNumber, ...values }: z.infer<typeof ProfileFormSchema>) => {
setEditingIsOn(false);
try {
const response = await api.patch(
'/users/me',
JSON.stringify(values.isSchResident ? { ...values, roomNumber } : values)
);
if (response.status === 200) {
toast({
title: 'Sikeres módosítás!',
});
toast({ title: 'Sikeres módosítás!' });
mutate();
} else {
toast({
Expand All @@ -61,7 +85,7 @@ export default function ProfileForm() {
variant: 'destructive',
});
}
}
};

const { reset } = form;
useEffect(() => {
Expand All @@ -73,14 +97,13 @@ export default function ProfileForm() {
roomNumber: user.roomNumber || 0,
canHelpNoobs: user.canHelpNoobs || false,
publicDesc: user.publicDesc || '',
idNumber: user.idNumber || '',
});
}
}, [user, reset]);

const [editingIsOn, setEditingIsOn] = React.useState(false);
if (isLoading) return <p>Loading...</p>;
if (error) return <p>Error loading profile.</p>;

if (!user) return null;

return (
Expand All @@ -96,7 +119,7 @@ export default function ProfileForm() {
<CardHeader className='flex items-start flex-row justify-between'>
<div>
<CardTitle>
<LuFileEdit />
<LuFileUp />
Személyes adatok
</CardTitle>
</div>
Expand Down Expand Up @@ -128,6 +151,19 @@ export default function ProfileForm() {
</FormItem>
)}
/>
<FormField
control={form.control}
name='idNumber'
render={({ field }) => (
<FormItem>
<FormLabel>Személyi szám</FormLabel>
<FormControl>
<Input {...field} disabled={isIdFieldDisabled || !editingIsOn} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
</CardContent>
</Card>
<Card>
Expand Down Expand Up @@ -166,7 +202,9 @@ export default function ProfileForm() {
name='roomNumber'
render={({ field }) => (
<FormItem
className={`flex flex-col md:flex-row gap-1 md:items-center justify-between rounded-lg border p-4 shadow-sm ${form.watch('isSchResident') ? 'opacity-100' : 'opacity-0'}`}
className={`flex flex-col md:flex-row gap-1 md:items-center justify-between rounded-lg border p-4 shadow-sm ${
form.watch('isSchResident') ? 'opacity-100' : 'opacity-0'
}`}
>
<div className='space-y-0.5'>
<FormLabel>Szoba szám</FormLabel>
Expand Down
2 changes: 1 addition & 1 deletion apps/frontend/src/components/ui/StatusBadge.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ export default function StatusBadge({ status, hover }: Readonly<{ status: Applic
}, [convertedStatus]);

return (
<Badge variant={color} hover>
<Badge variant={color} hover={hover === undefined ? true : hover}>
<div className='py-1 pr-2'>{icon}</div>
{ApplicationStatus[convertedStatus]}
</Badge>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ export default function SubmittedApplicationBannerCard({ user, application, curr
<CardHeader className='md:flex-row max-md:flex-col justify-between gap-2 md:items-start p-2'>
{!currentPeriod && <CardTitle className='m-4'>Utolsó jelentkezésed</CardTitle>}
{currentPeriod && (
<div className='flex flex-col gap-4 justify-start '>
<CardTitle className='m-4'> Leadott jelentkezés </CardTitle>
<div className='flex flex-col gap-4 justify-start m-4'>
<CardTitle> Leadott jelentkezés </CardTitle>
<p>
A most zajló, <span className='font-bold'>{currentPeriod.name}</span> időszakra már sikeresen
jelentkeztél!
Expand Down
4 changes: 3 additions & 1 deletion apps/frontend/src/components/ui/Ticket.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,11 @@ export default function Ticket({ user }: { user: UserEntity }) {
<TooltipTrigger asChild>
<Card className='flex gap-2 p-2 bg-red-200 relative rounded-sm'>
<Image
src={`${process.env.NEXT_PUBLIC_API_URL}/users/${user.authSchId}/profile-picture?cb=${Date.now()} `}
src={`${process.env.NEXT_PUBLIC_API_URL}/users/${user.authSchId}/profile-picture?cb=${Date.now()}`}
className='min-w-[65px] w-[65px] h-[90px] overflow-hidden rounded-sm object-cover'
alt='kep'
width={65}
height={90}
/>
<div>
<CardTitle className='max-w-40 text-lg overflow-hidden whitespace-nowrap'>{user.fullName}</CardTitle>
Expand Down
2 changes: 1 addition & 1 deletion apps/frontend/src/components/ui/UserProfileBanner.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ export default function UserProfileBanner(props: {
)}
{props.editingIsOn && (
<>
<Button type='submit'>
<Button type='submit' onClick={props.onSubmit}>
<FiSave />
Mentés
</Button>
Expand Down
2 changes: 1 addition & 1 deletion apps/frontend/src/components/ui/badge.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import * as React from 'react';
import { cn } from '@/lib/utils';

const badgeVariants = cva(
'inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2',
'inline-flex items-center rounded-full border px-2.5 py-0.5 text-sm font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2',
{
variants: {
variant: {
Expand Down
1 change: 1 addition & 0 deletions apps/frontend/src/zod-form-schemas/ProfileFormSchema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export const ProfileFormSchema = z
invalid_type_error: 'String, tesó!',
}),
email: z.string().email(),
idNumber: z.string(),
isSchResident: z.boolean().optional(),
roomNumber: z
.union([
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,5 +31,5 @@
"workspaces": [
"apps/*"
],
"packageManager": "yarn@4.5.1"
"packageManager": "yarn@4.5.3"
}
Loading