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

Feature/FE-092 : map, 회원가입, 로그인 QA 대응 #128

Merged
merged 12 commits into from
Jul 30, 2023
Merged
1 change: 1 addition & 0 deletions src/app/login/components/LoginButton/LoginButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ const LoginButton = ({ submitErrorMsg }: LoginButtonProps) => {
active={true}
onClick={onClickPersistentButton}
type="button"
initActive={keep === 'Y'}
/>
<Typography variant="label2" as="p" color="sub">
로그인 유지
Expand Down
23 changes: 15 additions & 8 deletions src/app/login/components/LoginWrapper/LoginWrapper.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,25 @@
'use client';
import { LoginForm, LoginTitle } from '../../components';
import { Content } from '@/components';
import { useIsMobile } from '@/hooks';
import { animate } from '@/styles/theme.css';

import { Media } from '@/components';
const LoginWrapper = () => {
const mobile = useIsMobile();

return (
<div className={animate}>
<Content verticalCenter={mobile ? false : true}>
<LoginTitle />
<LoginForm />
</Content>
<Media breakpoint="m" fallback={<></>}>
<Media.Less>
<Content verticalCenter={false}>
<LoginTitle />
<LoginForm />
</Content>
</Media.Less>
<Media.Greater>
<Content verticalCenter={true}>
<LoginTitle />
<LoginForm />
</Content>
</Media.Greater>
</Media>
</div>
);
};
Expand Down
2 changes: 1 addition & 1 deletion src/app/login/contexts/LoginContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ interface LoginContextValue {
const LoginContext = createContext<LoginContextValue | null>(null);

const LoginContextProvider = ({ children }: { children: ReactNode }) => {
const [keep, setKeep] = useState('N');
const [keep, setKeep] = useState('Y');

const contextValue = useMemo(() => ({ keep, setKeep }), [keep, setKeep]);

Expand Down
4 changes: 2 additions & 2 deletions src/app/signup/components/AgreeButton/AgreeButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,10 @@ const AgreeButton = ({ onClick, error, text, name }: AgreeButtonProps) => {
type="button"
/>
<Typography variant="label2" as="p" color="sub">
(필수){' '}
(필수)
<span className={agreeText} onClick={() => onClickAgreeText()}>
{text}
</span>{' '}
</span>
동의
</Typography>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import clsx from 'classnames';
const ProfileSetupSignUp = () => {
const { userInfo } = useSignupContext();
const router = useRouter();
const [disabled, setDisabled] = useState<boolean>(false);
const [selectedValue, setSelectedValue] = useState<SelectedDropDownValue>({
job: null,
birth: null,
Expand All @@ -26,13 +27,18 @@ const ProfileSetupSignUp = () => {
const successSignup = () => {
router.replace('/welcome');
};
const onError = () => {
setDisabled(false);
};
const { postData, errorMsg } = usePostApi<SignupRequest, SignupResponse>({
apiFunction: postSignup,
onSuccess: successSignup,
onError,
});
const { method } = useCommonForm({ schema: signupSchema, checkMode: 'onSubmit' });

const onSubmit: SubmitHandler<FieldValues> = async (data: FieldValues) => {
setDisabled(true);
postData({
email: `${userInfo?.email}@samsung.com`,
password: userInfo?.password,
Expand Down Expand Up @@ -67,7 +73,7 @@ const ProfileSetupSignUp = () => {
label="직군 소분류"
name="job"
placeholder="ex) uiux디자이너"
required={true}
required={false}
method={method}
className={inputMargin}
/>
Expand All @@ -82,11 +88,11 @@ const ProfileSetupSignUp = () => {
selections={birthType}
/>
</div>
<Button size="large" type="submit" className={button}>
<Button size="large" type="submit" className={button} disabled={disabled}>
저장하기
</Button>
<div className={requiredFields}>{errorMsg}</div>
<BottomButton type="submit" errorMsg={errorMsg}>
<BottomButton type="submit" errorMsg={errorMsg} disabled={disabled}>
저장하기
</BottomButton>
</InputField>
Expand Down
2 changes: 1 addition & 1 deletion src/app/signup/constants/dropdown.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ export const birthType = getBirthList();
export const jobType = [
'개발',
'교육',
'금융재무',
'금융/재무',
'기획/경영',
'데이터',
'디자인',
Expand Down
8 changes: 5 additions & 3 deletions src/app/signup/constants/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,10 @@ export const passwordSchema = z
password: z
.string()
.min(1, '필수 입력 정보를 입력해 주세요.')
.min(8, '영문과 숫자를 포함하여 8~20자로 입력해 주세요.')
.max(20, '영문과 숫자를 포함하여 8~20자로 입력해 주세요.'),
.refine(
(value) => /^(?=.*[a-zA-Z])(?=.*\d).{8,20}$/.test(value),
'영문과 숫자를 포함하여 8~20자로 입력해 주세요.',
),
passwordCheck: z.string().min(1, '필수 입력 정보를 입력해 주세요.'),
})
.refine((data) => data.password === data.passwordCheck, {
Expand All @@ -21,5 +23,5 @@ export const passwordSchema = z
});
export const signupSchema = z.object({
nickname: z.string().min(2, '2-10자로 입력해 주세요.').max(10, '2-10자로 입력해 주세요.'),
job: z.string().min(1, '10자 이하로 입력해주세요.').max(10, '10자 이하로 입력해주세요.'),
job: z.string().min(0, '10자 이하로 입력해주세요.').max(10, '10자 이하로 입력해주세요.'),
});
1 change: 1 addition & 0 deletions src/app/signup/hooks/useConsent/useConsent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ export const useConsent = (): [boolean, boolean, () => void, () => void] => {
const [error, setError] = useState(false);

const onClickConsent = useCallback(() => {
setError(false);
setAgree((prev: boolean) => !prev);
}, []);

Expand Down
56 changes: 41 additions & 15 deletions src/components/IconButton/IconButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ type IconButtonProps = {
hover?: boolean;
active?: boolean;
error?: boolean;
initActive?: boolean;
} & Image &
ButtonHTMLAttributes<HTMLButtonElement>;

Expand All @@ -30,41 +31,66 @@ const IconButton = ({
active = false,
error = false,
disabled = false,
initActive = false,
width = '36',
height = '36',
onClick,
className,
...rest
}: IconButtonProps) => {
const [isActive, setIsActive] = useState(false);
const [isActive, setIsActive] = useState(initActive);
const [status, setStatus] = useState(ICON_STATUS.DEFAULT);
const [iconSvgId, setIconSvgId] = useState<string>(iconType);

useEffect(() => {
if (!error) return;
setStatus(error ? ICON_STATUS.ERROR : ICON_STATUS.DEFAULT);
switch (true) {
case error:
setStatus(ICON_STATUS.ERROR);
break;
case disabled:
setStatus(ICON_STATUS.DISABLE);
break;
case active:
initActive && setStatus(ICON_STATUS.ACTIVE);
break;
default:
setStatus(ICON_STATUS.DEFAULT);
break;
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [error, disabled]);

useEffect(() => {
setStatus(disabled ? ICON_STATUS.DISABLE : ICON_STATUS.DEFAULT);
}, [disabled]);
const updateClickStatus = () => {
switch (true) {
case error:
setStatus(ICON_STATUS.ACTIVE);
setIsActive(true);
break;
case active:
setStatus(isActive ? ICON_STATUS.DEFAULT : ICON_STATUS.ACTIVE);
setIsActive(!isActive);
break;
default:
setStatus(ICON_STATUS.DEFAULT);
break;
}
};
const isPossibleHover = () => !error && !disabled && status !== ICON_STATUS.ACTIVE && hover;

const handleMouseEnter = () => {
if (error || disabled || status === ICON_STATUS.ACTIVE) return;
hover && setStatus(ICON_STATUS.HOVER);
if (isPossibleHover()) {
setStatus(ICON_STATUS.HOVER);
}
};

const handleMouseLeave = () => {
if (error || disabled || status === ICON_STATUS.ACTIVE) return;
hover && setStatus(ICON_STATUS.DEFAULT);
if (isPossibleHover()) {
setStatus(ICON_STATUS.DEFAULT);
}
};

const handleOnClick = (e: MouseEvent<HTMLButtonElement>): void => {
if (disabled) return;
if (active || error) {
setStatus(isActive ? ICON_STATUS.DEFAULT : ICON_STATUS.ACTIVE);
setIsActive(!isActive);
}
updateClickStatus();
onClick?.(e);
};
useEffect(() => {
Expand Down
3 changes: 3 additions & 0 deletions src/components/Map/Map.css.ts
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,9 @@ export const searchList = style({
'&:focus': {
background: 'rgba(28, 26, 66, 0.1)',
},
'&:hover': {
background: 'rgba(28, 26, 66, 0.04)',
},
},
});

Expand Down
6 changes: 5 additions & 1 deletion src/components/Map/MapConfirmButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,17 @@ type MapConfirmButtonProps = {

const MapConfirmButton = ({ onClick }: MapConfirmButtonProps) => {
const { mapState } = useMapContext();
const disabledButton = () => {
const place = mapState.place as Place;
return Object.keys(place).length === 0;
};
const handleOnClick = () => {
const place = mapState.place as Place;
onClick(place);
};
return (
<div className={buttonWrapper}>
<Button disabled={!mapState.keyword} size="medium" aria-label="확인" onClick={handleOnClick}>
<Button disabled={disabledButton()} size="medium" aria-label="확인" onClick={handleOnClick}>
확인
</Button>
</div>
Expand Down
19 changes: 5 additions & 14 deletions src/components/Map/MapSearchList.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
'use client';
import { searchinfoWrapper, noSearchInfoWrapper } from './Map.css';
import { useCallback, useRef } from 'react';
import { Place } from '@/types/map';
import { useMapPickMarker, useMapListMarkers } from './hooks';
import { useSearchList } from './hooks';
import MapSearchItem from './MapSearchItem';
import IconButton from '../IconButton/IconButton';
import { useDisplayContext, useMapContext } from './contexts/MapContextProvider';
import { useDisplayContext } from './contexts/MapContextProvider';

type MapSearchListProps = {
map: any;
Expand Down Expand Up @@ -36,17 +35,9 @@ const SearchInfo = () => {
);
};
const MapSearchList = ({ map, marker }: MapSearchListProps) => {
const markers = useRef<any[]>([]);
const listRefs = useRef<Record<number, HTMLLIElement | null>>({});
const setListItemRef = useCallback((ref: HTMLLIElement | null, index: number) => {
listRefs.current[index] = ref;
}, []);
const { mapState } = useMapContext();
const { displayState } = useDisplayContext();
const placeList = mapState.markerPlace?.length != 0 ? mapState.markerPlace : mapState.searchedPlaces;
const { handleOnClickList, placeList, setListItemRef } = useSearchList({ map, marker });

const { handleOnClickListWithMarkers } = useMapListMarkers({ map, markers });
const { handleOnClickOnlyList } = useMapPickMarker({ map, marker, markers });
if (!placeList) {
return <SearchInfo />;
}
Expand All @@ -56,12 +47,12 @@ const MapSearchList = ({ map, marker }: MapSearchListProps) => {
return (
<div className={searchinfoWrapper({ display: displayState?.searchList, marker: displayState?.marker })} role="list">
<ul>
{placeList?.map((place: Place, index) => (
{placeList?.map((place: Place, index: number) => (
<MapSearchItem
key={index}
place={place}
index={index}
handleOnClickList={mapState.markerPlace?.length != 0 ? handleOnClickOnlyList : handleOnClickListWithMarkers}
handleOnClickList={handleOnClickList}
setListItemRef={setListItemRef}
aria-label={`장소 ${index + 1}`}
/>
Expand Down
12 changes: 2 additions & 10 deletions src/components/Map/contexts/MapContextProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,7 @@ type DisplayAction =
| { type: 'handleClickMarker'; payload: boolean };
type DisplayDispatch = (action: DisplayAction) => void;

type MapAction =
| { type: 'handleClickPlaceList'; payload: MapState }
| { type: 'handleClickPlaceResult'; payload: Place }
| { type: 'handleClickInitPlace' };
type MapAction = { type: 'handleClickPlaceList'; payload: MapState } | { type: 'handleClickInitPlace' };
type MapDispatch = (action: MapAction) => void;

const MapContext = createContext<{ mapState: MapState; mapDispatch: MapDispatch }>({
Expand All @@ -43,12 +40,7 @@ const MapContextProvider = ({ children }: { children: ReactNode }) => {
keyword: action.payload.keyword,
searchedPlaces: action.payload.searchedPlaces,
markerPlace: action.payload.markerPlace,
place: {},
};
case 'handleClickPlaceResult':
return {
...state,
...{ place: action.payload },
place: action.payload.place,
};
case 'handleClickInitPlace':
return {
Expand Down
3 changes: 1 addition & 2 deletions src/components/Map/hooks/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
export { default as useMap } from './useMap';
export { default as useMapListMarkers } from './useMapListMarkers';
export { default as useSearchList } from './useSearchList';
export { default as useMapSearchForm } from './useMapSearchForm';
export { default as useMapPickMarker } from './useMapPickMarker';
44 changes: 0 additions & 44 deletions src/components/Map/hooks/useMapListMarkers.ts

This file was deleted.

Loading