5주차 회고를... 빼 먹었습니다... 우와! 핑계...를 대자면 저번주에 정말 바쁘고 개인적으로 여러 일이 있었어서 프로젝트에 크게 몰입이 안되서... 아무튼 핑계고 다시 으쌰으쌰 해야지..!
import * as React from 'react';
declare class ReCAPTCHA extends React.Component<ReCAPTCHAProps> {}
import ReCAPTCHA from "react-google-recaptcha";
function FindPasswordForm() {
const recaptchaRef = useRef<ReCAPTCHA>(null);
const findPasswordFormik = useFormik({
initialValues: findPasswordFormInitialValue,
validationSchema: Yup.object({
...(중략)...
}),
onSubmit: async (values) => {
const token = (await recaptchaRef?.current?.executeAsync()) as string;
const dataToSubmit: AuthEmail = Object.assign(values, {
token,
});
recaptchaRef.current?.reset();
mutation.mutate(dataToSubmit);
},
});
return (
<ReCAPTCHA
ref={recaptchaRef}
size="invisible"
sitekey={`${process.env.NEXT_PUBLIC_RECAPTCHA_SITE_KEY}`}>
</ReCAPTCHA>
)
}
// common/container/Container
import React from "react";
import {
FOOTER_HEIGHT,
FULL_HEIGHT,
HEADER_HEIGHT,
MAIN_COLOR,
} from "@utils/constant";
import { Container as OuterContainer, InnerContainer } from "./Container.style";
interface ContainerProp {
children: React.ReactNode;
}
function Container({ children }: ContainerProp) {
return (
<OuterContainer
$bgColor={MAIN_COLOR}
$headerHeight={HEADER_HEIGHT}
$footerHeight={FOOTER_HEIGHT}
$fullHeight={FULL_HEIGHT}>
<InnerContainer>{children}</InnerContainer>
</OuterContainer>
);
}
export default Container;
비밀번호 찾기 알림 Modal
유저에게 비밀번호 찾기가 성공적으로 진행되었는지, 실패했는지 여부를 알려주는 Modal을 띄웁니다.
Capture 컴포넌트 공통 컴포넌트로 분리
Capture 컴포넌트가 프로필 이미지 변경이나 유저가 알약을 찍을 때 필요한 중복되는 기능이어서 공통으로 뺐습니다.
이미지는 부모 사이즈에 맞춰 출력됩니다.
import { useState } from "react";
import Image from "next/image";
import { CaptureContainer, CaptureButton } from "./Capture.style";
function Capture() {
const [source, setSource] = useState("");
const handleCapture = (event: React.ChangeEvent<HTMLInputElement>) => {
const { files } = event.target;
if (files?.length) {
const file = files[0];
const newUrl = URL.createObjectURL(file);
setSource(newUrl);
// 이미지를 서버에 보내주면 됨!
}
};
return (
<>
<Image
src={source ? source : "/images/register_logo.png"}
alt="wondering-pill-logo"
layout="fill"
objectFit="cover"
style={{
borderRadius: "50%",
}}
priority={true}
/>
<CaptureContainer>
<input
accept="image/*"
id="icon-button-file"
type="file"
onChange={handleCapture}
style={{ display: "none" }}
/>
<CaptureButton htmlFor="icon-button-file" />
</CaptureContainer>
</>
);
}
export default Capture;
그런데... 이 친구를 적용하면 제 css가... 굴러들어온 slider가 박혀있던 제 css를 부시더군요. slider 이 친구도 난리가 나구요.
styletron의 useStyletron으로 slider에 css를 주입해서 진정 시켰습니다. 또한 slider의 크기만큼 자식의 크기를 조정하고 싶었는데 해결이 안되더군요. slider의 자식들은 vh옵션으로 크기를 조정 했습니다.
<Slider
{...settings}
className={css({
width: "70vw",
height: "80%",
maxWidth: "400px",
margin: "auto",
border: `1px solid ${MAIN_COLOR}`,
})}>
{Object.entries(pharmacyData).map(([key, value], index) => (
<Pharmarcy
key={key}
name={value.name}
phoneNumber={value.phnoeNumber}
/>
))}
</Slider>
getServerSideProps
를 활용해서 구현되었으며, 이전에는 params로 email이 넘어왔는데 변경되어서 email과 token이 query로 넘어옵니다. (이 또한 백엔드의 요청으로 이후 재 변경됩니다.) 서버로 email과 token을 넘겨주면 유효한 token인지 확인하고 결과를 반환합니다. 결과에 따라 새 비밀번호 page를 렌더링 하던가, error page를 렌더링 하게 됩니다.interface NewPasswordProp {
isValidToken: boolean;
}
function NewPassword({ isValidToken }: NewPasswordProp) {
return (
<Container>
<NewPasswordForm isValidToken={isValidToken} />
</Container>
);
}
export const getServerSideProps: GetServerSideProps = async (context) => {
const res = await get<FindPasswordResponse>(
`/auth/change-password/check?token=${context.query.token}&email=${context.query.email}`,
);
const isValidToken = res.result.result;
return {
props: {
isValidToken,
},
};
비밀번호 변경에 성공했다면, login page로 email을 query로 넘기고, redirect 시킵니다.
const mutatuin = useMutation(
(data: string) =>
put(`/auth/change-password/${email}`, {
password: data,
}),
{
onSuccess: () => {
if (router.query.email) {
router.push(
{
pathname: "/login",
query: {
email: router.query.email,
},
},
"/login",
);
}
},
onError: (error: any) => {
throw new Error(error);
},
},
);
getServerSideProps를 처음에 page가 아닌 component에 적용을 해서 왜 안돼? 했었습니다. 😢 (꼼꼼히 읽자!)
https://nextjs.org/docs/basic-features/data-fetching/get-server-side-props
getServerSideProps can only be exported from a page. You can’t export it from non-page files.
금방 적용할 줄 알았던 react-slick이 은근히 복병 역할을... 😂
PR도 신경써서 올리다 보니 이전과 같은 실수들은 거의 하지 않게 되었습니다.
또한 생각보다 길어질 수도 있는 일정에 너무 늘어지면 안된다는 생각이 드네요!
그래도 하나하나 기능이 완성 되어 가는 과정을 거치고, 그 과정을 즐기다 보면 그럴싸한 결과물이 나올 것이라 믿고 재밌게 개발..!
잘 읽고 갑니다 굿
react-slick css 안 먹히는 부분은 저도 동일하게 고민했던 부분인데 PharmacyWrapper 위에 fragment 하나 추가했었어요 map 돌려야 하다보니 key를 줘야해서 div로 바꾸긴 했는데 이렇게 하면 react-slick이 고정해둔 css는 div태그에 적용되고 그 아래는 자유롭게 css 적용 가능하더라구요