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

[김민정] Week20 #1086

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
5 changes: 5 additions & 0 deletions api/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,11 @@ export const postSignIn = async (data: any) => {
return fetchPOSTJson(url, data);
};

export const postSignUp = async(data: {email: string; password: string}) => {
const url = `${BASE_URL}sign-up`;
return fetchPOSTJson(url, data);
}

export const postCheckDuplicationEmail = async (data: any) => {
const url = `${BASE_URL}check-email`;
return fetchPOSTJson(url, data);
Expand Down
182 changes: 33 additions & 149 deletions components/SignInUp/EmailPwdInput.tsx
Original file line number Diff line number Diff line change
@@ -1,168 +1,59 @@
import { useState, useEffect, ChangeEvent, KeyboardEvent } from "react";
import { useState, useEffect } from "react";
import styled from "styled-components";
import Image from "next/image";
import eyeoff from "@/assets/icons/eye-off.png";
import eyeon from "@/assets/icons/eye-on.png";
import { changeInputBorderColor } from "@/utils/commonSigninupFunc";
import {
emailInputValidationcheck,
loginPasswordInputValidationcheck,
signInPasswordInputValidationcheck,
emailDuplicationCheck,
} from "@/utils/validation";
import { ERROR_MESSAGE } from "@/constants/errorMessage";
import INPUT_STATUS from "@/constants/inputStatus";
import eyeoff from "@/public/assets/icons/eye-off.png";
import eyeon from "@/public/assets/icons/eye-on.png";
import INPUT_ERROR_INFO from "@/type/inputErrorInfo";


type EmailPwdInputPropsType = {
title: string;
type: string;
valueType: string;
isEyeIcon?: boolean;
setEmailValue?: React.Dispatch<React.SetStateAction<string>>;
emailValue?: string | "";
setPasswordValue?: React.Dispatch<React.SetStateAction<string | undefined>>;
passwordValue?: string | undefined;
onEnterButtonClick: () => void;
loginStatus?: string;
signInStatus?: string;
setIsEmailValid?: React.Dispatch<React.SetStateAction<boolean>>;
setIsPasswordValid?: React.Dispatch<React.SetStateAction<boolean>>;
setIsPasswordConfirmValid?: React.Dispatch<React.SetStateAction<boolean>>;
eventFunc: {
onFocusOut: () => void;
onChange: () => void;
onKeydown: (e: React.KeyboardEvent<HTMLInputElement>) => void;
}
inputErrorInfo: INPUT_ERROR_INFO;
Comment on lines +12 to +16
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

JSX.IntrinsicElements['input'] 쓰셔도 괜찮을 거 같아요!

inputRef: React.RefObject<HTMLInputElement>
};


const EmailPwdInput = ({
title,
type,
valueType,
isEyeIcon,
setEmailValue,
emailValue,
setPasswordValue,
passwordValue,
onEnterButtonClick,
loginStatus,
signInStatus,
setIsEmailValid,
setIsPasswordValid,
setIsPasswordConfirmValid,
eventFunc,
inputErrorInfo,
inputRef
}: EmailPwdInputPropsType) => {
const INPUT_STATUS_VALUE = {
default: "default",
error: "error",
};

const [inputStatus, setInputStatus] = useState("default");
const [inputErrorMessage, setInputErrorMessage] = useState("");

const [isViewPassword, setIsViewPassword] = useState(false);

const onInputChangeHandler = (e: ChangeEvent<HTMLInputElement>) => {
const inputValue = e.target.value;
if (valueType === "email") {
setEmailValue?.(inputValue);
} else if (valueType === "password") {
setPasswordValue?.(inputValue);
}
};

const setInputStatusAndErrorMessage = (status: "valid" | ErrorType) => {
status === "valid"
? setInputStatus(INPUT_STATUS_VALUE.default)
: (setInputStatus(INPUT_STATUS_VALUE.error),
setInputErrorMessage(status.message));
};

const onInputFocusOutHandler = (e: ChangeEvent<HTMLInputElement>) => {
const inputValue = e.target.value;

switch (valueType) {
case "email":
emailInputFocusOutHandler(inputValue);
break;
case "password": {
passwordInputFocusOutHandler(inputValue);
break;
}
case "password2":
passwordConfirmInputFocusOutHandler(inputValue);
break;
default:
null;
}
};

const emailInputFocusOutHandler = async (email: string) => {
const emailInputStatus = emailInputValidationcheck(email);
setInputStatusAndErrorMessage(emailInputStatus);
if (emailInputStatus === "valid") {
setIsEmailValid?.(true);
if (signInStatus) {
const isDuplicateEmail = await emailDuplicationCheck(email);
isDuplicateEmail &&
setInputStatusAndErrorMessage(INPUT_STATUS.inUseEmail);
}
} else {
setIsEmailValid?.(false);
}
};

const passwordInputFocusOutHandler = async (password: string) => {
let passwordInputStatus;
if (loginStatus) {
passwordInputStatus = loginPasswordInputValidationcheck(password);
} else {
passwordInputStatus = signInPasswordInputValidationcheck(password);
}
setInputStatusAndErrorMessage(passwordInputStatus);
passwordInputStatus === "valid"
? setIsPasswordValid?.(true)
: setIsPasswordValid?.(false);
};

const passwordConfirmInputFocusOutHandler = async (password2: string) => {
const passwordInputStatus = signInPasswordInputValidationcheck(
passwordValue,
password2
);
setInputStatusAndErrorMessage(passwordInputStatus);
passwordInputStatus === "valid"
? setIsPasswordConfirmValid?.(true)
: setIsPasswordConfirmValid?.(false);
};

useEffect(() => {
if (loginStatus === "fail") {
valueType === "email"
? (setInputStatus(INPUT_STATUS_VALUE.error),
setInputErrorMessage(ERROR_MESSAGE.email.check))
: (setInputStatus(INPUT_STATUS_VALUE.error),
setInputErrorMessage(ERROR_MESSAGE.password.check));
}
}, [loginStatus]);

const onInputFocusHandler = () => {
setInputStatus("writing");
};

const KeyEventHandler = (e: KeyboardEvent<HTMLInputElement>) => {
const inputElement = e.target as HTMLInputElement;
if (e.key === "Enter") {
onEnterButtonClick();
inputElement.blur();
if(inputErrorInfo !== "valid") {
setInputErrorMessage(inputErrorInfo.message);
} else {
setInputErrorMessage('');
}
};

},[inputErrorInfo])

return (
<InputDiv>
<p>{title}</p>
<EmailPasswordInput
type={isViewPassword ? "text" : type}
status={inputStatus}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

type 도 string 보다 조금 더 구체적인 타입을 가지거나 기존 Input 의 type 프로퍼티를 확장하면 좋을 거 같아요!

onKeyDown={KeyEventHandler}
onChange={onInputChangeHandler}
onBlur={onInputFocusOutHandler}
onFocus={onInputFocusHandler}
inputErrorInfo={inputErrorInfo}
onChange={eventFunc.onChange}
onBlur={eventFunc.onFocusOut}
onKeyDown={eventFunc.onKeydown}
ref={inputRef}
/>
{isEyeIcon && (
{type==="password" && (
<EyeIconDiv
onClick={() => {
setIsViewPassword(!isViewPassword);
Expand All @@ -171,31 +62,24 @@ const EmailPwdInput = ({
<Image src={isViewPassword ? eyeon : eyeoff} alt="eye_off_icon" />
</EyeIconDiv>
)}
{inputStatus === "error" && (
{inputErrorMessage && (
<ErrorMessageDiv>{inputErrorMessage}</ErrorMessageDiv>
)}
</InputDiv>
);
};

type ErrorType =
| {
errorName: string;
type: string;
message: string;
}
| "valid";

const InputDiv = styled.div`
width: 100%;
margin-bottom: 24px;
position: relative;
`;
const EmailPasswordInput = styled.input<{ status: string }>`
const EmailPasswordInput = styled.input<{ inputErrorInfo: INPUT_ERROR_INFO }>`
width: 100%;
padding: 18px 15px;
border: ${({ status }) =>
`1px solid ${changeInputBorderColor(status) ?? "var(--Grey_300)"}`};
border: ${({ inputErrorInfo }) =>
`1px solid ${inputErrorInfo === "valid" ? "var(--Grey_300)" : "red"}`};
border-radius: 8px;
outline: none;
margin-top: 12px;
Expand Down
Empty file added components/SignInUp/Input.tsx
Empty file.
59 changes: 39 additions & 20 deletions components/common/FolderItem.tsx
Original file line number Diff line number Diff line change
@@ -1,35 +1,56 @@
import styled from "styled-components";
import { useState } from "react";
import { CalcTime } from "@/utils/calculator";
import Star from "@/assets/icons/card_star.svg";
import Kebab from "@/assets/icons/kebab.svg";
import logo from "@/assets/icons/logo.png";
import { calcTime } from "@/utils/calculator";
import Star from "@/public/assets/icons/card_star.svg";
import Kebab from "@/public/assets/icons/kebab.svg";
import logo from "@/public/assets/icons/logo.png";
import { PopOver } from "./modals/PopOver";
import Image from "next/image";
import styles from "@/styles/shared.module.css";
import Link from "next/link";
import { CommonFolderInfoProps } from "@/constants/commonTypes";
import { useModal } from "@/contexts/ModalContext";
import { DeleteModal } from "./modals/DeleteModal";
import { AddToFolder } from "./modals/AddToFolder";

interface FolderItemProps {
item: CommonFolderInfoProps;
$isModalVisible: string;
setIsModalVisible: any;
}

function FolderItem({
item,
$isModalVisible,
setIsModalVisible,
}: FolderItemProps) {
const { imageSource, createdAt, description, url, id } = item;
const { created_at, favorite, image_source } = item;
const [isPopOverVisible, setIsPopOverVisible] = useState(false);
const createdAtTime: string = String(createdAt ?? created_at);

const time = CalcTime(createdAtTime);
const time = calcTime(createdAtTime);
const img_src = image_source || imageSource;

const modal = useModal();

const openDeleteModal = () => {
modal.openModal(<DeleteModal />);
};
Comment on lines +33 to +35
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

컴포넌트 자체를 파라미터로 넘기면 나중에 추적할 때 복잡해져서 컴포넌트는 왠만하면 렌더부에만 선언하는 걸 추천드려요!


const openAddToFolderModal = () => {
modal.openModal(<AddToFolder />)
};

const POPOVER_INFO = [
{
option: "삭제하기",
callback: openDeleteModal
},
{
option: "폴더에 추가",
callback: openAddToFolderModal
}
]

return (
<a href={url} target="_blank" rel="noreferrer">
<Link href={url || './'} target="_blank" rel="noreferrer">
<Folder>
<ImageContainer>
{img_src ? (
Expand All @@ -49,25 +70,21 @@ function FolderItem({
e.preventDefault();
setIsPopOverVisible(!isPopOverVisible);
}}
/>
/>
<PopOver
$isPopOverVisible={isPopOverVisible}
setIsPopOverVisible={setIsPopOverVisible}
$options={["삭제하기", "폴더에 추가"]}
$modalType={["삭제", "폴더에 추가"]}
popOverInfo={POPOVER_INFO}
$top="20px"
$right="0px"
$isModalVisible={$isModalVisible}
setIsModalVisible={setIsModalVisible}
/>
</TimeContainer>
<Description>{description}</Description>

<DateText>2023. 3. 15</DateText>
</TextBox>{" "}
*
</Folder>
</a>
</TextBox>
</Folder>
</Link>
);
}

Expand Down Expand Up @@ -111,12 +128,13 @@ const DefaultImage = styled.div`

const TextBox = styled.div`
width: 100%;
height: 135px;
height: auto;
display: flex;
flex-direction: column;
gap: 10px;
padding: 15px 20px;
border-radius: 0px 0px 15px 15px;
text-decoration-line: none;
`;

const Description = styled.div`
Expand All @@ -129,6 +147,7 @@ const Description = styled.div`
line-height: 24px;
margin: 0px;
color: #000;
text-decoration: none;

display: -webkit-box;
-webkit-box-orient: vertical;
Expand Down
Loading
Loading