Skip to content
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
57 changes: 45 additions & 12 deletions src/app/(user-page)/mypage/components/BasicEdit.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,13 @@ const BasicEdit = ({ onEditComplete }: BasicEditProps) => {
const [ageLabel, setAgeLabel] = useState('์„ ํƒ ์•ˆํ•จ');
const [locationLabel, setLocationLabel] = useState('์„ ํƒ ์•ˆํ•จ');

// ์†Œ๊ฐœ๊ธ€ ๊ธ€์ž ์ˆ˜ ์ƒํƒœ ๊ด€๋ฆฌ
const [introLength, setIntroLength] = useState(0);

// ์ปค์Šคํ…€ ํ›…์„ ์‚ฌ์šฉํ•˜์—ฌ ํ”„๋กœํ•„ ๋ฐ์ดํ„ฐ ๊ฐ€์ ธ์˜ค๊ธฐ
const { data: profileData, isLoading } = useProfileQuery();

// ํ”„๋กœํ•„ ์—…๋ฐ์ดํŠธ ๋ฎคํ…Œ์ด์…˜ ํ›… ์‚ฌ์šฉ - ์ด ๋ถ€๋ถ„์ด ๋ˆ„๋ฝ๋˜์–ด ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค
// ํ”„๋กœํ•„ ์—…๋ฐ์ดํŠธ ๋ฎคํ…Œ์ด์…˜ ํ›… ์‚ฌ์šฉ
const { mutate: updateProfile, isPending: isUpdating } =
useUpdateProfileMutation();

Expand All @@ -35,6 +38,7 @@ const BasicEdit = ({ onEditComplete }: BasicEditProps) => {
control,
setValue,
reset,
watch,
formState: { errors, isSubmitting },
} = useForm<IFormData>({
defaultValues: {
Expand All @@ -53,6 +57,12 @@ const BasicEdit = ({ onEditComplete }: BasicEditProps) => {
name: 'gender',
});

// ์†Œ๊ฐœ๊ธ€ ๊ฐ์‹œํ•˜์—ฌ ๊ธ€์ž ์ˆ˜ ์—…๋ฐ์ดํŠธ
const introValue = watch('intro');
useEffect(() => {
setIntroLength(introValue?.length || 0);
}, [introValue]);

// ์˜ต์…˜ ๋ฐ์ดํ„ฐ - useMemo๋กœ ๋ฉ”๋ชจ์ด์ œ์ด์…˜
const positionOptions = useMemo(
() => [
Expand Down Expand Up @@ -115,6 +125,9 @@ const BasicEdit = ({ onEditComplete }: BasicEditProps) => {
location: profile.location || '',
});

// ์†Œ๊ฐœ๊ธ€ ๊ธ€์ž ์ˆ˜ ์ดˆ๊ธฐํ™”
setIntroLength(profile.intro?.length || 0);

// ๋“œ๋กญ๋‹ค์šด ๋ผ๋ฒจ ์ดˆ๊ธฐ ์„ค์ •
const positionOption = positionOptions.find(
(opt) => opt.value === profile.position,
Expand All @@ -133,6 +146,11 @@ const BasicEdit = ({ onEditComplete }: BasicEditProps) => {

// ํผ ์ œ์ถœ ์ฒ˜๋ฆฌ
const onSubmit = (data: IFormData) => {
// ๊ธ€์ž ์ˆ˜ ๊ฒ€์‚ฌ ์ถ”๊ฐ€
if (data.intro && data.intro.length > 250) {
return;
}

updateProfile(data, {
onSuccess: () => {
onEditComplete();
Expand Down Expand Up @@ -193,28 +211,43 @@ const BasicEdit = ({ onEditComplete }: BasicEditProps) => {
id="name-input"
type="text"
{...register('name', { required: true })}
className="typo-button1 h-[50px] rounded-[8px] border-b border-Cgray300 bg-Cgray200 py-2 pl-[16px] text-Cgray700 focus:outline-none"
className="rounded-2 typo-button1 h-[50px] border-b border-Cgray300 bg-Cgray200 px-4 py-2 text-Cgray700 focus:outline-none"
/>
{errors.name && (
<span className="text-red-500 text-sm">์ด๋ฆ„์„ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”</span>
<span className="text-sm text-warning">์ด๋ฆ„์„ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”</span>
)}
</div>

{/* ์ž๊ธฐ์†Œ๊ฐœ ํ…์ŠคํŠธ ์˜์—ญ */}
<div className="flex flex-col gap-[8px]">
<label htmlFor="intro-input" className="typo-head3 text-main">
์ž๊ธฐ์†Œ๊ฐœ
</label>
<div className="flex flex-col gap-2">
<div className="flex items-center justify-between">
<label htmlFor="intro-input" className="typo-head3 text-main">
์ž๊ธฐ์†Œ๊ฐœ
</label>
</div>
<textarea
id="intro-input"
{...register('intro')}
{...register('intro', {
maxLength: {
value: 250,
message: '์ตœ๋Œ€ 250์ž๊นŒ์ง€ ์ž‘์„ฑ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค',
},
})}
rows={3}
className="h-[140px] resize-none rounded-[8px] border-b border-Cgray300 bg-Cgray200 py-2 pl-[16px] text-Cgray700 focus:outline-none"
className="rounded-2 h-[140px] resize-none border-b border-Cgray300 bg-Cgray200 px-4 py-2 text-Cgray700 focus:outline-none"
/>
{errors.intro && (
<span className="text-sm text-warning">{errors.intro.message}</span>
)}
{introLength > 250 && !errors.intro && (
<span className="text-sm text-warning">
์ตœ๋Œ€ 250์ž๊นŒ์ง€ ์ž‘์„ฑ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค
</span>
)}
</div>

{/* ํฌ์ง€์…˜ ๋“œ๋กญ๋‹ค์šด */}
<div className="flex flex-col gap-[16px] border-b border-Cgray300 pb-[32px]">
<div className="flex flex-col gap-4 border-b border-Cgray300 pb-8">
<div className="typo-head3 text-main">ํฌ์ง€์…˜</div>
<Controller
name="position"
Expand All @@ -241,7 +274,7 @@ const BasicEdit = ({ onEditComplete }: BasicEditProps) => {
<button
key={option}
type="button"
className={`flex-1 rounded-md px-4 py-2 transition-colors duration-200 ${
className={`flex-1 rounded-md px-1 py-2 transition-colors duration-200 ${
currentGender === option
? 'bg-main font-medium text-white'
: 'bg-white'
Expand Down Expand Up @@ -307,7 +340,7 @@ const BasicEdit = ({ onEditComplete }: BasicEditProps) => {
<Button
type="submit"
className="h-[40px] w-[140px] select-none md:h-[46px]"
disabled={isSubmitting || isUpdating}
disabled={isSubmitting || isUpdating || introLength > 250}
>
{isUpdating ? '์ €์žฅ ์ค‘...' : '๋ณ€๊ฒฝ์‚ฌํ•ญ ์ €์žฅ'}
</Button>
Expand Down
10 changes: 3 additions & 7 deletions src/app/(user-page)/mypage/components/BasicInfo.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,15 @@
import { Button } from '@/components/ui/Button';
import { useQuery } from '@tanstack/react-query';
import { useProfileQuery } from '@/hooks/queries/useMyPageQueries';

import { getProfile } from '../../../../service/api/mypageProfile';
import SkeletonBasicInfo from './skeletons/SkeletonBasicInfo';

interface BasicInfoProps {
onEnableEdit: () => void;
}

const BasicInfo = ({ onEnableEdit }: BasicInfoProps) => {
// tanstack query๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์‚ฌ์šฉ์ž ํ”„๋กœํ•„ ๋ฐ์ดํ„ฐ ๋ถˆ๋Ÿฌ์˜ค๊ธฐ
const { data, isLoading, error } = useQuery({
queryKey: ['profile'],
queryFn: getProfile,
});
// Use the custom hook instead of direct useQuery
const { data, isLoading, error } = useProfileQuery();

// ์‚ฌ์šฉ์ž ๋ฐ์ดํ„ฐ ํฌ๋งทํŒ…
const userData = {
Expand Down
2 changes: 1 addition & 1 deletion src/app/(user-page)/mypage/components/ContactEdit.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ const ContactEdit = ({ onEditComplete }: ContactEditProps) => {
return (
<form
onSubmit={handleSubmit(onSubmit)}
className="mb-6 w-full rounded-[16px] border border-Cgray300 p-[32px]"
className="w-full rounded-[16px] border border-Cgray300 p-[32px]"
>
<div className="flex flex-col gap-[32px]">
<div className="flex flex-col gap-[8px]">
Expand Down
10 changes: 9 additions & 1 deletion src/app/(user-page)/mypage/components/PasswordEdit.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
'use client';

import { useToast } from '@/components/common/ToastContext';
import { Button } from '@/components/ui/Button';
import { Input } from '@/components/ui/Input';
import { useUpdatePasswordMutation } from '@/hooks/queries/useMyPageQueries';
Expand All @@ -16,6 +17,9 @@ interface PasswordEditProps {
}

const PasswordEdit = ({ onEditComplete }: PasswordEditProps) => {
// Toast ์ปจํ…์ŠคํŠธ ์‚ฌ์šฉ
const { showToast } = useToast();

// React Hook Form ์„ค์ •
const {
register,
Expand Down Expand Up @@ -58,7 +62,11 @@ const PasswordEdit = ({ onEditComplete }: PasswordEditProps) => {
},
{
onSuccess: () => {
// ์„ฑ๊ณต ์‹œ ํŽธ์ง‘ ๋ชจ๋“œ ์ข…๋ฃŒ
// ์„ฑ๊ณต ์‹œ ํ† ์ŠคํŠธ ๋ฉ”์‹œ์ง€ ํ‘œ์‹œ
showToast('๋น„๋ฐ€๋ฒˆํ˜ธ๊ฐ€ ์„ฑ๊ณต์ ์œผ๋กœ ๋ณ€๊ฒฝ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.', 'success', {
duration: 3000,
});
// ํŽธ์ง‘ ๋ชจ๋“œ ์ข…๋ฃŒ
onEditComplete();
},
onError: () => {
Expand Down
39 changes: 22 additions & 17 deletions src/app/(user-page)/mypage/components/TechStackEdit.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
'use client';

import { Button } from '@/components/ui/Button';
// Button ์ปดํฌ๋„ŒํŠธ import ์ถ”๊ฐ€
import {
useProfileQuery,
useUpdateSkillsMutation,
Expand All @@ -16,9 +18,13 @@ import TechButtonList from '../../../../components/ui/tech-stack/tech-stack-comp

interface TechStackEditProps {
onEditComplete: () => void;
maxSelections?: number;
}

const TechStackEdit = ({ onEditComplete }: TechStackEditProps) => {
const TechStackEdit = ({
onEditComplete,
maxSelections = 999,
}: TechStackEditProps) => {
const queryClient = useQueryClient(); // ์ถ”๊ฐ€: ์ง์ ‘ queryClient ์ฐธ์กฐ
const [activeCategory, setActiveCategory] = useState<CategoryType>('all');

Expand All @@ -42,7 +48,7 @@ const TechStackEdit = ({ onEditComplete }: TechStackEditProps) => {
handleRemoveSelection,
setInitialSelection,
} = useTechSelection({
maxSelections: 5,
maxSelections: maxSelections,
});

// ์ดˆ๊ธฐ ์Šคํ‚ฌ ์„ค์ • - ๋‹จ ํ•œ ๋ฒˆ๋งŒ ์‹คํ–‰๋˜๋„๋ก ๊ฐœ์„ 
Expand Down Expand Up @@ -73,12 +79,9 @@ const TechStackEdit = ({ onEditComplete }: TechStackEditProps) => {
}

return (
<div className="rounded-lg border border-Cgray300 bg-Cgray200 p-4">
<div className="rounded-lg border border-Cgray300 bg-BG p-[32px]">
<div className="mb-4 flex items-center justify-between">
<h3 className="typo-head3 text-Cgray700">๊ธฐ์ˆ  ์Šคํƒ ํŽธ์ง‘</h3>
<span className="text-xs text-Cgray500">
์ตœ๋Œ€ 5๊ฐœ ์„ ํƒ ๊ฐ€๋Šฅ ({selectedCount}/5)
</span>
<div className="typo-head3 text-main">๊ธฐ์ˆ  ์Šคํƒ ํŽธ์ง‘</div>
</div>

{/* ์„ ํƒ๋œ ๊ธฐ์ˆ  ๋ชฉ๋ก */}
Expand All @@ -102,26 +105,28 @@ const TechStackEdit = ({ onEditComplete }: TechStackEditProps) => {
icons={getIconsByCategory(activeCategory)}
clickedButtons={clickedButtons}
selectedCount={selectedCount}
maxSelections={5}
maxSelections={maxSelections}
onButtonClick={handleButtonClick}
className="bg-transparent"
/>

<div className="mt-4 flex justify-end gap-3">
<button
<div className="mt-4 flex justify-between">
<Button
type="button"
variant="outline"
className="h-[40px] w-[140px] md:h-[46px]"
onClick={onEditComplete}
className="rounded-md border border-Cgray300 px-4 py-2 text-Cgray700"
>
์ทจ์†Œ
</button>
<button
</Button>
<Button
type="button"
onClick={handleSave}
className="rounded-md bg-main px-4 py-2 text-white"
className="h-[40px] w-[140px] select-none md:h-[46px]"
disabled={isUpdating}
onClick={handleSave}
>
{isUpdating ? '์ €์žฅ ์ค‘...' : '์ €์žฅ'}
</button>
{isUpdating ? '์ €์žฅ ์ค‘...' : '๋ณ€๊ฒฝ์‚ฌํ•ญ ์ €์žฅ'}
</Button>
</div>
</div>
);
Expand Down
24 changes: 14 additions & 10 deletions src/app/(user-page)/mypage/components/TechStackInfo.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { Button } from '@/components/ui/Button';
import { useProfileQuery } from '@/hooks/queries/useMyPageQueries';
import { getIconColor, getIconComponent } from '@/util/getIconDetail';
import React from 'react';
Expand All @@ -20,15 +21,9 @@ const TechStackInfo = ({ onEnableEdit }: TechStackInfoProps) => {
}

return (
<div className="rounded-lg border border-Cgray300 bg-Cgray200 p-4">
<div className="rounded-[16px] border border-Cgray300 bg-BG p-[32px]">
<div className="mb-4 flex items-center justify-between">
<h3 className="typo-head3 text-Cgray700">๊ธฐ์ˆ  ์Šคํƒ</h3>
<button
onClick={onEnableEdit}
className="hover:text-main-dark text-sm text-main"
>
ํŽธ์ง‘
</button>
<div className="typo-head3 text-Cgray700">๊ธฐ์ˆ  ์Šคํƒ</div>
</div>

{userSkills.length > 0 ? (
Expand All @@ -42,7 +37,7 @@ const TechStackInfo = ({ onEnableEdit }: TechStackInfoProps) => {
className="flex items-center gap-1 rounded-full border border-main bg-Cgray100 px-2 py-1 shadow-sm"
>
<span className="flex-shrink-0">
<Icon size={14} color={color} />
<Icon size={20} color={color} />
</span>
<span
style={{ color }}
Expand All @@ -55,8 +50,17 @@ const TechStackInfo = ({ onEnableEdit }: TechStackInfoProps) => {
})}
</div>
) : (
<p className="text-sm text-Cgray500">๋“ฑ๋ก๋œ ๊ธฐ์ˆ  ์Šคํƒ์ด ์—†์Šต๋‹ˆ๋‹ค.</p>
<p className=" text-Cgray500">๋“ฑ๋ก๋œ ๊ธฐ์ˆ  ์Šคํƒ์ด ์—†์Šต๋‹ˆ๋‹ค.</p>
)}
<div className="flex justify-center pt-[32px] md:justify-start">
<Button
variant="outline"
className="h-[40px] w-[295px] md:h-[46px] md:w-[280px]"
onClick={onEnableEdit}
>
๊ธฐ์ˆ ์Šคํƒ ๋ณ€๊ฒฝ
</Button>
</div>
</div>
);
};
Expand Down
1 change: 1 addition & 0 deletions src/components/common/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ const AfterLogin = ({ userInfo }: { userInfo: IUserInfo }) => {
src={userInfo.profilePic}
width={40}
height={40}
className="h-10 w-10 rounded-full"
alt="ํ”„๋กœํ•„ ์ด๋ฏธ์ง€"
/>
),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ interface TechButtonListProps {
selectedCount: number;
maxSelections: number;
onButtonClick: (name: string) => void;
className?: string;
}

const TechButtonList = ({
Expand All @@ -17,9 +18,10 @@ const TechButtonList = ({
selectedCount,
maxSelections,
onButtonClick,
className = '',
}: TechButtonListProps): JSX.Element => {
return (
<div className="mt-4 rounded-md bg-Cgray200 p-4">
<div className={`mt-4 rounded-md bg-Cgray200 p-4 ${className}`}>
<div
className="h-[140px] overflow-y-auto pr-2"
style={{
Expand Down
Loading