-
Notifications
You must be signed in to change notification settings - Fork 1
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
[FE] assignment : Daystar #4
Open
jinhyeonkwon
wants to merge
15
commits into
main
Choose a base branch
from
daystar
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 7 commits
Commits
Show all changes
15 commits
Select commit
Hold shift + click to select a range
af75fa7
Feat daystar's assignment with some modification on app.ts
jinhyeonkwon 944c52a
Merge branch 'main' into daystar
jinhyeonkwon 94bcc99
After merge of main
jinhyeonkwon 58ce382
feat: start implementing TextInput
jinhyeonkwon 55c9159
feat: Done for InputText without label
jinhyeonkwon 5ef443b
feat: impl DaystarItemNumberInput without unit or cursor support
jinhyeonkwon 3439c37
feat: unit and cursor support on DaystarItemNumberInput and add link …
jinhyeonkwon 3b0a52d
feat: add label on DaystarItemNumberInput
jinhyeonkwon 714a551
feat: [2nd assignment] implement 'Daystar/my' page
jinhyeonkwon eea0918
refactor: reflect comments on 1st assignment
jinhyeonkwon 215eee8
feat: custom MyServiceFrame using API call
jinhyeonkwon 445b7fa
fix: connection error due to absence of coerce
jinhyeonkwon 91003c0
feat: impl myInfo API connection
jinhyeonkwon 19d5f20
fix: type issue of button type state
jinhyeonkwon 2168527
fix: deps on useEffect
jinhyeonkwon File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
78 changes: 78 additions & 0 deletions
78
2024-summer-FE-seminar/packages/web/src/app/Daystar/page.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
"use client"; | ||
|
||
import React, { useState } from "react"; | ||
import styled from "styled-components"; | ||
|
||
import Card from "@sparcs-clubs/web/common/components/Card"; | ||
import DaystarItemNumberInput from "@sparcs-clubs/web/common/components/Daystar/DaystarItemNumberInput"; | ||
import DaystarTextInput from "@sparcs-clubs/web/common/components/Daystar/DaystarTextInput"; | ||
import ItemNumberInput from "@sparcs-clubs/web/common/components/Forms/ItemNumberInput"; | ||
import TextInput from "@sparcs-clubs/web/common/components/Forms/TextInput"; | ||
import Select from "@sparcs-clubs/web/common/components/Select"; | ||
import Typography from "@sparcs-clubs/web/common/components/Typography"; | ||
|
||
const DaystarWrapper = styled.div` | ||
display: flex; | ||
flex-direction: column; | ||
gap: 8px; | ||
`; | ||
|
||
const Daystar = () => { | ||
const [firstText, setFirstText] = useState(""); | ||
const [secondText, setSecondText] = useState(""); | ||
const [firstItemNumber, setFirstItemNumber] = useState("0"); | ||
|
||
const [secondHasError, setSecondHasError] = useState(true); | ||
|
||
const handleSecondTextChange = (value: string) => { | ||
setSecondText(value); | ||
setSecondHasError(value.length < 5); // 5글자보다 짧으면 에러 뜨는 것으로 테스트 | ||
}; | ||
Comment on lines
+29
to
+32
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. (optional) 여기서 이 input을 한 번도 클릭하지 않았을 때는 에러가 안 뜨게 하려면 어떻게 해야할까요! There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
|
||
const handleFirstItemNumberChange = (value: string) => { | ||
setFirstItemNumber(value); | ||
}; | ||
|
||
return ( | ||
<DaystarWrapper> | ||
<TextInput placeholder="" /> | ||
<ItemNumberInput placeholder="" /> | ||
<Select items={[]} /> | ||
<Card outline gap={16}> | ||
<Typography type="h3">부모 컴포넌트가 받는 값들</Typography> | ||
<Typography> | ||
입력 값들 | ||
<br /> | ||
{`1번째 InputText : ${firstText}`} | ||
<br /> | ||
{`2번째 InputText : ${secondText}`} | ||
<br /> | ||
{`1번째 ItemNumberInput : ${firstItemNumber}`} | ||
</Typography> | ||
</Card> | ||
<DaystarTextInput placeholder="Placeholder" handleChange={setFirstText} /> | ||
<DaystarTextInput | ||
placeholder="5글자 미만이면 Error" | ||
errorMessage={secondHasError ? "5글자 이상 입력해주세요" : ""} | ||
handleChange={handleSecondTextChange} | ||
/> | ||
<DaystarTextInput placeholder="Disabled" disabled /> | ||
<DaystarItemNumberInput | ||
value={firstItemNumber} | ||
itemLimit={50} | ||
unit="개" | ||
placeholder="0개" | ||
handleChange={handleFirstItemNumberChange} | ||
/> | ||
<DaystarItemNumberInput | ||
itemLimit={50} | ||
disabled | ||
unit="개" | ||
placeholder="0개" | ||
handleChange={handleFirstItemNumberChange} | ||
/> | ||
</DaystarWrapper> | ||
); | ||
}; | ||
|
||
export default Daystar; |
191 changes: 191 additions & 0 deletions
191
2024-summer-FE-seminar/packages/web/src/common/components/Daystar/DaystarItemNumberInput.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,191 @@ | ||
import React, { | ||
ChangeEvent, | ||
InputHTMLAttributes, | ||
useEffect, | ||
useRef, | ||
useState, | ||
} from "react"; | ||
|
||
import isPropValid from "@emotion/is-prop-valid"; | ||
import styled, { css } from "styled-components"; | ||
|
||
import FormError from "@sparcs-clubs/web/common/components/FormError"; | ||
|
||
// import FormError from "../FormError"; | ||
// import Typography from "../Typography"; | ||
|
||
export interface DaystarItemNumberInputProps | ||
extends InputHTMLAttributes<HTMLInputElement | HTMLTextAreaElement> { | ||
placeholder?: string; | ||
// hasError?: boolean; <- 이건 errorMessage의 존재 여부로 판단합니다 | ||
disabled?: boolean; | ||
unit?: string; // 단위 | ||
value?: string; // 입력 값 | ||
itemLimit?: number; // 최대 수량 | ||
handleChange?: (value: string) => void; // 값이 변할 때 상위 컴포넌트의 함수를 호출할 수 있도록 | ||
setErrorStatus?: (hasError: boolean) => void; // 에러 상태를 상위 컴포넌트에 전달 | ||
} | ||
|
||
const errorStyle = css` | ||
border: 1px solid ${({ theme }) => theme.colors.RED[600]}; | ||
&:focus { | ||
border: 1px solid ${({ theme }) => theme.colors.RED[600]}; | ||
} | ||
`; | ||
|
||
const disabledStyle = css` | ||
background: ${({ theme }) => theme.colors.GRAY[100]}; | ||
color: ${({ theme }) => theme.colors.GRAY[300]}; | ||
`; | ||
|
||
const Input = styled.input.withConfig({ | ||
shouldForwardProp: prop => isPropValid(prop), | ||
// 왜 InputText에서는 검사하지 않는지는 잘 모르겠습니다. 우선 코드를 가져왔습니다. | ||
// 여기서는 textarea가 될 상황이 없어서 attrs는 사용하지 않습니다. | ||
})<DaystarItemNumberInputProps & { hasError: boolean }>` | ||
width: 100%; | ||
display: flex; | ||
padding: 8px 12px; | ||
justify-content: center; | ||
align-items: center; | ||
gap: 8px; | ||
align-self: stretch; | ||
border-radius: 4px; | ||
color: ${({ theme }) => theme.colors.BLACK}; | ||
font-family: Pretendard; | ||
font-size: 16px; | ||
font-style: normal; | ||
font-weight: 400; | ||
line-height: 20px; | ||
jinhyeonkwon marked this conversation as resolved.
Show resolved
Hide resolved
|
||
border: 1px solid ${({ theme }) => theme.colors.GRAY[200]}; | ||
background: ${({ theme }) => theme.colors.WHITE}; | ||
&::placeholder { | ||
color: ${({ theme }) => theme.colors.GRAY[200]}; | ||
} | ||
&:focus { | ||
border: 1px solid ${({ theme }) => theme.colors.PRIMARY}; | ||
outline: none; | ||
} | ||
&:hover:not(:focus) { | ||
border: 1px solid ${({ theme }) => theme.colors.GRAY[300]}; | ||
} | ||
|
||
${({ hasError }) => hasError && errorStyle}; | ||
${({ disabled }) => disabled && disabledStyle}; | ||
`; | ||
|
||
const MaxUnit = styled.div.withConfig({ | ||
shouldForwardProp: prop => isPropValid(prop), | ||
})<{ hasError: boolean }>` | ||
position: absolute; | ||
right: 12px; | ||
left: auto; | ||
top: auto; | ||
bottom: auto; | ||
display: flex; | ||
align-items: center; | ||
color: ${({ theme, hasError }) => | ||
hasError ? theme.colors.RED[600] : theme.colors.GRAY[300]}; | ||
font-family: Pretendard; | ||
font-size: 16px; | ||
font-style: normal; | ||
font-weight: 400; | ||
line-height: 20px; /* 125% */ | ||
jinhyeonkwon marked this conversation as resolved.
Show resolved
Hide resolved
|
||
`; | ||
|
||
const InputWrapper = styled.div` | ||
position: relative; | ||
width: 100%; | ||
display: flex; | ||
align-items: center; | ||
`; | ||
|
||
const DaystarItemNumberInputWrapper = styled.div` | ||
display: flex; | ||
width: 300px; | ||
flex-direction: column; | ||
align-items: flex-start; | ||
gap: 4px; | ||
`; | ||
|
||
const DaystarItemNumberInput: React.FC<DaystarItemNumberInputProps> = ({ | ||
itemLimit = 0, | ||
unit = null, | ||
value = "", | ||
handleChange = () => {}, | ||
setErrorStatus = () => {}, | ||
...props | ||
}) => { | ||
const [errorMessage, setErrorMessage] = useState(""); // 에러 여부를 내부에서 체크 | ||
|
||
const handleValueChange = (e: ChangeEvent<HTMLInputElement>) => { | ||
const inputValue = e.target.value.replace(/[^0-9]/g, ""); // 숫자 형식만 떼어냅니다. | ||
|
||
if ( | ||
inputValue.length <= itemLimit.toString().length && | ||
inputValue !== "0" | ||
) { | ||
// 이 if문 구조는 너무 비용이 크지만 않다면 기존 컴포넌트에도 제안 드리고 싶습니다 | ||
// (itemLimit이 2자리보다 길어도 작동) | ||
jinhyeonkwon marked this conversation as resolved.
Show resolved
Hide resolved
|
||
handleChange(inputValue); // 이 컴포넌트를 호출한 외부에서 처리하여 적절한 value 값으로 | ||
// 이 컴포넌트를 리렌더링해 줄 것입니다. => 아래의 useEffect가 작동하여 새로운 value에 대응합니다. | ||
} | ||
}; | ||
|
||
useEffect(() => { | ||
const isValidFormat = /^\d+$/g.test(value); // 숫자만 입력되었는지 확인합니다. | ||
const amount = parseInt(value); // 입력을 숫자로 변환 | ||
// 기존 코드를 가져왔습니다. | ||
if (value === "") { | ||
// | ||
setErrorMessage(""); | ||
setErrorStatus(false); | ||
} else if (!isValidFormat) { | ||
// 숫자 아님 | ||
setErrorMessage("숫자만 입력해주세요."); | ||
setErrorStatus(true); | ||
} else if (amount > itemLimit) { | ||
setErrorMessage("신청 가능 개수를 초과했습니다."); | ||
setErrorStatus(true); | ||
} else { | ||
setErrorMessage(""); | ||
setErrorStatus(false); | ||
} | ||
}, [value, itemLimit, setErrorStatus]); | ||
|
||
const mainInputRef = useRef<HTMLInputElement>(null); | ||
const displayValue = value ? `${value}${unit}` : ""; | ||
|
||
const handleCursor = () => { | ||
// 매 입력 또는 선택마다 커서를 적절한 위치로 옮기는 함수입니다. 그대로 가져왔습니다. | ||
// 이를 Input의 onSelect로 하여 키보드 입력 또는 커서 선택 시 숫자 범위를 벗어나지 않게 합니다. | ||
mainInputRef.current?.setSelectionRange( | ||
mainInputRef.current.selectionStart! >= displayValue.length | ||
? displayValue.length - 1 | ||
: mainInputRef.current.selectionStart, | ||
mainInputRef.current.selectionEnd! >= displayValue.length | ||
? displayValue.length - 1 | ||
: mainInputRef.current.selectionEnd, | ||
); | ||
}; | ||
|
||
return ( | ||
<DaystarItemNumberInputWrapper> | ||
<InputWrapper> | ||
<Input | ||
ref={mainInputRef} | ||
hasError={!!errorMessage} | ||
onChange={handleValueChange} | ||
value={displayValue} | ||
onSelect={handleCursor} | ||
{...props} | ||
/> | ||
{unit && itemLimit && ( | ||
<MaxUnit hasError={!!errorMessage}>{`/ ${itemLimit}${unit}`}</MaxUnit> | ||
)} | ||
</InputWrapper> | ||
{errorMessage && <FormError>{errorMessage}</FormError>} | ||
</DaystarItemNumberInputWrapper> | ||
); | ||
}; | ||
export default DaystarItemNumberInput; |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FlexWrapper를 사용합시당