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

템플릿 Edit UX 개선 #499

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
8 changes: 4 additions & 4 deletions frontend/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
"@sentry/webpack-plugin": "^2.21.1",
"@tanstack/react-query": "^5.51.1",
"@uiw/codemirror-extensions-langs": "^4.23.0",
"@uiw/codemirror-theme-vscode": "^4.23.0",
"@uiw/codemirror-theme-material": "^4.23.0",
"@uiw/react-codemirror": "^4.23.0",
"react": "^18.3.1",
"react-dom": "^18.3.1",
Expand Down
26 changes: 22 additions & 4 deletions frontend/src/components/SourceCodeEditor/SourceCodeEditor.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,25 @@
import { type LanguageName, loadLanguage } from '@uiw/codemirror-extensions-langs';
import { vscodeDark } from '@uiw/codemirror-theme-vscode';
import { materialLight } from '@uiw/codemirror-theme-material';
import ReactCodeMirror from '@uiw/react-codemirror';
import { ChangeEvent } from 'react';

import { ToastContext } from '@/contexts';
import { useCustomContext } from '@/hooks/utils';
import { validateFileName } from '@/service/validates';
import { getLanguageByFilename } from '@/utils';
import * as S from './style';

interface Props {
index: number;
fileName: string;
content: string;
onChangeContent: (newContent: string) => void;
onChangeFileName: (newFileName: string) => void;
}

const SourceCodeEditor = ({ fileName, content, onChangeContent, onChangeFileName }: Props) => {
const SourceCodeEditor = ({ index, fileName, content, onChangeContent, onChangeFileName }: Props) => {
const { failAlert } = useCustomContext(ToastContext);

const handleFileNameChange = (event: ChangeEvent<HTMLInputElement>) => {
onChangeFileName(event.target.value);
};
Expand All @@ -22,17 +28,29 @@ const SourceCodeEditor = ({ fileName, content, onChangeContent, onChangeFileName
onChangeContent(value);
};

const handleValidateFileName = (event: React.FocusEvent<HTMLInputElement, Element>) => {
if (validateFileName(event.target.value)) {
failAlert(validateFileName(event.target.value));
}
};

return (
<S.SourceCodeEditorContainer>
<S.SourceCodeFileNameInput value={fileName} onChange={handleFileNameChange} placeholder={'파일명.js'} />
<S.SourceCodeFileNameInput
value={fileName}
onChange={handleFileNameChange}
onBlur={handleValidateFileName}
placeholder={'파일명.js'}
autoFocus={index !== 0 ? true : false}
/>
<ReactCodeMirror
placeholder={'// 코드를 입력해주세요'}
value={content}
height='100%'
minHeight='10rem'
maxHeight='40rem'
style={{ width: '100%' }}
theme={vscodeDark}
theme={materialLight}
onChange={handleContentChange}
extensions={[loadLanguage(getLanguageByFilename(fileName) as LanguageName) || []]}
/>
Expand Down
1 change: 1 addition & 0 deletions frontend/src/components/TemplateEdit/TemplateEdit.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ const TemplateEdit = ({
<Flex key={idx} style={{ position: 'relative' }} width='100%'>
<SourceCodeEditor
key={idx}
index={idx}
fileName={sourceCode.filename}
content={sourceCode.content}
onChangeContent={(newContent) => handleCodeChange(newContent, idx)}
Expand Down
6 changes: 3 additions & 3 deletions frontend/src/hooks/template/useTemplateEdit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ export const useTemplateEdit = ({ template, toggleEditButton }: Props) => {
const deletedSourceCodeId = sourceCodes[index].id;

if (!sourceCodes[index]) {
console.error('존재하지 않는 스니펫 인덱스입니다.');
console.error('존재하지 않는 소스코드 인덱스입니다.');
}

if (deletedSourceCodeId) {
Expand All @@ -79,11 +79,11 @@ export const useTemplateEdit = ({ template, toggleEditButton }: Props) => {
}

if (sourceCodes.filter((sourceCode) => !sourceCode.filename).length) {
return '파일 명을 입력해주세요';
return '파일명을 입력해주세요';
}

if (sourceCodes.filter((sourceCode) => !sourceCode.content).length) {
return '스니펫 내용을 입력해주세요';
return '소스코드 내용을 입력해주세요';
}

return '';
Expand Down
6 changes: 3 additions & 3 deletions frontend/src/hooks/template/useTemplateUpload.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ export const useTemplateUpload = () => {

const handleDeleteSourceCode = (index: number) => {
if (!sourceCodes[index]) {
console.error('존재하지 않는 스니펫 인덱스입니다.');
console.error('존재하지 않는 소스코드 인덱스입니다.');
}

setSourceCodes((prevSourceCodes) => prevSourceCodes.filter((_, idx) => index !== idx));
Expand All @@ -72,11 +72,11 @@ export const useTemplateUpload = () => {
}

if (sourceCodes.filter((sourceCode) => !sourceCode.filename).length) {
return '파일 명을 입력해주세요';
return '파일명을 입력해주세요';
}

if (sourceCodes.filter((sourceCode) => !sourceCode.content).length) {
return '스니펫 내용을 입력해주세요';
return '소스코드 내용을 입력해주세요';
}

return '';
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/pages/MyTemplatesPage/MyTemplatePage.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ describe('MyTemplatePage', () => {
});
});

test('키워드 검색 (스니펫): "Hello, World"를 검색하면 템플릿의 sourceCode에 "Hello, World"이 포함되어 있는지 확인', async () => {
test('키워드 검색 (소스코드): "Hello, World"를 검색하면 템플릿의 sourceCode에 "Hello, World"이 포함되어 있는지 확인', async () => {
const { getByPlaceholderText, getAllByText } = renderWithProviders(<MyTemplatePage />);

const searchInput = getByPlaceholderText('검색');
Expand Down
22 changes: 22 additions & 0 deletions frontend/src/service/validates.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,25 @@ export const validatePassword = (password: string) => {

export const validateConfirmPassword = (password: string, confirmPassword: string) =>
password === confirmPassword ? '' : '비밀번호가 일치하지 않습니다.';

export const validateFileName = (fileName: string) => {
const fileNamePattern = /^[가-힣a-zA-Z0-9_-]+\.[a-zA-Z]+$/;

const invalidChars = /[<>:"/\\|?*]/;

const maxLength = 255;

if (fileName.length > maxLength || fileName.length === 0) {
return '파일명의 길이는 1~255자로 입력해주세요!';
}

if (invalidChars.test(fileName)) {
return '특수 문자 (<, >, :, ", /, , |, ?, *)는 사용할 수 없습니다!';
}

if (!fileNamePattern.test(fileName)) {
return '확장자를 입력해주세요!';
}

return '';
};
Loading