Skip to content

Commit

Permalink
add new design changes
Browse files Browse the repository at this point in the history
  • Loading branch information
Markusplay committed Jan 12, 2025
1 parent 9523694 commit 5e1ac5f
Show file tree
Hide file tree
Showing 21 changed files with 2,485 additions and 4,742 deletions.
6,570 changes: 2,050 additions & 4,520 deletions package-lock.json

Large diffs are not rendered by default.

5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
"dependencies": {
"@hookform/resolvers": "^3.9.1",
"@radix-ui/react-accordion": "^1.2.1",
"@radix-ui/react-alert-dialog": "^1.1.4",
"@radix-ui/react-aspect-ratio": "^1.1.0",
"@radix-ui/react-avatar": "^1.1.1",
"@radix-ui/react-checkbox": "^1.1.2",
Expand All @@ -22,10 +23,10 @@
"@radix-ui/react-scroll-area": "^1.2.1",
"@radix-ui/react-select": "^2.1.4",
"@radix-ui/react-separator": "^1.1.0",
"@radix-ui/react-slot": "^1.1.0",
"@radix-ui/react-slot": "^1.1.1",
"@radix-ui/react-switch": "^1.1.2",
"@radix-ui/react-toast": "^1.2.2",
"@radix-ui/react-tooltip": "^1.1.4",
"@radix-ui/react-tooltip": "^1.1.6",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"dayjs": "^1.11.13",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,12 @@ export function CodeOfHonor() {
const handleAcceptCodeOfHonor = async () => {
setLoading(true);
const res = await acceptCodeOfHonor();
setLoading(false);

if (!res) {
errorToast();
return;
}
setLoading(false);
setUser(res);
};

Expand Down
53 changes: 0 additions & 53 deletions src/app/[locale]/(private)/profile/components/contact-editor.tsx

This file was deleted.

18 changes: 10 additions & 8 deletions src/app/[locale]/(private)/profile/components/contacts.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,9 @@ import * as z from 'zod';
import { useForm } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';
import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
import { ContactEditor } from '@/app/[locale]/(private)/profile/components/contact-editor';
import { useTranslations } from 'next-intl';
import { EditableField } from '@/app/[locale]/(private)/profile/components/editable-field';
import { Fragment } from 'react';

interface Props {
contacts: Contact[];
Expand Down Expand Up @@ -58,13 +59,14 @@ export function Contacts({ contacts, contactTypes }: Props) {
<Separator />
<div className="flex w-full flex-col gap-4">
{contacts.map((contact) => (
<ContactEditor
key={contact.id}
label={contact.type.name}
value={contact.value}
onSave={(newValue) => handleUpdateContact(contact.id, contact.type.id, newValue)}
onDelete={() => handleDeleteContact(contact.id)}
/>
<Fragment key={contact.id}>
<EditableField
label={contact.type.name}
value={contact.value}
onSave={(newValue) => handleUpdateContact(contact.id, contact.type.id, newValue)}
onDelete={() => handleDeleteContact(contact.id)}
/>
</Fragment>
))}
</div>
</div>
Expand Down
140 changes: 140 additions & 0 deletions src/app/[locale]/(private)/profile/components/editable-field.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
import React, { useState } from 'react';
import { Input } from '@/components/ui/input';
import { Button } from '@/components/ui/button';
import { Paragraph } from '@/components/typography/paragraph';
import { PencilBold, XBold } from '@/app/images';
import { Show } from '@/components/utils/show';
import { useTranslations } from 'next-intl';
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/components/ui/tooltip';
import {
AlertDialog,
AlertDialogAction,
AlertDialogCancel,
AlertDialogContent,
AlertDialogDescription,
AlertDialogFooter,
AlertDialogHeader,
AlertDialogTitle,
AlertDialogTrigger,
} from '@/components/ui/alert-dialog';
import { Heading6 } from '@/components/typography/headers';

interface EditableFieldProps {
onSave: (newValue: string) => void;
size?: 'small' | 'medium';
value?: string;
onDelete?: () => void;
label?: string;
renderValue?: (value: string) => React.ReactNode;
disableClearValue?: boolean;
placeholder?: string;
}

export function EditableField({
onSave,
value,
size = 'medium',
onDelete,
label,
renderValue,
disableClearValue = false,
placeholder,
}: EditableFieldProps) {
const t = useTranslations('private.profile');
const [isEditing, setIsEditing] = useState(!value);
const [currentValue, setCurrentValue] = useState(value || '');

const handleSave = () => {
onSave(currentValue);
setIsEditing(false);
};

const handleDelete = () => {
if (onDelete) {
onDelete();
}
};

return (
<div className="group flex flex-col items-start gap-4 xl:flex-row xl:items-center">
<Show when={!!label}>
<Paragraph className="m-0 w-full min-w-[170px] max-w-[250px] font-semibold text-neutral-400">
{label}:
</Paragraph>
</Show>

{isEditing ? (
<div className="flex w-full flex-wrap items-center gap-2 md:flex-nowrap">
<Input
size={size}
className="text-lg font-medium text-neutral-900"
value={currentValue}
onChange={(e) => setCurrentValue(e.target.value)}
placeholder={placeholder}
/>
<Button size={size} onClick={handleSave}>
{t('button.save')}
</Button>
</div>
) : (
<div className="flex flex-wrap justify-between gap-4 md:flex-nowrap">
{renderValue ? renderValue(currentValue) : <Paragraph className="m-0 font-medium">{currentValue}</Paragraph>}
<div className="flex gap-2 opacity-100 transition-opacity md:opacity-0 md:group-hover:opacity-100">
<TooltipProvider>
<Tooltip>
<TooltipTrigger>
<Button
variant="tertiary"
className="size-6"
icon={<PencilBold className="text-basic-blue" />}
onClick={() => setIsEditing(true)}
/>
</TooltipTrigger>
<TooltipContent>
<p>{t('contact.edit-contact')}</p>
</TooltipContent>
</Tooltip>
</TooltipProvider>

{!disableClearValue && onDelete && (
<AlertDialog>
<TooltipProvider>
<Tooltip>
<TooltipTrigger asChild>
<AlertDialogTrigger asChild>
<Button
variant="tertiary"
className="size-6"
icon={<XBold className="text-status-danger-300" />}
/>
</AlertDialogTrigger>
</TooltipTrigger>
<TooltipContent>
<p>{t('contact.delete-contact')}</p>
</TooltipContent>
</Tooltip>
</TooltipProvider>
<AlertDialogContent className="w-[400px]">
<AlertDialogHeader>
<AlertDialogTitle>
<Heading6>{t('contact.delete-dialog-title')}</Heading6>
</AlertDialogTitle>
<AlertDialogDescription className="text-base font-medium">
{t('contact.delete-dialog-description')}
</AlertDialogDescription>
</AlertDialogHeader>
<AlertDialogFooter className="flex h-[44px] flex-col sm:flex-row sm:justify-between sm:space-x-2">
<AlertDialogCancel className="w-full">{t('contact.delete-dialog-cancel')}</AlertDialogCancel>
<AlertDialogAction className="w-full" onClick={handleDelete}>
{t('contact.delete-dialog-confirm')}
</AlertDialogAction>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>
)}
</div>
</div>
)}
</div>
);
}
40 changes: 0 additions & 40 deletions src/app/[locale]/(private)/profile/components/fullname-english.tsx

This file was deleted.

13 changes: 10 additions & 3 deletions src/app/[locale]/(private)/profile/components/info-block.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@ import { useServerErrorToast } from '@/hooks/use-server-error-toast';
import { User } from '@/types/user';
import { USER_CATEGORIES } from '@/types/constants';
import React from 'react';
import { FullNameEnglish } from '@/app/[locale]/(private)/profile/components/fullname-english';
import { LecturerInfo } from '@/app/[locale]/(private)/profile/components/lecturer-info';
import { StudentInfo } from '@/app/[locale]/(private)/profile/components/student-info';
import { ProfilePicture } from '@/components/ui/profile-picture';
import { EditableField } from '@/app/[locale]/(private)/profile/components/editable-field';

interface Props {
className?: string;
Expand Down Expand Up @@ -43,11 +43,18 @@ export function InfoBlock({ className }: Props) {
return (
<Card className={cn(className)}>
<CardContent className="flex flex-col gap-6 space-y-1.5 p-9">
<div className="flex flex-col gap-6 md:flex-row">
<div className="flex w-full flex-col gap-6 md:flex-row">
<ProfilePicture size="xl" src={user?.photo || ''} />
<div className="flex flex-col gap-4 md:gap-2">
<Heading4>{user?.fullName}</Heading4>
<FullNameEnglish fullNameEnglish={user?.fullNameEnglish || ''} onSave={handleSaveFullNameEn} />
<EditableField
size="small"
value={user?.fullNameEnglish || ''}
onSave={handleSaveFullNameEn}
renderValue={(value: string) => <Heading6>{value}</Heading6>}
disableClearValue
placeholder={t('info.full-name-EN')}
/>
<div className="flex gap-2">
{user?.userCategories.map((category) => (
<Heading6 key={category} className="text-basic-blue">
Expand Down
23 changes: 23 additions & 0 deletions src/app/[locale]/(private)/profile/components/info-list.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { Paragraph } from '@/components/typography/paragraph';

export type InfoItem = {
label: string;
value?: number | string;
};

interface Props {
items: InfoItem[];
}

export function InfoList({ items }: Props) {
return (
<div className="flex flex-col gap-4">
{items.map((item, index) => (
<div key={index} className="flex flex-col gap-3 md:flex-row md:gap-6">
<Paragraph className="m-0 w-[170px] font-semibold text-neutral-400">{item.label}:</Paragraph>
<Paragraph className="m-0 font-medium">{item.value}</Paragraph>
</div>
))}
</div>
);
}
Loading

0 comments on commit 5e1ac5f

Please sign in to comment.