Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
673cd24
[feat] prevent copy and paste at input in LoginPage (/auth)
seongjin2427 Jan 30, 2025
a881d83
[feat] prevent moving to go to home when logo is clicked
seongjin2427 Jan 30, 2025
b54742c
[feat] indicate required message after clicking submit with empty inp…
seongjin2427 Jan 30, 2025
26846af
[feat] update regexp for password
seongjin2427 Jan 30, 2025
dc261a9
[feat] remove auto-complete style and add logic to execute with enter…
seongjin2427 Jan 30, 2025
81d09c7
[feat] after sending email, reset button is rendered with timer concu…
seongjin2427 Jan 30, 2025
afb26b9
[fix] change invalid input message when user submitted inexistent id …
seongjin2427 Feb 4, 2025
78befd3
[refact] refactoring signup page
seongjin2427 Feb 4, 2025
3f8bec6
[style] move AuthLayout position to center direction
seongjin2427 Feb 5, 2025
0e4f989
[refact] remove unnecessary hook and reduce useSocialAccountServerReq…
seongjin2427 Feb 5, 2025
9139bd7
[refact] change socialAccount with react-hook-form fieldArray API to …
seongjin2427 Feb 5, 2025
bdf7122
[refact] remove react-hook-form API
seongjin2427 Feb 5, 2025
763ce82
[refact] combine with addUserInterest and addRecommendedInterest
seongjin2427 Feb 5, 2025
bb130f3
[feat] remove react-hook-form Array API logic
seongjin2427 Feb 10, 2025
73f5ac7
[feat] split hooks with useUserInterests and useUserSocialAccount
seongjin2427 Feb 10, 2025
37512e8
[refact] remove unnecessary empty object
seongjin2427 Feb 10, 2025
19db30d
Merge branch 'develop' of https://github.com/f-lab-edu/Prostargram-fr…
seongjin2427 Feb 10, 2025
7d6dd4e
[feat] update profile page logic
seongjin2427 Feb 10, 2025
2b3c3a6
[feat] add Suspense at MainLayout Component to resolve deploy error i…
seongjin2427 Feb 10, 2025
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
8 changes: 4 additions & 4 deletions src/api/info.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,24 @@
import { authInstance } from './httpRequest';

const postSocialAccount = async (account: { socialAccountUrl: string }) => {
const postSocialAccount = async (socialAccount: string) => {
const url = `/social-accounts`;

const result = await authInstance({
method: 'POST',
url,
data: account,
data: socialAccount,
});

return result;
};

const removeSocialAccount = async (account: { socialAccountUrl: string }) => {
const removeSocialAccount = async (socialAccount: string) => {
const url = `/social-accounts`;

const result = await authInstance({
method: 'DELETE',
url,
data: account,
data: socialAccount,
});

return result;
Expand Down
35 changes: 15 additions & 20 deletions src/api/mutations/info.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@ import {
removeSocialAccount,
} from '../info';

type CustomMutationOptionType<T> =
| UseMutationOptions<HttpSuccessType<unknown>, ResponseError, T>
| undefined;

const useAddSocialAccountMutation = (
options: UseMutationOptions<
HttpSuccessType<unknown>,
ResponseError,
{ socialAccountUrl: string }
>,
options: CustomMutationOptionType<string> = {},
) => {
return useMutation({
mutationFn: postSocialAccount,
Expand All @@ -21,11 +21,7 @@ const useAddSocialAccountMutation = (
};

const useRemoveSocialAccountMutation = (
options: UseMutationOptions<
HttpSuccessType<unknown>,
ResponseError,
{ socialAccountUrl: string }
>,
options: CustomMutationOptionType<string> = {},
) => {
return useMutation({
mutationFn: removeSocialAccount,
Expand All @@ -34,11 +30,10 @@ const useRemoveSocialAccountMutation = (
};

const useAddInterest = (
options: UseMutationOptions<
HttpSuccessType<unknown>,
ResponseError,
{ userId: number; interestName: string }
>,
options: CustomMutationOptionType<{
userId: number;
interestName: string;
}> = {},
) => {
return useMutation({
mutationFn: postInterest,
Expand All @@ -47,11 +42,11 @@ const useAddInterest = (
};

const useRemoveInterest = (
options: UseMutationOptions<
HttpSuccessType<unknown>,
ResponseError,
{ userId: number; hashTagId: number; name: string }
>,
options: CustomMutationOptionType<{
userId: number;
hashTagId: number;
name: string;
}> = {},
) => {
return useMutation({
mutationFn: removeInterest,
Expand Down
File renamed without changes.
10 changes: 5 additions & 5 deletions src/app/(AuthLayout)/auth/github/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ const GithubSignupPage = () => {
isEmailRequest,
isEmailRetry,
isUsernameConfirmed,
changeConfirmState,
changeConfirmCodeState,
changeUsernameState,
changeSignupToken,
} = useSignUpState();
Expand All @@ -65,7 +65,7 @@ const GithubSignupPage = () => {
} = useSignupMutation({
formMethods,
changeSignupToken,
changeConfirmState,
changeConfirmCodeState,
changeUsernameState,
});

Expand All @@ -78,7 +78,7 @@ const GithubSignupPage = () => {
const resetEmail = () => {
resetField('email');
resetField('confirm');
changeConfirmState(CONFIRM_STATES.PENDING);
changeConfirmCodeState(CONFIRM_STATES.PENDING);
};

const onSubmit = (values: ISignUpFormValueType) => {
Expand Down Expand Up @@ -118,7 +118,7 @@ const GithubSignupPage = () => {

return (
<div className={styles.container}>
<Logo />
<Logo isGoHome={false} />

<form onSubmit={handleSubmit(onSubmit)} className={styles.form}>
<div>
Expand Down Expand Up @@ -159,7 +159,7 @@ const GithubSignupPage = () => {
<Field.TimerButton
type="button"
className={styles.button}
changeState={() => changeConfirmState('retry')}
expireTimeEvent={() => changeConfirmCodeState('retry')}
isConfirm={isEmailConfirmed}
timerDuration={300_000} // 5분
disabled={isRequestEmailPending || !isEmailRetry}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { KeyboardEvent } from 'react';
import { useFormContext } from 'react-hook-form';

import Input from '@/components/common/Input';
import RemoveIcon from '@/assets/icons/close.svg';
Expand All @@ -8,12 +7,11 @@ import styles from './AdditionalLink.module.scss';

interface AdditionalLinkProps {
index: number;
removeHandler: (index: number) => void;
id: string;
removeHandler: (index: string) => void;
}

const AdditionalLink = ({ index, removeHandler }: AdditionalLinkProps) => {
const { register } = useFormContext();

const AdditionalLink = ({ index, id, removeHandler }: AdditionalLinkProps) => {
const keyupHandler = (e: KeyboardEvent<HTMLInputElement>) => {
if (e.key === 'Enter') {
e.preventDefault();
Expand All @@ -30,14 +28,13 @@ const AdditionalLink = ({ index, removeHandler }: AdditionalLinkProps) => {
<button
type="button"
className={styles.remove_link_button}
onClick={() => removeHandler(index)}
onClick={() => removeHandler(id)}
aria-label="remove-link"
>
<RemoveIcon />
</button>
)
}
{...register(`links.${index}.link`)}
/>
);
};
Expand Down
Original file line number Diff line number Diff line change
@@ -1,40 +1,63 @@
'use client';

import clsx from 'clsx';
import { useFormContext } from 'react-hook-form';
import { HTMLAttributes, useState } from 'react';
import { HTMLAttributes, useEffect, useState } from 'react';

import styles from './InterestCheckbox.module.scss';

interface InterestCheckboxType extends HTMLAttributes<HTMLInputElement> {
interface InterestCheckboxType extends HTMLAttributes<HTMLButtonElement> {
value: string;
isMax: boolean;
isCheckedInterest?: boolean;
onClickWithChecked: () => void;
onClickWithUnchecked: () => void;
}

const InterestCheckbox = ({ value, ...props }: InterestCheckboxType) => {
const [isChecked, setIsChecked] = useState<boolean>(false);
const { register } = useFormContext();
const InterestCheckbox = ({
value,
isMax,
isCheckedInterest,
onClickWithChecked,
onClickWithUnchecked,
...props
}: InterestCheckboxType) => {
const [isChecked, setIsChecked] = useState<boolean | undefined>(
isCheckedInterest,
);

const handleChange = () => {
setIsChecked((prev) => !prev);
const clickHandler = () => {
if (!isChecked && isMax === false) {
onClickWithUnchecked();
setIsChecked(true);
}
if (!isChecked && isMax === true) {
setIsChecked(false);
}
if (isChecked && isMax === false) {
setIsChecked(false);
onClickWithChecked();
}
if (isChecked && isMax === true) {
setIsChecked(false);
onClickWithChecked();
}
};

useEffect(() => {
setIsChecked(isCheckedInterest);
}, [isCheckedInterest]);

return (
<label
htmlFor={value}
<button
type="button"
className={clsx(styles.checkbox, {
[styles.checked]: isChecked,
})}
onChange={handleChange}
onClick={clickHandler}
{...props}
>
<input
id={value}
type="checkbox"
value={value}
{...props}
{...register('interests')}
/>
{`#${value}`}
</label>
</button>
);
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,94 +3,79 @@
import clsx from 'clsx';
import {
useState,
FocusEvent,
ChangeEvent,
KeyboardEvent,
HTMLAttributes,
useRef,
useEffect,
} from 'react';
import { useFormContext } from 'react-hook-form';

import { REG_EXP } from '@/constants/regExp';
import { calculateWidth } from '@/utils/dynamicWidth';
import CircleCloseIcon from '@/assets/icons/circle-close.svg';
import { IAddionalInfoType } from '../../types/AdditionalInfoTypes';

import styles from './MyInterestField.module.scss';

type UserInterestType = { id: string; interestName: string };

interface MyInterestFieldProps
extends Omit<HTMLAttributes<HTMLInputElement>, 'onClick'> {
index: number;
checkList: string[];
onRemove: (index: number) => void;
field: UserInterestType;
onRemove: (id: string) => void;
updateUserInterest: (field: UserInterestType) => void;
}

const MyInterestField = ({
index,
checkList,
field,
onRemove,
updateUserInterest,
...props
}: MyInterestFieldProps) => {
const [word, setIsWord] = useState<string>('');
const [isEditing, setIsEditing] = useState<boolean>(true);
const { register, setError, clearErrors } =
useFormContext<IAddionalInfoType>();
const { onChange, onBlur, ...formProps } = register(
`myInterests.${index}.myInterest`,
);
const inputRef = useRef<HTMLInputElement>(null);

const inputWidth = calculateWidth(word.length);

const noticeDuplicateError = () =>
setError('myInterests', {
type: 'validate',
message: '중복된 관심사입니다.',
});

const isDuplicate = () => {
if (word !== '' && checkList.includes(word)) {
noticeDuplicateError();
onRemove(index);
return true;
}
return false;
const updateInterest = () => {
updateUserInterest({ id: field.id, interestName: word });
setIsEditing(false);
};

const clickHandler = () => {
if (!isEditing) {
onRemove(index);
onRemove(field.id);
}
};

const keydownHandler = (e: KeyboardEvent<HTMLInputElement>) => {
if (e.key !== ' ' && e.key !== 'Enter') return;
if (isEditing && isDuplicate()) return;
e.preventDefault();

setIsEditing(false);
clearErrors('myInterests');
updateInterest();
};

const blurHandler = (e: FocusEvent<HTMLInputElement>) => {
const blurHandler = () => {
if (!word.length) {
onRemove(index);
onRemove(field.id);
return;
}
if (isEditing && isDuplicate()) return;

onBlur(e);
setIsEditing(false);
clearErrors('myInterests');
updateInterest();
};

const changeHandler = (e: ChangeEvent<HTMLInputElement>) => {
const next = e.target.value.trim();

if (REG_EXP.ONLY_ENG_NUM.test(next)) {
setIsWord(() => next);
onChange(e);
}
};

useEffect(() => {
inputRef.current?.focus();
}, []);

return (
<button
type="button"
Expand All @@ -102,14 +87,14 @@ const MyInterestField = ({
>
<input
type={isEditing ? 'text' : 'hidden'}
ref={inputRef}
value={word}
className={styles.input}
style={{ width: inputWidth }}
maxLength={15}
onChange={changeHandler}
onBlur={blurHandler}
onKeyDown={keydownHandler}
{...formProps}
{...props}
/>
{!isEditing && (
Expand Down
Loading
Loading