From cb62173325e2f35c40805f9e0c76846ed9db1516 Mon Sep 17 00:00:00 2001 From: Cheonse <108046230+cheonseunghyeon@users.noreply.github.com> Date: Tue, 26 Sep 2023 18:18:16 +0900 Subject: [PATCH] =?UTF-8?q?Feat=20-=20=EA=B0=9C=EB=B0=9C=EC=9E=90=20?= =?UTF-8?q?=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EB=A7=81=ED=81=AC.=20=EC=8A=A4?= =?UTF-8?q?=ED=83=9D=20=EC=9D=B4=EC=8A=88=20=EA=B0=9C=EC=84=A0=20(#60)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../project/publish/ProjectPublish.tsx | 42 ++-- src/component/project/publish/component.tsx | 180 +++++++++++++++++- src/component/project/publish/hook.ts | 22 ++- 3 files changed, 219 insertions(+), 25 deletions(-) diff --git a/src/component/project/publish/ProjectPublish.tsx b/src/component/project/publish/ProjectPublish.tsx index 4f6edc7..98bf280 100644 --- a/src/component/project/publish/ProjectPublish.tsx +++ b/src/component/project/publish/ProjectPublish.tsx @@ -40,6 +40,8 @@ import { StackInput, DateRanges, CustomSelect, + StackInputContainer, + StackInput2, } from './component'; import { updateProjectCrew, @@ -115,8 +117,8 @@ const ProjectPublish = () => { const doAsyncWork = async (data: any) => { try { await mutation[0]({ accessToken, newProjectData: data }); - console.log(data); navigate('/project'); + // console.log(data); } catch (error) { console.error('데이터 전송 중 오류 발생:', error); navigate('/project/publish'); @@ -173,10 +175,6 @@ const ProjectPublish = () => { display: none; `} /> - - 서비스 형태가 들어가요 - 소속 클럽 이름이 들어가요 -
{ {/* */} 사용된 기술 스택 -
- {StackTags.length > 0 && - StackTags.map((StackTag) => { - return ( - - ); - })} - +
+
+ {StackTags.length > 0 && + StackTags.map((StackTag) => { + return ( + + ); + })} + +
diff --git a/src/component/project/publish/component.tsx b/src/component/project/publish/component.tsx index a16d50e..2de2a24 100644 --- a/src/component/project/publish/component.tsx +++ b/src/component/project/publish/component.tsx @@ -453,9 +453,11 @@ export const DateSelector = ({ // 기술 스택 컴포넌트 export function StackInput({ onAddStackTag }: StackInputProps) { const [inputStackTag, setInputStackTag] = useState(''); + const [alertShown, setAlertShown] = useState(false); const changeStackTagInput = (e: ChangeEvent) => { setInputStackTag(e.target.value); + setAlertShown(false); }; const isEmptyValue = (value: string) => { @@ -463,7 +465,7 @@ export function StackInput({ onAddStackTag }: StackInputProps) { }; const addStackTag = () => { - if (inputStackTag.length < 10) { + if (inputStackTag.length < 20) { if (isEmptyValue(inputStackTag)) { setInputStackTag(''); return; @@ -483,8 +485,10 @@ export function StackInput({ onAddStackTag }: StackInputProps) { onAddStackTag(newStackTag); setInputStackTag(''); - } else { - alert('10개 이상 불가능'); + } else if (!alertShown) { + alert('최대 글자를 초과했습니다.'); + setAlertShown(true); + setInputStackTag(''); } }; @@ -506,13 +510,14 @@ export function StackInput({ onAddStackTag }: StackInputProps) { onChange={changeStackTagInput} onKeyDown={onkeyDown} onBlur={onBlur} - placeholder="스택을 입력해주세요 (최대 10개)" + placeholder="스택을 입력해주세요" css={css` background: none; color: #fff; font-size: 2rem; letter-spacing: -0.6px; cursor: pointer; + width: 80rem; ${theme.typography.body1} &::placeholder { color: #cbcbcb; @@ -523,6 +528,173 @@ export function StackInput({ onAddStackTag }: StackInputProps) { ); } +export function StackInput2({ onAddStackTag }: StackInputProps) { + const [inputStackTag, setInputStackTag] = useState(''); + const [isInputVisible, setInputVisible] = useState(false); + + const changeStackTagInput = (e: ChangeEvent) => { + setInputStackTag(e.target.value); + }; + + const isEmptyValue = (value: string) => { + return !value.trim(); + }; + + const addStackTag = () => { + if (inputStackTag.length < 100) { + if (isEmptyValue(inputStackTag)) { + setInputStackTag(''); + return; + } + + let newStackTag = inputStackTag.trim(); + const regExp = /[{}[\]/?.;:|)*~`!^_+<>@#$%&\\=('"]/g; + if (regExp.test(newStackTag)) { + newStackTag = newStackTag.replace(regExp, ''); + } + if (newStackTag.endsWith(',')) { + newStackTag = newStackTag.slice(0, newStackTag.length - 1); + } + + if (isEmptyValue(newStackTag)) return; + + onAddStackTag(newStackTag); + + setInputStackTag(''); + } else { + alert('10개 이상 불가능'); + } + }; + + const onkeyDown = (e: React.KeyboardEvent) => { + const allowedCommand = [' ', 'Enter', ',']; + if (allowedCommand.includes(e.key)) { + e.preventDefault(); + addStackTag(); + } + }; + + const onBlur = () => { + addStackTag(); + setInputVisible(false); + }; + + const toggleInputVisibility = () => { + setInputVisible(!isInputVisible); + }; + + return ( +
+ + {isInputVisible && ( +
+ +
+ )} +
+ ); +} + +export const StackInputContainer = ({ + onAddStackTag, +}: { + onAddStackTag: (tag: string) => void; +}) => { + const [newStackTag, setNewStackTag] = useState(''); + const [stackTags, setStackTags] = useState([]); + + const handleInputChange = (event: React.ChangeEvent) => { + setNewStackTag(event.target.value); + }; + + const handleAddStackTag = () => { + if (newStackTag.trim() !== '') { + onAddStackTag(newStackTag); + setStackTags([...stackTags, newStackTag]); // 스택 태그 추가 + setNewStackTag(''); + } + }; + + return ( +
+ +
+ {stackTags.map((tag) => ( +
+ {tag} +
+ ))} +
+ +
+ ); +}; + export const OptionData = ({ data }: { data: any }) => { const [options, setOptions] = useState([{ value: 0, label: '소속 클럽 없음' }]); diff --git a/src/component/project/publish/hook.ts b/src/component/project/publish/hook.ts index 5015ec5..7d51a9c 100644 --- a/src/component/project/publish/hook.ts +++ b/src/component/project/publish/hook.ts @@ -40,11 +40,21 @@ export const useFormFields = (State: any) => { export default useFormFields; export const extractSubstring = (input: string) => { - const startIndex = input.indexOf('//'); - const endIndex = input.indexOf('.'); - - if (startIndex !== -1 && endIndex !== -1) { - return input.slice(startIndex + 2, endIndex); + const wwwIndex = input.indexOf('www'); + if (wwwIndex !== -1) { + // 'www'가 있는 경우 + const startIndex = input.indexOf('.', wwwIndex); // 'www' 다음의 첫 번째 '.'를 찾습니다. + const endIndex = input.indexOf('.', startIndex + 1); // 첫 번째 '.' 다음의 '.'를 찾습니다. + if (startIndex !== -1 && endIndex !== -1) { + return input.slice(startIndex + 1, endIndex); // 'www' 다음의 '.' 다음부터 추출합니다. + } + } else { + // 'www'가 없는 경우 + const startIndex = input.indexOf('//'); + const endIndex = input.indexOf('.'); + if (startIndex !== -1 && endIndex !== -1) { + return input.slice(startIndex + 2, endIndex); + } } return null; }; @@ -192,7 +202,7 @@ export const validateProjectData = (otherData: any) => { alert('유효하지 않은 팀원 구성입니다'); return 'teamInfoContainer'; } - const regex = /^(http|https):\/\/.*\.com$/; + const regex = /^(http|https):\/\/.*\./; if (!otherData.projectLink.every((item: any) => regex.test(item.linkUrl.trim()))) { alert('한 개 이상의 유효하지 않은 링크가 존재합니다'); return 'LinkContainer';