From 2228b36464816ba44338d19052b529a6b224dfeb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8B=E1=85=B5=E1=84=90=E1=85=A2=E1=84=92=E1=85=AE?= =?UTF-8?q?=E1=86=AB?= Date: Thu, 26 Sep 2024 21:35:48 +0900 Subject: [PATCH] =?UTF-8?q?fix:=20=EB=A9=A4=EB=B2=84=20=EC=B6=94=EA=B0=80?= =?UTF-8?q?=20=EC=8B=9C=20=EC=A0=9C=EB=8C=80=EB=A1=9C=20=EC=9E=91=EB=8F=99?= =?UTF-8?q?=ED=95=98=EC=A7=80=20=EC=95=8A=EB=8A=94=20=EB=AC=B8=EC=A0=9C=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Design/components/Input/Input.style.ts | 42 +++++--- .../Design/components/Input/Input.tsx | 102 +++++++++++------- .../Design/components/Input/Input.type.ts | 6 +- .../components/LabelGroupInput/Element.tsx | 63 ----------- .../LabelGroupInput/Element.type.ts | 10 -- .../LabelGroupInput/GroupInputContext.tsx | 32 ------ .../LabelGroupInput.stories.tsx | 75 ------------- .../LabelGroupInput/LabelGroupInput.style.ts | 25 ----- .../LabelGroupInput/LabelGroupInput.tsx | 47 -------- .../LabelGroupInput/LabelGroupInput.type.ts | 10 -- .../components/LabelGroupInput/index.ts | 3 - .../LabelInput/LabelInput.stories.tsx | 56 ---------- .../components/LabelInput/LabelInput.style.ts | 31 ------ .../components/LabelInput/LabelInput.tsx | 57 ---------- .../components/LabelInput/LabelInput.type.ts | 15 --- .../components/LabelInput/useLabelInput.ts | 26 ----- client/src/components/Design/index.tsx | 4 - client/src/hooks/useMembersStep.ts | 30 +++--- client/src/pages/AccountPage/Account.tsx | 8 +- .../pages/AddBillFunnel/steps/MembersStep.tsx | 26 ++++- .../pages/AddBillFunnel/steps/TitleStep.tsx | 4 +- .../CreateEventPage/SetEventNameStep.tsx | 4 +- .../CreateEventPage/SetEventPasswordStep.tsx | 4 +- .../EventPage/AdminPage/EventLoginPage.tsx | 6 +- 24 files changed, 148 insertions(+), 538 deletions(-) delete mode 100644 client/src/components/Design/components/LabelGroupInput/Element.tsx delete mode 100644 client/src/components/Design/components/LabelGroupInput/Element.type.ts delete mode 100644 client/src/components/Design/components/LabelGroupInput/GroupInputContext.tsx delete mode 100644 client/src/components/Design/components/LabelGroupInput/LabelGroupInput.stories.tsx delete mode 100644 client/src/components/Design/components/LabelGroupInput/LabelGroupInput.style.ts delete mode 100644 client/src/components/Design/components/LabelGroupInput/LabelGroupInput.tsx delete mode 100644 client/src/components/Design/components/LabelGroupInput/LabelGroupInput.type.ts delete mode 100644 client/src/components/Design/components/LabelGroupInput/index.ts delete mode 100644 client/src/components/Design/components/LabelInput/LabelInput.stories.tsx delete mode 100644 client/src/components/Design/components/LabelInput/LabelInput.style.ts delete mode 100644 client/src/components/Design/components/LabelInput/LabelInput.tsx delete mode 100644 client/src/components/Design/components/LabelInput/LabelInput.type.ts delete mode 100644 client/src/components/Design/components/LabelInput/useLabelInput.ts diff --git a/client/src/components/Design/components/Input/Input.style.ts b/client/src/components/Design/components/Input/Input.style.ts index 666508cf8..71b5fc156 100644 --- a/client/src/components/Design/components/Input/Input.style.ts +++ b/client/src/components/Design/components/Input/Input.style.ts @@ -5,12 +5,35 @@ import {Theme} from '@theme/theme.type'; const getBorderStyle = (isFocus: boolean, theme: Theme, isError?: boolean) => isError ? `0 0 0 1px ${theme.colors.error} inset` : isFocus ? `0 0 0 1px ${theme.colors.primary} inset` : 'none'; -export const inputBoxStyle = ( - theme: Theme, - isFocus: boolean, - isError: boolean | undefined, - isAlwaysOnBorder: boolean, -) => +export const labelTextStyle = (theme: Theme, hasFocus: boolean, hasValue: boolean) => + css([ + { + height: '1.125rem', + color: theme.colors.gray, + }, + labelTextAnimationStyle(hasFocus, hasValue), + ]); + +export const labelTextAnimationStyle = (hasFocus: boolean, hasValue: boolean) => + css({ + opacity: hasFocus || hasValue ? '1' : '0', + + transition: '0.2s', + transitionTimingFunction: 'cubic-bezier(0.7, 0.62, 0.62, 1.16)', + }); + +export const errorTextStyle = (theme: Theme, isError: boolean) => + css({ + height: '1.125rem', + color: theme.colors.onErrorContainer, + + opacity: isError ? '1' : '0', + + transition: '0.2s', + transitionTimingFunction: 'cubic-bezier(0.7, 0.62, 0.62, 1.16)', + }); + +export const inputBoxStyle = (theme: Theme, isFocus: boolean, isError: boolean | undefined) => css([ { display: 'flex', @@ -22,7 +45,7 @@ export const inputBoxStyle = ( boxSizing: 'border-box', boxShadow: getBorderStyle(isFocus, theme, isError), }, - isAlwaysOnBorder ? inputBoxAlwaysBorderStyle(theme) : inputBoxAnimationStyle(), + inputBoxAnimationStyle(), ]); export const inputBoxAnimationStyle = () => @@ -31,11 +54,6 @@ export const inputBoxAnimationStyle = () => transitionTimingFunction: 'cubic-bezier(0.7, 0.62, 0.62, 1.16)', }); -export const inputBoxAlwaysBorderStyle = (theme: Theme) => - css({ - boxShadow: `0 0 0 1px ${theme.colors.primary} inset`, - }); - export const inputStyle = (theme: Theme) => css( { diff --git a/client/src/components/Design/components/Input/Input.tsx b/client/src/components/Design/components/Input/Input.tsx index 08d879c6a..dd0e2de22 100644 --- a/client/src/components/Design/components/Input/Input.tsx +++ b/client/src/components/Design/components/Input/Input.tsx @@ -1,65 +1,85 @@ /** @jsxImportSource @emotion/react */ -import React, {forwardRef, useImperativeHandle, useRef} from 'react'; +import React, {forwardRef, useEffect, useImperativeHandle, useRef, useState} from 'react'; import IconButton from '@HDcomponents/IconButton/IconButton'; import {InputProps} from '@HDcomponents/Input/Input.type'; -import {inputBoxStyle, inputStyle} from '@HDcomponents/Input/Input.style'; -import {useInput} from '@HDcomponents/Input/useInput'; import Icon from '@HDcomponents/Icon/Icon'; import {useTheme} from '@theme/HDesignProvider'; +import Flex from '../Flex/Flex'; +import Text from '../Text/Text'; +import {inputBoxStyle, inputStyle, labelTextStyle, errorTextStyle} from './Input.style'; export const Input: React.FC = forwardRef(function Input( { - value: propsValue, + value, onChange, - onFocus, - onBlur, - inputType, - isError, + onDelete, placeholder, - autoFocus, - isAlwaysOnBorder = false, + autoFocus = false, + labelText, + errorText = '', + inputType = 'input', + isError, ...htmlProps }: InputProps, ref, ) { const {theme} = useTheme(); const inputRef = useRef(null); - const {value, handleChange, hasFocus, handleClickDelete, handleBlur, handleFocus, handleKeyDown} = useInput({ - propsValue, - onChange, - onBlur, - onFocus, - inputRef, - autoFocus, - }); + const [hasFocus, setHasFocus] = useState(autoFocus); + const hasValue = !!value; + useImperativeHandle(ref, () => inputRef.current!); + useEffect(() => { + inputRef.current?.addEventListener('focus', () => setHasFocus(true)); + inputRef.current?.addEventListener('blur', () => setHasFocus(false)); + return () => { + inputRef.current?.removeEventListener('focus', () => setHasFocus(true)); + inputRef.current?.removeEventListener('blur', () => setHasFocus(false)); + }; + }, []); + return ( -
- - {inputType === 'input' && value && hasFocus && ( - - - - )} - {inputType === 'search' && ( - - - + + {(labelText || errorText) && ( + + {labelText && ( + + {labelText} + + )} + {errorText && ( + + {errorText} + + )} + )} -
+ +
+ + {onDelete && value && hasFocus && ( + + + + )} + {inputType === 'search' && ( + + + + )} +
+
+ ); }); diff --git a/client/src/components/Design/components/Input/Input.type.ts b/client/src/components/Design/components/Input/Input.type.ts index 7360c1061..d706b644f 100644 --- a/client/src/components/Design/components/Input/Input.type.ts +++ b/client/src/components/Design/components/Input/Input.type.ts @@ -2,14 +2,16 @@ import {Theme} from '@theme/theme.type'; export interface InputStyleProps { theme?: Theme; - isAlwaysOnBorder?: boolean; + isError?: boolean; } export type InputType = 'input' | 'search'; export interface InputCustomProps { inputType?: InputType; - isError?: boolean; + labelText?: string; + errorText?: string | null; + onDelete?: () => void; } export type InputOptionProps = InputStyleProps & InputCustomProps; diff --git a/client/src/components/Design/components/LabelGroupInput/Element.tsx b/client/src/components/Design/components/LabelGroupInput/Element.tsx deleted file mode 100644 index 5ffd852bd..000000000 --- a/client/src/components/Design/components/LabelGroupInput/Element.tsx +++ /dev/null @@ -1,63 +0,0 @@ -/** @jsxImportSource @emotion/react */ - -import {forwardRef, useEffect, useImperativeHandle, useRef, useState} from 'react'; - -import Input from '../Input/Input'; - -import {ElementProps} from './Element.type'; -import {useGroupInputContext} from './GroupInputContext'; - -const Element: React.FC = forwardRef(function Element( - {elementKey, value: propsValue, onChange, onBlur, onFocus, isError, autoFocus, ...htmlProps}: ElementProps, - - ref, -) { - useImperativeHandle(ref, () => inputRef.current!); - const inputRef = useRef(null); - const {setHasAnyFocus, values, setValues, errors, setErrors} = useGroupInputContext(); - - useEffect(() => { - setValues({...values, [elementKey]: `${propsValue}`}); - }, [propsValue]); - - const handleChange = (e: React.ChangeEvent) => { - const newValue = e.target.value; - setValues({...values, [elementKey]: newValue}); - if (onChange) { - onChange(e); - } - }; - - useEffect(() => { - setErrors({...errors, [elementKey]: isError ?? false}); - }, [isError]); - - const handleBlur = (e: React.FocusEvent) => { - setHasAnyFocus(false); - if (onBlur) { - onBlur(e); - } - }; - - const handleFocus = (e: React.FocusEvent) => { - setHasAnyFocus(true); - if (onFocus) { - onFocus(e); - } - }; - - return ( - - ); -}); - -export default Element; diff --git a/client/src/components/Design/components/LabelGroupInput/Element.type.ts b/client/src/components/Design/components/LabelGroupInput/Element.type.ts deleted file mode 100644 index 2ec2ef9ed..000000000 --- a/client/src/components/Design/components/LabelGroupInput/Element.type.ts +++ /dev/null @@ -1,10 +0,0 @@ -export interface ElementStyleProps {} - -export interface ElementCustomProps { - elementKey: string; - isError?: boolean; -} - -export type ElementOptionProps = ElementStyleProps & ElementCustomProps; - -export type ElementProps = React.ComponentProps<'input'> & ElementOptionProps; diff --git a/client/src/components/Design/components/LabelGroupInput/GroupInputContext.tsx b/client/src/components/Design/components/LabelGroupInput/GroupInputContext.tsx deleted file mode 100644 index 142183e6b..000000000 --- a/client/src/components/Design/components/LabelGroupInput/GroupInputContext.tsx +++ /dev/null @@ -1,32 +0,0 @@ -import React, {createContext, PropsWithChildren, useContext, useState} from 'react'; - -interface GroupInputContextProps { - hasAnyFocus: boolean; - setHasAnyFocus: React.Dispatch>; - values: {[key: string]: string}; - setValues: React.Dispatch>; - errors: {[key: string]: boolean}; - setErrors: React.Dispatch>; -} - -const GroupInputContext = createContext(undefined); - -export const useGroupInputContext = () => { - const context = useContext(GroupInputContext); - if (!context) { - throw new Error('useGroupInputContext must be used within an GroupInputProvider'); - } - return context; -}; - -export const GroupInputProvider: React.FC = ({children}: React.PropsWithChildren) => { - const [hasAnyFocus, setHasAnyFocus] = useState(false); - const [values, setValues] = useState<{[key: string]: string}>({}); - const [errors, setErrors] = useState<{[key: string]: boolean}>({}); - - return ( - - {children} - - ); -}; diff --git a/client/src/components/Design/components/LabelGroupInput/LabelGroupInput.stories.tsx b/client/src/components/Design/components/LabelGroupInput/LabelGroupInput.stories.tsx deleted file mode 100644 index a2b873060..000000000 --- a/client/src/components/Design/components/LabelGroupInput/LabelGroupInput.stories.tsx +++ /dev/null @@ -1,75 +0,0 @@ -/** @jsxImportSource @emotion/react */ -import type {Meta, StoryObj} from '@storybook/react'; - -import {useState} from 'react'; - -import LabelGroupInput from '@HDcomponents/LabelGroupInput/LabelGroupInput'; - -const meta = { - title: 'Components/LabelGroupInput', - component: LabelGroupInput, - tags: ['autodocs'], - parameters: { - // layout: 'centered', - }, - argTypes: { - labelText: { - description: 'label에 들어갈 텍스트를 작성', - control: {type: 'text'}, - }, - errorText: { - description: 'error에 들어갈 텍스트를 작성', - control: {type: 'text'}, - }, - }, - args: { - labelText: '지출내역 / 금액', - errorText: 'error가 발생했을 때 나타납니다!', - }, -} satisfies Meta; - -export default meta; - -type Story = StoryObj; - -export const Playground: Story = { - render: ({...args}) => { - const [name, setName] = useState(''); - const [price, setPrice] = useState(''); - const [isError, setIsError] = useState(false); - const handleChangeName = (event: React.ChangeEvent) => { - if (event.target.value.length < 4) { - setName(event.target.value); - setIsError(false); - } else { - event.target.value = name; - setIsError(true); - } - }; - const handleChangePrice = (event: React.ChangeEvent) => { - setPrice(event.target.value); - }; - return ( - - handleChangeName(e)} - onBlur={() => console.log('!!!')} - isError={isError} - autoFocus - /> - console.log('!!!')} - isError={false} - autoFocus - /> - - ); - }, -}; diff --git a/client/src/components/Design/components/LabelGroupInput/LabelGroupInput.style.ts b/client/src/components/Design/components/LabelGroupInput/LabelGroupInput.style.ts deleted file mode 100644 index df64636e9..000000000 --- a/client/src/components/Design/components/LabelGroupInput/LabelGroupInput.style.ts +++ /dev/null @@ -1,25 +0,0 @@ -import {css} from '@emotion/react'; - -import {Theme} from '@theme/theme.type'; - -export const labelTextStyle = (theme: Theme, hasFocus: boolean, hasValue: boolean) => - css({ - height: '1.125rem', - color: theme.colors.gray, - - opacity: hasFocus || hasValue ? '1' : '0', - - transition: '0.2s', - transitionTimingFunction: 'cubic-bezier(0.7, 0.62, 0.62, 1.16)', - }); - -export const errorTextStyle = (theme: Theme, isError: boolean) => - css({ - height: '1.125rem', - color: theme.colors.onErrorContainer, - - opacity: isError ? '1' : '0', - - transition: '0.2s', - transitionTimingFunction: 'cubic-bezier(0.7, 0.62, 0.62, 1.16)', - }); diff --git a/client/src/components/Design/components/LabelGroupInput/LabelGroupInput.tsx b/client/src/components/Design/components/LabelGroupInput/LabelGroupInput.tsx deleted file mode 100644 index 3c60e14a6..000000000 --- a/client/src/components/Design/components/LabelGroupInput/LabelGroupInput.tsx +++ /dev/null @@ -1,47 +0,0 @@ -/** @jsxImportSource @emotion/react */ - -import Text from '@HDcomponents/Text/Text'; -import {useTheme} from '@theme/HDesignProvider'; - -import Flex from '../Flex/Flex'; - -import {LabelGroupInputProps} from './LabelGroupInput.type'; -import {errorTextStyle, labelTextStyle} from './LabelGroupInput.style'; -import Element from './Element'; -import {GroupInputProvider, useGroupInputContext} from './GroupInputContext'; - -const LabelGroupInput: React.FC = ({labelText, errorText, children}: LabelGroupInputProps) => { - const {theme} = useTheme(); - const {hasAnyFocus, values, errors} = useGroupInputContext(); - - const hasAnyValue = !Object.values(values).every(value => value === ''); - const hasAnyError = !Object.values(errors).every(error => !error); - - return ( - - - - {labelText} - - {errorText && ( - - {errorText} - - )} - - - {children} - - - ); -}; - -const LabelGroupInputContainer = (props: LabelGroupInputProps) => ( - - - -); - -LabelGroupInputContainer.Element = Element; - -export default LabelGroupInputContainer; diff --git a/client/src/components/Design/components/LabelGroupInput/LabelGroupInput.type.ts b/client/src/components/Design/components/LabelGroupInput/LabelGroupInput.type.ts deleted file mode 100644 index 8507311b5..000000000 --- a/client/src/components/Design/components/LabelGroupInput/LabelGroupInput.type.ts +++ /dev/null @@ -1,10 +0,0 @@ -export interface LabelGroupInputStyleProps {} - -export interface LabelGroupInputCustomProps { - labelText: string; - errorText: string | null; -} - -export type LabelGroupInputOptionProps = LabelGroupInputStyleProps & LabelGroupInputCustomProps; - -export type LabelGroupInputProps = React.ComponentProps<'input'> & LabelGroupInputOptionProps; diff --git a/client/src/components/Design/components/LabelGroupInput/index.ts b/client/src/components/Design/components/LabelGroupInput/index.ts deleted file mode 100644 index c31f35eaf..000000000 --- a/client/src/components/Design/components/LabelGroupInput/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -import LabelGroupInputContainer from './LabelGroupInput'; - -export {LabelGroupInputContainer as LabelGroupInput}; diff --git a/client/src/components/Design/components/LabelInput/LabelInput.stories.tsx b/client/src/components/Design/components/LabelInput/LabelInput.stories.tsx deleted file mode 100644 index 9bff764ef..000000000 --- a/client/src/components/Design/components/LabelInput/LabelInput.stories.tsx +++ /dev/null @@ -1,56 +0,0 @@ -/** @jsxImportSource @emotion/react */ -import type {Meta, StoryObj} from '@storybook/react'; - -import {useEffect, useState} from 'react'; - -import LabelInput from '@HDcomponents/LabelInput/LabelInput'; - -const meta = { - title: 'Components/LabelInput', - component: LabelInput, - tags: ['autodocs'], - parameters: { - // layout: 'centered', - }, - argTypes: { - labelText: { - description: 'label에 들어갈 텍스트를 작성', - control: {type: 'text'}, - }, - isError: { - description: '', - control: {type: 'boolean'}, - }, - errorText: { - description: 'error에 들어갈 텍스트를 작성', - control: {type: 'text'}, - }, - }, - args: { - // value: '', - labelText: '이름', - errorText: 'error가 발생했을 때 나타납니다!', - autoFocus: true, - }, -} satisfies Meta; - -export default meta; - -type Story = StoryObj; - -export const Playground: Story = { - render: ({...args}) => { - const [value, setValue] = useState(''); - const [isError, setIsError] = useState(false); - const handleChange = (event: React.ChangeEvent) => { - if (event.target.value.length < 4) { - setValue(event.target.value); - setIsError(false); - } else { - event.target.value = value; - setIsError(true); - } - }; - return handleChange(e)} isError={isError} {...args} />; - }, -}; diff --git a/client/src/components/Design/components/LabelInput/LabelInput.style.ts b/client/src/components/Design/components/LabelInput/LabelInput.style.ts deleted file mode 100644 index e6f00284d..000000000 --- a/client/src/components/Design/components/LabelInput/LabelInput.style.ts +++ /dev/null @@ -1,31 +0,0 @@ -import {css} from '@emotion/react'; - -import {Theme} from '@theme/theme.type'; - -export const labelTextStyle = (theme: Theme, hasFocus: boolean, hasValue: boolean, isAlwaysOnLabel: boolean) => - css([ - { - height: '1.125rem', - color: theme.colors.gray, - }, - !isAlwaysOnLabel && labelTextAnimationStyle(hasFocus, hasValue), - ]); - -export const labelTextAnimationStyle = (hasFocus: boolean, hasValue: boolean) => - css({ - opacity: hasFocus || hasValue ? '1' : '0', - - transition: '0.2s', - transitionTimingFunction: 'cubic-bezier(0.7, 0.62, 0.62, 1.16)', - }); - -export const errorTextStyle = (theme: Theme, isError: boolean) => - css({ - height: '1.125rem', - color: theme.colors.onErrorContainer, - - opacity: isError ? '1' : '0', - - transition: '0.2s', - transitionTimingFunction: 'cubic-bezier(0.7, 0.62, 0.62, 1.16)', - }); diff --git a/client/src/components/Design/components/LabelInput/LabelInput.tsx b/client/src/components/Design/components/LabelInput/LabelInput.tsx deleted file mode 100644 index 8f7b1b5e3..000000000 --- a/client/src/components/Design/components/LabelInput/LabelInput.tsx +++ /dev/null @@ -1,57 +0,0 @@ -/** @jsxImportSource @emotion/react */ - -import {forwardRef, useImperativeHandle, useRef} from 'react'; - -import Text from '@HDcomponents/Text/Text'; -import {useTheme} from '@theme/HDesignProvider'; - -import Input from '../Input/Input'; -import Flex from '../Flex/Flex'; - -import {errorTextStyle, labelTextStyle} from './LabelInput.style'; -import {useLabelInput} from './useLabelInput'; -import {LabelInputProps} from './LabelInput.type'; - -const LabelInput: React.FC = forwardRef(function LabelInput( - { - labelText, - errorText, - isError, - isAlwaysOnLabel = false, - isAlwaysOnInputBorder = false, - ...htmlProps - }: LabelInputProps, - ref, -) { - useImperativeHandle(ref, () => inputRef.current!); - - const {theme} = useTheme(); - const inputRef = useRef(null); - const {hasFocus} = useLabelInput({inputRef}); - - return ( - - - - {labelText} - - {errorText && ( - - {errorText} - - )} - - - - - - ); -}); - -export default LabelInput; diff --git a/client/src/components/Design/components/LabelInput/LabelInput.type.ts b/client/src/components/Design/components/LabelInput/LabelInput.type.ts deleted file mode 100644 index 84bfc7279..000000000 --- a/client/src/components/Design/components/LabelInput/LabelInput.type.ts +++ /dev/null @@ -1,15 +0,0 @@ -export interface LabelInputStyleProps { - isAlwaysOnLabel?: boolean; - isAlwaysOnInputBorder?: boolean; -} - -export interface LabelInputCustomProps { - labelText: string; - errorText: string | null; - isError?: boolean; - autoFocus: boolean; -} - -export type LabelInputOptionProps = LabelInputCustomProps & LabelInputStyleProps; - -export type LabelInputProps = React.ComponentProps<'input'> & LabelInputOptionProps; diff --git a/client/src/components/Design/components/LabelInput/useLabelInput.ts b/client/src/components/Design/components/LabelInput/useLabelInput.ts deleted file mode 100644 index e967c5f89..000000000 --- a/client/src/components/Design/components/LabelInput/useLabelInput.ts +++ /dev/null @@ -1,26 +0,0 @@ -import {RefObject, useEffect, useState} from 'react'; - -interface UseLabelInput { - inputRef: RefObject; - autoFocus?: boolean; -} - -export const useLabelInput = ({inputRef, autoFocus}: UseLabelInput) => { - const [hasFocus, setHasFocus] = useState(inputRef.current === document.activeElement); - - useEffect(() => { - setHasFocus(inputRef.current === document.activeElement); - }, []); - - useEffect(() => { - inputRef.current?.addEventListener('focus', () => setHasFocus(true)); - inputRef.current?.addEventListener('blur', () => setHasFocus(false)); - - return () => { - inputRef.current?.removeEventListener('focus', () => setHasFocus(true)); - inputRef.current?.removeEventListener('blur', () => setHasFocus(false)); - }; - }, []); - - return {hasFocus}; -}; diff --git a/client/src/components/Design/index.tsx b/client/src/components/Design/index.tsx index a75245994..aaada3e57 100644 --- a/client/src/components/Design/index.tsx +++ b/client/src/components/Design/index.tsx @@ -14,9 +14,7 @@ import Flex from './components/Flex/Flex'; import Icon from './components/Icon/Icon'; import IconButton from './components/IconButton/IconButton'; import Input from './components/Input/Input'; -import LabelInput from './components/LabelInput/LabelInput'; import ListButton from './components/ListButton/ListButton'; -import LabelGroupInput from './components/LabelGroupInput/LabelGroupInput'; import Top from './components/Top/Top'; import Tab from './components/Tabs/Tab'; import Tabs from './components/Tabs/Tabs'; @@ -43,9 +41,7 @@ export { Icon, IconButton, Input, - LabelInput, ListButton, - LabelGroupInput, Top, Tab, Tabs, diff --git a/client/src/hooks/useMembersStep.ts b/client/src/hooks/useMembersStep.ts index 86c42b0b6..a9ff6bb5a 100644 --- a/client/src/hooks/useMembersStep.ts +++ b/client/src/hooks/useMembersStep.ts @@ -11,6 +11,7 @@ import REGEXP from '@constants/regExp'; import useRequestPostMembers from './queries/member/useRequestPostMembers'; import useRequestPostBill from './queries/bill/useRequestPostBill'; import {BillStep} from './useAddBillFunnel'; +import {isIOS} from '@utils/detectDevice'; interface Props { billInfo: BillInfo; @@ -23,6 +24,7 @@ const useMembersStep = ({billInfo, setBillInfo, currentMembers, setStep}: Props) const [errorMessage, setErrorMessage] = useState(''); const [nameInput, setNameInput] = useState(''); const inputRef = useRef(null); + const hiddenRef = useRef(null); const {postMembersAsync, isPending: isPendingPostMembers} = useRequestPostMembers(); @@ -59,24 +61,25 @@ const useMembersStep = ({billInfo, setBillInfo, currentMembers, setStep}: Props) } }; - const handleNameInputEnter = (event: React.KeyboardEvent) => { - if (event.key === 'Enter' && canAddMembers) { - if (!billInfo.members.map(({name}) => name).includes(nameInput)) { - setBillInfoMemberWithId(nameInput); - } + const addMembersFromInput = () => { + if (!billInfo.members.map(({name}) => name).includes(nameInput)) { + setBillInfoMemberWithId(nameInput); setNameInput(''); - if (inputRef.current) { - inputRef.current.blur(); - setTimeout(() => { - inputRef.current?.focus(); - }, 0); - } - if (event.nativeEvent.isComposing) { - return; + if (isIOS()) { + hiddenRef.current?.focus(); + inputRef.current?.focus(); } } }; + const handleNameInputEnter = (event: React.KeyboardEvent) => { + if (event.nativeEvent.isComposing) return; + if (event.key === 'Enter' && canAddMembers && inputRef.current) { + event.preventDefault(); + addMembersFromInput(); + } + }; + const handlePostBill = async () => { if (billInfo.members.map(({id}) => id).includes(-1)) { const newMembers = await postMembersAsync({ @@ -116,6 +119,7 @@ const useMembersStep = ({billInfo, setBillInfo, currentMembers, setStep}: Props) errorMessage, nameInput, inputRef, + hiddenRef, handleNameInputChange, handleNameInputEnter, isPendingPostBill, diff --git a/client/src/pages/AccountPage/Account.tsx b/client/src/pages/AccountPage/Account.tsx index 0490ead31..5939ae364 100644 --- a/client/src/pages/AccountPage/Account.tsx +++ b/client/src/pages/AccountPage/Account.tsx @@ -5,7 +5,7 @@ import BankSelectModal from '@components/Modal/BankSelectModal/BankSelectModal'; import useAccount from '@hooks/useAccount'; -import {FixedButton, Flex, FunnelLayout, LabelInput, MainLayout, Top, TopNav} from '@components/Design'; +import {FixedButton, Flex, FunnelLayout, Input, MainLayout, Top, TopNav} from '@components/Design'; import getDeletedLastPath from '@utils/getDeletedLastPath'; @@ -42,17 +42,16 @@ const Account = () => { - setIsBottomSheetOpen(true)} /> - { onChange={handleAccount} onPaste={handleAccountOnPaste} autoFocus={false} - isAlwaysOnLabel /> {isBottomSheetOpen && ( errorMessage, nameInput, inputRef, + hiddenRef, handleNameInputChange, handleNameInputEnter, isPendingPostBill, @@ -46,7 +49,8 @@ const MembersStep = ({billInfo, setBillInfo, currentMembers, setStep}: Props) => - + {isIOS() && ( + + )} { - void; @@ -37,7 +37,7 @@ const SetEventNameStep = ({
- - { - { onChange={e => handleChange(e)} isError={!!errorMessage} autoFocus - > + > 관리 페이지로