Skip to content

Commit

Permalink
feat-fe: 지원서 단답형/장문형 입력 필드에 글자 수 제한 추가 (#505)
Browse files Browse the repository at this point in the history
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Seongjin Hong <[email protected]>
Co-authored-by: Seongjin Hong <[email protected]>
  • Loading branch information
3 people authored Aug 19, 2024
1 parent b418da4 commit 7bbea2f
Show file tree
Hide file tree
Showing 9 changed files with 104 additions and 9 deletions.
11 changes: 11 additions & 0 deletions frontend/src/components/common/InputField/InputField.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,15 @@ const meta = {
type: { name: 'string' },
control: { type: 'text' },
},
isLengthVisible: {
description: 'Input 하단에 입력값의 길이 표시 여부를 설정합니다.',
control: { type: 'boolean' },
},
maxLength: {
description: 'Input에 입력 허용할 값의 최대 길이를 설정합니다.',
type: { name: 'number' },
control: { type: 'number' },
},
disabled: {
description: 'Input이 비활성화된 경우 true로 설정합니다.',
control: { type: 'boolean' },
Expand Down Expand Up @@ -78,5 +87,7 @@ export const Default: Story = {
placeholder: '여기에 직접 입력해보세요.',
required: true,
disabled: false,
isLengthVisible: false,
maxLength: 50,
},
};
21 changes: 19 additions & 2 deletions frontend/src/components/common/InputField/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,19 @@ interface InputFieldProps extends ComponentProps<'input'> {
label?: string;
error?: string;
focus?: boolean;
isLengthVisible?: boolean;
}

export default function InputField({ label, value, onChange, disabled, error, required, ...props }: InputFieldProps) {
export default function InputField({
label,
value,
onChange,
disabled,
error,
required,
isLengthVisible,
...props
}: InputFieldProps) {
return (
<S.Wrapper>
{label && (
Expand All @@ -26,7 +36,14 @@ export default function InputField({ label, value, onChange, disabled, error, re
{...props}
/>

{error && <S.ErrorText>{error}</S.ErrorText>}
{(isLengthVisible || error) && (
<S.Footer isError={!!error}>
{error && <S.ErrorText>{error}</S.ErrorText>}
{isLengthVisible && (
<S.LengthText>{`${value ? value.toString().length : 0} / ${props.maxLength}`}</S.LengthText>
)}
</S.Footer>
)}
</S.Wrapper>
);
}
18 changes: 17 additions & 1 deletion frontend/src/components/common/InputField/style.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,9 +65,23 @@ const Input = styled.input<{ isError: boolean }>`
`}
`;

const Footer = styled.div<{ isError: boolean }>`
display: flex;
flex-direction: row;
align-items: flex-start;
justify-content: ${({ isError }) => (isError ? 'space-between' : 'flex-end')};
gap: 1rem;
`;

const ErrorText = styled.p`
color: ${({ theme }) => theme.colors.feedback.error};
${({ theme }) => theme.typography.common.default};
${({ theme }) => theme.typography.common.small};
`;

const LengthText = styled.p`
min-width: fit-content;
${({ theme }) => theme.typography.common.small};
color: ${({ theme }) => theme.baseColors.grayscale[600]};
`;

const S = {
Expand All @@ -76,7 +90,9 @@ const S = {
Asterisk,
Wrapper,
Input,
Footer,
ErrorText,
LengthText,
};

export default S;
13 changes: 12 additions & 1 deletion frontend/src/components/common/TextField/TextField.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,15 @@ const meta = {
type: { name: 'string' },
control: { type: 'text' },
},
isLengthVisible: {
description: 'Input 하단에 입력값의 길이 표시 여부를 설정합니다.',
control: { type: 'boolean' },
},
maxLength: {
description: 'Input에 입력 허용할 값의 최대 길이를 설정합니다.',
type: { name: 'number' },
control: { type: 'number' },
},
disabled: {
description: 'Input이 비활성화된 경우 true로 설정합니다.',
control: { type: 'boolean' },
Expand All @@ -59,7 +68,7 @@ const meta = {
decorators: [
(Story) => {
const [value, setValue] = useState('');
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => setValue(e.target.value);
const handleChange = (e: React.ChangeEvent<HTMLTextAreaElement>) => setValue(e.target.value);

return (
<div style={{ width: '30rem' }}>
Expand All @@ -82,5 +91,7 @@ export const Default: Story = {
placeholder: '여기에 직접 입력해보세요.',
required: true,
disabled: false,
isLengthVisible: false,
maxLength: 1000,
},
};
11 changes: 10 additions & 1 deletion frontend/src/components/common/TextField/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ interface TextFieldProps extends ComponentProps<'textarea'> {
error?: string;
focus?: boolean;
resize?: boolean;
isLengthVisible?: boolean;
}

export default function TextField({
Expand All @@ -16,6 +17,7 @@ export default function TextField({
error,
required,
resize = true,
isLengthVisible,
...props
}: TextFieldProps) {
return (
Expand All @@ -37,7 +39,14 @@ export default function TextField({
{...props}
/>

{error && <S.ErrorText>{error}</S.ErrorText>}
{(isLengthVisible || error) && (
<S.Footer isError={!!error}>
{error && <S.ErrorText>{error}</S.ErrorText>}
{isLengthVisible && (
<S.LengthText>{`${value ? value.toString().length : 0} / ${props.maxLength}`}</S.LengthText>
)}
</S.Footer>
)}
</S.Wrapper>
);
}
18 changes: 17 additions & 1 deletion frontend/src/components/common/TextField/style.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,9 +69,23 @@ const TextArea = styled.textarea<{ isError: boolean; resize: boolean }>`
${({ resize }) => !resize && 'resize: none;'};
`;

const Footer = styled.div<{ isError: boolean }>`
display: flex;
flex-direction: row;
align-items: flex-start;
justify-content: ${({ isError }) => (isError ? 'space-between' : 'flex-end')};
gap: 1rem;
`;

const ErrorText = styled.p`
color: ${({ theme }) => theme.colors.feedback.error};
${({ theme }) => theme.typography.common.default};
${({ theme }) => theme.typography.common.small};
`;

const LengthText = styled.p`
min-width: fit-content;
${({ theme }) => theme.typography.common.small};
color: ${({ theme }) => theme.baseColors.grayscale[600]};
`;

const S = {
Expand All @@ -80,7 +94,9 @@ const S = {
Asterisk,
Wrapper,
TextArea,
Footer,
ErrorText,
LengthText,
};

export default S;
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ export default function ApplyForm({ questions, isClosed }: ApplyFormProps) {
key={question.questionId}
question={question}
value={answers[question.questionId]}
isLengthVisible
onChange={changeHandler[question.type]}
/>
))}
Expand Down
15 changes: 12 additions & 3 deletions frontend/src/components/recruitmentPost/CustomQuestion/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,21 @@ import RadioLabelField from '@components/common/RadioLabelField';
import CheckboxLabelField from '@components/common/CheckboxLabelField';
import { Question } from '@customTypes/apply';
import { ChangeEventHandler } from 'react';
import { QUESTION_INPUT_LENGTH } from '@constants/constants';

interface CustomQuestionProps {
question: Question;
value: string[];
isLengthVisible?: boolean;
onChange?: (id: string, value: string) => void;
}

export default function CustomQuestion({ question, value = [], onChange = () => {} }: CustomQuestionProps) {
export default function CustomQuestion({
question,
value = [],
isLengthVisible = false,
onChange = () => {},
}: CustomQuestionProps) {
const { type, questionId, label } = question;

if (type === 'SHORT_ANSWER') {
Expand All @@ -25,7 +32,8 @@ export default function CustomQuestion({ question, value = [], onChange = () =>
onChange={handleChange}
label={label}
name={questionId}
maxLength={50}
maxLength={QUESTION_INPUT_LENGTH.SHORT_ANSWER}
isLengthVisible={isLengthVisible}
/>
);
}
Expand All @@ -43,7 +51,8 @@ export default function CustomQuestion({ question, value = [], onChange = () =>
onChange={handleChange}
resize={false}
style={{ height: 'calc(2.4rem * 10 + 1.2rem)' }}
maxLength={5000}
maxLength={QUESTION_INPUT_LENGTH.LONG_ANSWER}
isLengthVisible={isLengthVisible}
/>
);
}
Expand Down
5 changes: 5 additions & 0 deletions frontend/src/constants/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,8 @@ export const QUESTION_TYPE_NAME = {
SINGLE_CHOICE: '객관식(단일 선택)',
MULTIPLE_CHOICE: '객관식(복수 선택)',
} as const;

export const QUESTION_INPUT_LENGTH = {
SHORT_ANSWER: 50,
LONG_ANSWER: 1000,
} as const;

0 comments on commit 7bbea2f

Please sign in to comment.