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

chacha-FE-lecture1,2,3 #1

Open
wants to merge 38 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 30 commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
a49ed0c
feat: add ItemNumberInput.tsx
ChaeyeonAhn Jul 21, 2024
d61fa1b
feat: start off TextInput.tsx
ChaeyeonAhn Jul 21, 2024
b377b14
feat: add test methods
ChaeyeonAhn Jul 21, 2024
f187ebd
feat: work on disabled and default
ChaeyeonAhn Jul 21, 2024
3e8e558
feat: impl disabled case TextInput.tsx
ChaeyeonAhn Jul 22, 2024
fee8fe2
feat: finish TextInput.tsx
ChaeyeonAhn Jul 22, 2024
917e0b8
feat: impl TextInput.tsx done
ChaeyeonAhn Jul 22, 2024
31d5118
feat: start ItemNumberInput.tsx
ChaeyeonAhn Jul 22, 2024
217e4ee
feat: finish TextInput.tsx
ChaeyeonAhn Jul 22, 2024
64b6c01
feat: work on examples
ChaeyeonAhn Jul 22, 2024
8ce2443
feat: ItemNumberInput not erased other works well
ChaeyeonAhn Jul 22, 2024
411fd61
feat: set up my/page.tsx
ChaeyeonAhn Jul 24, 2024
fa0a56c
feat: infoFrame set up
ChaeyeonAhn Jul 25, 2024
be92054
feat: infoFrame quite done?
ChaeyeonAhn Jul 25, 2024
4042682
feat: work on club frame
ChaeyeonAhn Jul 25, 2024
317723e
feat: add clubCardList
ChaeyeonAhn Jul 27, 2024
45256f6
feat: delete main frame and add /my/clubs
ChaeyeonAhn Jul 27, 2024
4d1dab8
feat: add service frame and toggle
ChaeyeonAhn Jul 27, 2024
4ae0a64
feat: add toggle handler and add /chacha/my/clubs and service frame
ChaeyeonAhn Jul 27, 2024
59e97b8
feat: delete MainFrame
ChaeyeonAhn Jul 27, 2024
8a1f407
feat: fix color in error case and flexwrapper
ChaeyeonAhn Jul 29, 2024
598aeb2
feat: add chachaMockMyClub.ts
ChaeyeonAhn Aug 2, 2024
4c49460
feat: add acfmockup
ChaeyeonAhn Aug 2, 2024
284db54
feat: add cmsmockup
ChaeyeonAhn Aug 2, 2024
c98a073
feat: add mock my club
ChaeyeonAhn Aug 2, 2024
fd40f6d
feat: add import
ChaeyeonAhn Aug 2, 2024
8ddfd14
feat: add phone mock up and import
ChaeyeonAhn Aug 2, 2024
5550ef5
feat: add - inside phone number and add handle change
ChaeyeonAhn Aug 2, 2024
cb55fbf
feat: delete comments
ChaeyeonAhn Aug 2, 2024
2a42cf3
feat: add all variations
ChaeyeonAhn Aug 2, 2024
484b275
feat: resolve review comments
ChaeyeonAhn Aug 10, 2024
2e30823
feat: fix foldable feature using ClubsSectionFrame
ChaeyeonAhn Aug 10, 2024
a508a35
feat: fix on club detail title
ChaeyeonAhn Aug 10, 2024
e49d5df
feat: add useGetMyRental.ts
ChaeyeonAhn Aug 11, 2024
0dad88d
feat: add useGetMyAcf.ts
ChaeyeonAhn Aug 11, 2024
15a3c7c
feat: add useGetMyPrt.ts
ChaeyeonAhn Aug 11, 2024
3b92a5d
feat: add useGetMyCms and fix zod error
ChaeyeonAhn Aug 11, 2024
e7ab301
feat: add useGetMyUser.ts
ChaeyeonAhn Aug 11, 2024
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
"use client";

import React from "react";

import ClubListGrid from "@sparcs-clubs/web/features/clubs/components/ClubListGrid";
import FlexWrapper from "@sparcs-clubs/web/common/components/FlexWrapper";
import FoldableSectionTitle from "@sparcs-clubs/web/common/components/FoldableSectionTitle";
import PageHead from "@sparcs-clubs/web/common/components/PageHead";
import mockMyClubList from "@sparcs-clubs/web/features/my/clubs/service/_mock/mockMyClubList";

const ChachaMyClubs = () => (
<FlexWrapper direction="column" gap={60}>
<PageHead
items={[
{ name: "마이페이지", path: "/my" },
{ name: "나의 동아리", path: "/my/clubs" },
]}
title="나의 동아리"
/>
{mockMyClubList.semesters.map(e => (
<React.Fragment key={e.id}>
<FoldableSectionTitle title={e.name} />
<ClubListGrid clubList={e.clubs} />
ChaeyeonAhn marked this conversation as resolved.
Show resolved Hide resolved
</React.Fragment>
))}
</FlexWrapper>
);

export default ChachaMyClubs;
25 changes: 25 additions & 0 deletions 2024-summer-FE-seminar/packages/web/src/app/chacha/my/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
"use client";

import React from "react";

import styled from "styled-components";

import PageHead from "@sparcs-clubs/web/common/components/PageHead";
import ChachaMyInfoFrame from "@sparcs-clubs/web/features/my/frame/_atomic/ChachaMyInfoFrame";
import ChachaMyClubFrame from "@sparcs-clubs/web/features/my/frame/_atomic/ChachaMyClubFrame";
import ChachaMyServiceFrame from "@sparcs-clubs/web/features/my/frame/_atomic/ChachaMyServiceFrame";
import FlexWrapper from "@sparcs-clubs/web/common/components/FlexWrapper";

const ChachaMy = () => (
<FlexWrapper direction="column" gap={60}>
<PageHead
items={[{ name: "마이페이지", path: "/my" }]}
title="마이페이지"
/>
<ChachaMyInfoFrame />
<ChachaMyClubFrame />
<ChachaMyServiceFrame />
</FlexWrapper>
);

export default ChachaMy;
44 changes: 44 additions & 0 deletions 2024-summer-FE-seminar/packages/web/src/app/chacha/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
"use client";

import React, { useState, useEffect } from "react";

import TextInput from "@sparcs-clubs/web/common/components/chacha/TextInput";
import ItemNumberInput from "@sparcs-clubs/web/common/components/chacha/ItemNumberInput";

import FlexWrapper from "@sparcs-clubs/web/common/components/FlexWrapper";

const Chacha = () => {
const [inputText, setInputText] = useState("");
const [inputNumber, setInputNumber] = useState("");

useEffect(() => {
setInputText(inputText);
}, [inputText]);
return (
<FlexWrapper direction="column" gap={16}>
<TextInput disabled inputValue={inputText} setInputValue={setInputText} />
<TextInput
disabled={false}
placeholder="내용"
inputValue={inputText}
setInputValue={setInputText}
/>
<TextInput
disabled={false}
placeholder="내용"
errorMessage="에러 메세지"
inputValue={inputText}
setInputValue={setInputText}
/>
ChaeyeonAhn marked this conversation as resolved.
Show resolved Hide resolved
<ItemNumberInput
disabled={false}
placeholder="내용"
label="Label"
input={inputNumber}
setInputValue={setInputNumber}
/>
</FlexWrapper>
);
};

export default Chacha;
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
import React, { useEffect, useState } from "react";

import styled from "styled-components";

import Label from "../FormLabel";

import FormError from "../FormError";

import InfoOutlinedIcon from "@mui/icons-material/InfoOutlined";

interface ItemNumberInputProps
extends InputHTMLAttributes<HTMLInputElement | HTMLTextAreaElement> {
constraint?: number;
disabled: boolean;
error?: boolean;
placeholder: string;
label: string;
input?: string;
setInputValue?: (inputValue: string) => void;
}

const ItemInputWrapper = styled.div`
display: flex;
flex-direction: column;
align-items: flex-start;
gap: 4px;
`;

const ItemLabel = styled.div`
display: flex;
padding: 0px 2px;
align-items: center;
gap: 4px;
align-self: stretch;
`;

const Icon = styled(InfoOutlinedIcon)`
color: ${({ theme }) => theme.colors.GRAY[300]};
cursor: pointer;
width: 16px;
height: 16px;
`;

const ItemInputInner = styled.div`
display: flex;
align-items: center;
align-self: stretch;
`;

const ItemInput = styled.input`
width: 100%;
border-radius: 4px;
padding: 8px 12px;
border: 1px solid ${({ theme }) => theme.colors.GRAY[200]};
background: ${({ theme }) => theme.colors.WHITE};
z-index: 0;
font-family: ${({ theme }) => theme.fonts.FAMILY.PRETENDARD};
font-size: 16px;
font-style: normal;
font-weight: ${({ theme }) => theme.fonts.WEIGHT.REGULAR};
line-height: 20px;
&:focus {
outline: none;
border: 1px solid
${({ theme, error, disabled }) =>
(!error && !disabled && theme.colors.PRIMARY) ||
(error && !disabled && theme.colors.RED[600])};
}
&:hover:not(:focus) {
border: 1px solid
${({ theme, disabled, error }) =>
disabled
? !error && theme.colors.GRAY[200]
: (!error && theme.colors.GRAY[300]) ||
(error && theme.colors.RED[600])};
}
&::placeholder {
color: ${({ theme }) => theme.colors.GRAY[200]};
}
${({ disabled, theme }) =>
`background-color: ${disabled ? theme.colors.GRAY[100] : theme.colors.WHITE};
color: ${disabled ? theme.colors.GRAY[300] : theme.colors.BLACK};`}

${({ error, theme }) =>
error
? `border: 1px solid ${theme.colors.RED[600]};
color: ${theme.colors.RED[600]}`
: ``};
`;

const ItemInputConstraint = styled.div`
ChaeyeonAhn marked this conversation as resolved.
Show resolved Hide resolved
display: flex;
white-space: nowrap;
position: relative;
right: 60px;
color: ${({ theme }) => theme.colors.GRAY[300]};
font-family: ${({ theme }) => theme.fonts.FAMILY.PRETENDARD};
font-size: 16px;
font-style: normal;
font-weight: ${({ theme }) => theme.fonts.WEIGHT.REGULAR};
line-height: 20px;
z-index: 1;
`;

const ItemNumberInput: React.FC<ItemNumberInputProps> = ({
constraint = 99,
disabled,
error = false,
placeholder,
label,
input = "",
setInputValue = () => {},
}) => {
const [errorMessage, setErrorMessage] = useState("");
const [shownValue, setShownValue] = useState("");

useEffect(() => {
if (input === "") return;
setShownValue(`${input}개`);
}, [input, shownValue]);
// useEffect(() => {
// const digitTest = /^\d*$/g.test(input);
// console.log(input);
// const inputNumber = parseInt(input);

// if (input === "") {
// setErrorMessage("");
// } else if (!digitTest) {
// setErrorMessage("숫자만 입력 가능합니다");
// console.log(digitTest);
// } else if (inputNumber > constraint) {
// setErrorMessage("신청 가능 갯수를 초과했습니다");
// console.log(constraint);
// console.log(inputNumber);
// } else {
// setErrorMessage("");
// }
// setInputValue(input);
// }, [input, constraint]);

const handleChange = (e: ChangeEvent<HTMLInputElement>) => {
setShownValue(input);
const value = e.target.value.replace("개", "");
const digitTest = /^\d*$/g.test(value);

const inputValue = e.target.value.replace(/[^0-9]/g, "");
console.log(e.target.value);
const inputNumber = parseInt(inputValue);
ChaeyeonAhn marked this conversation as resolved.
Show resolved Hide resolved

if (value === "") {
setErrorMessage("");
setInputValue("");
} else if (!digitTest) {
setShownValue("");
setInputValue("");
setErrorMessage("숫자만 입력 가능합니다");
} else if (inputNumber > constraint) {
setErrorMessage("신청 가능 갯수를 초과했습니다");
setInputValue(inputValue);
setShownValue(`${inputValue}개`);
} else {
setErrorMessage("");
setInputValue(inputValue);
setShownValue(`${inputValue}개`);
}
};

// const handleChange = (e: ChangeEvent<HTMLInputElement>) => {
// const inputValue = e.target.value.replace("개", "");
// console.log(input);
// setInputValue(inputValue);
// };

return (
<ItemInputWrapper>
<ItemLabel>
{label && <Label>{label}</Label>}
<Icon style={{ fontSize: "16px" }} />
</ItemLabel>
<ItemInputInner error={!!errorMessage}>
<ItemInput
placeholder={placeholder}
disabled={disabled}
placeholder={placeholder}
value={shownValue}
onChange={handleChange}
error={!!errorMessage}
/>
<ItemInputConstraint>/ {constraint}개</ItemInputConstraint>
</ItemInputInner>
{errorMessage && <FormError>{errorMessage}</FormError>}
</ItemInputWrapper>
);
};

export default ItemNumberInput;
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
"use client";

import React, { ChangeEvent, InputHTMLAttributes, useEffect } from "react";

import styled from "styled-components";

import FormError from "../FormError";

import Typography from "@sparcs-clubs/web/common/components/Typography";

interface TextInputProps
extends InputHTMLAttributes<HTMLInputElement | HTMLTextAreaElement> {
// 의미 : HTML 요소의 기본 속성을 쓸 수 있음.
disabled: boolean;
error?: boolean;
errorMessage?: string;
placeholder: string;
inputValue?: string;
onValueChange?: (inputValue: string) => void;
}

const TextInputInner = styled.input`
display: flex;
width: 300px;
padding: 8px 12px;
justify-content: center;
align-items: center;
gap: 8px;
border-radius: 4px;
border: 1px solid ${({ theme }) => theme.colors.GRAY[200]};
background: ${({ theme }) => theme.colors.WHITE};
&:focus {
outline: none;
border: 1px solid
${({ theme, error, disabled }) =>
(!error && !disabled && theme.colors.PRIMARY) ||
(error && !disabled && theme.colors.RED[600])};
}
&:hover:not(:focus) {
border: 1px solid
${({ theme, disabled, error }) =>
disabled
? !error && theme.colors.GRAY[200]
: (!error && theme.colors.GRAY[300]) ||
(error && theme.colors.RED[600])};
}
&::placeholder {
color: ${({ theme }) => theme.colors.GRAY[200]};
}
${({ disabled, theme }) =>
`background-color: ${disabled ? theme.colors.GRAY[100] : theme.colors.WHITE};
color: ${disabled ? theme.colors.GRAY[300] : theme.colors.BLACK};`}

${({ error, theme }) =>
error ? `border: 1px solid ${theme.colors.RED[600]};` : ``}

font-family: ${({ theme }) => theme.fonts.FAMILY.PRETENDARD};
font-size: 16px;
font-style: normal;
font-weight: ${({ theme }) => theme.fonts.WEIGHT.REGULAR};
line-height: 20px;
`;

const TextInputWrapper = styled.div`
display: flex;
width: 300px;
flex-direction: column;
align-items: flex-start;
gap: 4px;
`;

const TextInput: React.FC<TextInputProps> = ({
disabled,
error = false,
errorMessage = "",
placeholder,
inputValue = "", // 의미: api 연결 시 필요, 모듈화 목적?
setInputValue = () => {}, // 의미: 필요한 함수 대입 사용.
}) => {
// 코드 참고
const handleChange = (e: ChangeEvent<HTMLInputElement>) => {
const input = e.target.value;
setInputValue(input);
};

return (
<TextInputWrapper>
<TextInputInner
disabled={disabled}
error={!!errorMessage}
placeholder={placeholder}
value={inputValue}
onChange={handleChange}
/>
{errorMessage && <FormError>{errorMessage}</FormError>}
</TextInputWrapper>
);
};
export default TextInput;
Loading