Skip to content

Commit

Permalink
Merge branch 'develop' into feat/#66/NarrowDropDown
Browse files Browse the repository at this point in the history
  • Loading branch information
ocahs9 authored Jul 13, 2024
2 parents 02bc722 + 6986d50 commit 15ad97a
Show file tree
Hide file tree
Showing 40 changed files with 936 additions and 75 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ node_modules
dist
dist-ssr
*.local
.env

# Editor directories and files
.vscode
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
"@mui/icons-material": "^5.16.0",
"@mui/material": "^5.16.0",
"@mui/x-date-pickers": "^7.9.0",
"axios": "^1.7.2",
"dayjs": "^1.11.11",
"jotai": "^2.8.4",
"postcss": "^8.4.38",
Expand Down
9 changes: 9 additions & 0 deletions public/svgs/empty.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
10 changes: 10 additions & 0 deletions public/svgs/icon_eye_on.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import theme from "@styles/theme";
import { RouterProvider } from "react-router-dom";
import { ThemeProvider } from "styled-components";

import Modal from "@components/commons/modal/Modal";
import { ThemeProvider as MuiThemeProvider, createTheme } from "@mui/material/styles";

const darkTheme = createTheme({
Expand All @@ -23,6 +24,7 @@ function App() {
<LocalizationProvider dateAdapter={AdapterDayjs}>
<GlobalStyle />
<RouterProvider router={router} />
<Modal />
<Alert />
<Confirm />
</LocalizationProvider>
Expand Down
14 changes: 14 additions & 0 deletions src/apis/kakoLogin/getKakaoData.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import axios from "axios";

export const getData = async (token: string) => {
try {
const res = await axios.get("https://kapi.kakao.com/v2/user/me", {
headers: {
Authorization: `Bearer ${token}`,
},
});
return await res.data;
} catch (error) {
console.log(error);
}
};
25 changes: 25 additions & 0 deletions src/apis/kakoLogin/postKakaoToken.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import axios from "axios";

export const getToken = async (code: string) => {
const grant_type = "authorization_code";
const REST_API = import.meta.env.VITE_REST_API;
const REDIRECT_URI = "http://localhost:5173/auth";
const AUTHORIZE_CODE = code;

try {
const res = await axios.post(
`https://kauth.kakao.com/oauth/token?grant_type=${grant_type}&client_id=${REST_API}&redirect_uri=${REDIRECT_URI}&code=${AUTHORIZE_CODE}`,
{
headers: {
"Content-type": "application/x-www-form-urlencoded;charset=utf-8",
},
}
);

const token = res.data.access_token;

return token;
} catch (error) {
console.log(error);
}
};
52 changes: 52 additions & 0 deletions src/assets/svgs/Empty.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import * as React from "react";
import type { SVGProps } from "react";
const SvgEmpty = (props: SVGProps<SVGSVGElement>) => (
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 150 150" {...props}>
<rect
width={14.319}
height={17.183}
fill="#3E3E3E"
rx={4}
transform="scale(-1 1)rotate(-25.907 -19.855 294.567)"
/>
<rect
width={8.592}
height={2.864}
fill="#3E3E3E"
rx={1.432}
transform="scale(-1 1)rotate(-25.907 -27.514 289.78)"
/>
<rect
width={14.319}
height={17.183}
x={20.252}
y={20.929}
fill="#3E3E3E"
rx={4}
transform="rotate(-25.907 20.252 20.93)"
/>
<rect
width={8.592}
height={2.864}
x={21.574}
y={17.102}
fill="#3E3E3E"
rx={1.432}
transform="rotate(-25.907 21.574 17.102)"
/>
<path
fill="#fff"
fillOpacity={0.2}
d="M48.323 124.032 116.5 32.499l-14.057 91.534z"
opacity={0.1}
/>
<path
fill="#fff"
fillOpacity={0.2}
d="M102.626 124.032 34.449 32.5l14.057 91.533z"
opacity={0.1}
/>
<ellipse cx={75.5} cy={124} fill="#3E3E3E" rx={27.5} ry={3} />
</svg>
);
export default SvgEmpty;
1 change: 0 additions & 1 deletion src/assets/svgs/IconArrowRight.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import type { SVGProps } from "react";
const SvgIconArrowRight = (props: SVGProps<SVGSVGElement>) => (
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" {...props}>
<path
fill="#fff"
fillRule="evenodd"
d="M7.83 19.546a1.125 1.125 0 0 1 0-1.591L13.784 12 7.83 6.045a1.125 1.125 0 1 1 1.59-1.59l6.75 6.75c.44.439.44 1.151 0 1.59l-6.75 6.75c-.439.44-1.151.44-1.59 0"
clipRule="evenodd"
Expand Down
20 changes: 20 additions & 0 deletions src/assets/svgs/IconEyeOn.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import * as React from "react";
import type { SVGProps } from "react";
const SvgIconEyeOn = (props: SVGProps<SVGSVGElement>) => (
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" {...props}>
<g clipPath="url(#icon_eye_on_svg__a)">
<path
fill="#F4F4F4"
fillRule="evenodd"
d="M4.8 12.299v.002a1 1 0 0 0 .086.25q.158.337.381.636c.358.498.894 1.073 1.57 1.619C8.2 15.904 10.03 16.8 12 16.8s3.802-.896 5.162-1.995c.677-.546 1.213-1.12 1.57-1.618q.222-.301.383-.638c.067-.149.081-.228.085-.247v-.005a1 1 0 0 0-.085-.247 3.8 3.8 0 0 0-.382-.637c-.358-.498-.894-1.073-1.57-1.619C15.8 8.696 13.968 7.8 12 7.8s-3.8.896-5.162 1.996c-.677.546-1.213 1.12-1.57 1.618-.18.25-.305.466-.382.638-.068.149-.082.228-.086.247m.908-3.906C7.277 7.13 9.495 6 12 6s4.723 1.129 6.292 2.393c.79.636 1.44 1.327 1.902 1.968q.328.447.563.95c.132.295.243.64.243.989 0 .35-.11.694-.244.99-.139.307-.331.628-.562.949-.462.641-1.113 1.332-1.902 1.968C16.723 17.47 14.505 18.6 12 18.6s-4.723-1.129-6.292-2.393c-.79-.636-1.44-1.327-1.902-1.968a5.6 5.6 0 0 1-.563-.95C3.111 12.994 3 12.65 3 12.3c0-.35.11-.693.244-.99q.232-.502.562-.949c.462-.641 1.113-1.333 1.902-1.968m4.383 1.998a2.7 2.7 0 1 1 3.818 3.818 2.7 2.7 0 0 1-3.818-3.818"
clipRule="evenodd"
/>
</g>
<defs>
<clipPath id="icon_eye_on_svg__a">
<path fill="#fff" d="M0 0h24v24H0z" />
</clipPath>
</defs>
</svg>
);
export default SvgIconEyeOn;
2 changes: 2 additions & 0 deletions src/assets/svgs/index.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export { default as Empty } from "./Empty";
export { default as IcHamburgar } from "./IcHamburgar";
export { default as IcomCopy } from "./IcomCopy";
export { default as IconArrowDown } from "./IconArrowDown";
Expand All @@ -11,6 +12,7 @@ export { default as IconCheckboxSelectedOn } from "./IconCheckboxSelectedOn";
export { default as IconCheckboxUnselectedOn } from "./IconCheckboxUnselectedOn";
export { default as IconChevronBack } from "./IconChevronBack";
export { default as IconEyeOff } from "./IconEyeOff";
export { default as IconEyeOn } from "./IconEyeOn";
export { default as IconHanna } from "./IconHanna";
export { default as IconIbk } from "./IconIbk";
export { default as IconIm } from "./IconIm";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,23 +1,34 @@
import * as S from "./PhoneNumber.styled";
import { IconCheck } from "@assets/svgs";

import Toast from "@components/commons/toast/Toast";
import useToast from "@hooks/useToast";

interface PhoneNumProps {
phone?: string;
}

const PhoneNumber = ({ phone }: PhoneNumProps) => {
const { showToast, isToastVisible } = useToast();

const handleCopyClipBoard = (text: string) => {
navigator.clipboard.writeText(text);
// 현재 토스트 메시지가 없어 간단한 alert로 대체. 후에 수정 필요
alert(`${text} 클립보드에 복사.`);

showToast();
};

return (
<S.PhoneNumWrapper>
<S.PhoneNumLayout type="button" onClick={() => handleCopyClipBoard(phone || "")}>
<S.PhoneNum>{phone}</S.PhoneNum>
<S.Copy />
</S.PhoneNumLayout>
</S.PhoneNumWrapper>
<>
<S.PhoneNumWrapper>
<S.PhoneNumLayout type="button" onClick={() => handleCopyClipBoard(phone || "")}>
<S.PhoneNum>{phone}</S.PhoneNum>
<S.Copy />
</S.PhoneNumLayout>
</S.PhoneNumWrapper>
<Toast icon={<IconCheck />} isVisible={isToastVisible} toastBottom={30}>
클립보드에 복사되었습니다!
</Toast>
</>
);
};

Expand Down
7 changes: 7 additions & 0 deletions src/components/commons/input/textField/TextField.styled.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,13 @@ export const TextUnit = styled.p`
${({ theme }) => theme.fonts["body2-normal-medi"]};
`;

export const ToggleVisibilityIcon = styled.section`
position: absolute;
right: 1.6rem;
width: 2.4rem;
`;

export const TextCap = styled.p`
${Generators.flexGenerator("row", "center", "end")}
Expand Down
23 changes: 21 additions & 2 deletions src/components/commons/input/textField/TextField.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import React, { ChangeEvent, InputHTMLAttributes, useRef } from "react";
import React, { ChangeEvent, InputHTMLAttributes, useRef, useState } from "react";
import * as S from "./TextField.styled";
import { IconEyeOff, IconEyeOn } from "@assets/svgs";

export interface TextFieldProps extends InputHTMLAttributes<HTMLInputElement> {
onChange: (e: React.ChangeEvent<HTMLInputElement>) => void;
Expand All @@ -9,9 +10,11 @@ export interface TextFieldProps extends InputHTMLAttributes<HTMLInputElement> {
unit?: "time" | "ticket" | "amount"; // 단위 : "분", "매", "원"
filter?: (value: string) => string;
cap?: false | true;
onToggleClick?: () => void;
}

const TextField = ({
type = "input",
name,
value,
onChange,
Expand All @@ -21,11 +24,13 @@ const TextField = ({
unit,
filter,
cap,
onToggleClick,
...rest
}: TextFieldProps) => {
const label = unit === "time" ? "분" : unit === "ticket" ? "매" : "원";

const inputRef = useRef<HTMLInputElement>(null);
const [isPasswordVisible, setIsPasswordVisible] = useState(type !== "password"); // 비밀번호 입력값 보이기/숨기기

// 값 입력될 떄
const handleOnInput = (e: ChangeEvent<HTMLInputElement>) => {
Expand Down Expand Up @@ -70,6 +75,11 @@ const TextField = ({
}
};

// 비밀번호 입력값 보이기 여부 관리
const handlePasswordVisibility = () => {
setIsPasswordVisible((prev) => !prev);
};

return (
<S.TextFieldLayout narrow={narrow}>
<S.TextFieldWrapper>
Expand All @@ -80,10 +90,19 @@ const TextField = ({
onChange={handleOnInput}
maxLength={maxLength}
placeholder={placeholder}
type={isPasswordVisible ? "text" : "password"} // 비밀번호 보이기 여부를 위해 타입에 조건을 걸음
{...rest}
/>
{!narrow && !unit && value && <S.TextClear onClick={handleClearInput} />}
{!narrow && !unit && value && type !== "password" && (
<S.TextClear onClick={handleClearInput} />
)}
{unit && <S.TextUnit>{label}</S.TextUnit>}
{type === "password" && (
<S.ToggleVisibilityIcon
onClick={handlePasswordVisibility}
as={isPasswordVisible ? IconEyeOn : IconEyeOff}
/>
)}
</S.TextFieldWrapper>
{maxLength && cap && <S.TextCap>{`${(value as string).length}/${maxLength}`}</S.TextCap>}
</S.TextFieldLayout>
Expand Down
2 changes: 1 addition & 1 deletion src/components/commons/modal/Alert.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ const Alert = () => {

if (isOpen) {
return (
<ModalWrapper type="alert">
<ModalWrapper>
<ModalTextBox title={title} subTitle={subTitle} />

<Button size="large" variant="primary" onClick={handleOk}>
Expand Down
2 changes: 1 addition & 1 deletion src/components/commons/modal/Confirm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ const Confirm = () => {

if (isOpen) {
return (
<ModalWrapper type="confirm">
<ModalWrapper>
<ModalTextBox title={title} subTitle={subTitle} />

<S.ButtonWrapper>
Expand Down
16 changes: 16 additions & 0 deletions src/components/commons/modal/Modal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { modalAtom } from "@stores/modal";
import { useAtomValue } from "jotai";
import ModalWrapper from "./components/ModalWrapper";

const Modal = () => {
const modal = useAtomValue(modalAtom);
const { isOpen, children } = modal;

if (isOpen) {
return <ModalWrapper>{children}</ModalWrapper>;
}

return <></>;
};

export default Modal;
32 changes: 4 additions & 28 deletions src/components/commons/modal/components/ModalWrapper.tsx
Original file line number Diff line number Diff line change
@@ -1,38 +1,14 @@
import useModal from "@hooks/useModal";
import React, { useRef } from "react";
import React from "react";
import * as S from "./ModalWrapper.styled";

interface ModalWrapperProps {
children: React.ReactNode;
type: "alert" | "confirm" | "modal";
}

const ModalWrapper = ({ children, type }: ModalWrapperProps) => {
const { closeAlert, closeConfirm } = useModal();
const containerRef = useRef<HTMLDivElement>(null);

const closeModal = () => {
switch (type) {
case "alert":
closeAlert();
return;
case "confirm":
closeConfirm();
return;
default:
return;
}
};

const handleClickOutside = (e: React.MouseEvent<HTMLDivElement, MouseEvent>) => {
if (containerRef.current && !containerRef.current.contains(e.target as Node)) {
closeModal();
}
};

const ModalWrapper = ({ children }: ModalWrapperProps) => {
return (
<S.ModalWrapper onClick={handleClickOutside}>
<S.ModalContainer ref={containerRef}>{children}</S.ModalContainer>
<S.ModalWrapper>
<S.ModalContainer>{children}</S.ModalContainer>
</S.ModalWrapper>
);
};
Expand Down
Loading

0 comments on commit 15ad97a

Please sign in to comment.