Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
e4dcbc3
feat: 사진 6장 제한
jw0202058 Jul 23, 2025
43b435f
feat: 글자수, 상한 가격 제한
jw0202058 Jul 23, 2025
d4b1e10
feat: 확장자, 용량 제한
jw0202058 Jul 23, 2025
c9ad85e
chore: 주석 달기
jw0202058 Jul 23, 2025
49369a9
feat: 직거래 장소 글자수 제한
jw0202058 Jul 23, 2025
6fd7ccc
feat: chat, chatroom 만들다 말기
jw0202058 Jul 16, 2025
29fc353
chore: 배경색 추가
jw0202058 Jul 17, 2025
1560e94
feat: chat, chat room 뷰 완성
jw0202058 Jul 17, 2025
326391d
fix: 공용 버튼 variant 이름 바꾸기
jw0202058 Jul 17, 2025
3f2c417
feat: 시간 붙이기
jw0202058 Jul 17, 2025
7326925
chore: 더미 데이터 추가
jw0202058 Jul 17, 2025
2a7142c
fix: gap 조정
jw0202058 Jul 17, 2025
c219820
feat: chatList 더미데이터
jw0202058 Jul 17, 2025
7d104db
chore: 스크롤 되나 보라고 좀 더 추가함
jw0202058 Jul 17, 2025
3e0f57e
chore: chatList에 key 부여
jw0202058 Jul 17, 2025
350f452
feat: date 파싱
jw0202058 Jul 17, 2025
281ef86
feat: Pick Chat 추가
jw0202058 Jul 17, 2025
65b554c
chore: todo 주석 달기
jw0202058 Jul 17, 2025
b14e55c
fix: pick image w 고치기
jw0202058 Jul 17, 2025
4378645
chore: key
jw0202058 Jul 17, 2025
7ed9558
feat: 스크롤 맨 아래가 디폴트로 두기
jw0202058 Jul 17, 2025
a7845a1
feat: 채팅 간 gap, 날짜 추가
jw0202058 Jul 18, 2025
32e7662
fix: 손보기
jw0202058 Jul 23, 2025
614839b
feat: login page 구현
halionaz Jul 15, 2025
3c579b2
feat: AuthGuard 구현 구현
halionaz Jul 15, 2025
85023db
fix: navigate logic
halionaz Jul 15, 2025
9cb4330
chore: base url 수정
halionaz Jul 15, 2025
7232f91
fix: 확실하지 않을땐 렌더링 생략
halionaz Jul 15, 2025
f0d7875
fix: thx copilot :: router path 명확하게 하기
halionaz Jul 15, 2025
226eef6
chore: delete vite base url
halionaz Jul 22, 2025
1d3c207
chore: delete dev github action logic
halionaz Jul 23, 2025
4675380
chore: delete gh-action
halionaz Jul 23, 2025
0c16ec7
feat: 사진 6장 제한
jw0202058 Jul 23, 2025
72d672a
feat: 글자수, 상한 가격 제한
jw0202058 Jul 23, 2025
3aa966b
feat: 확장자, 용량 제한
jw0202058 Jul 23, 2025
5119326
chore: 주석 달기
jw0202058 Jul 23, 2025
a653a22
feat: 직거래 장소 글자수 제한
jw0202058 Jul 23, 2025
7569ca0
Merge branch 'feat/#93/post-limit' of https://github.com/DevKor-githu…
jw0202058 Jul 23, 2025
7b1eacd
fix: thx 까치,,, constants로 옮기기
jw0202058 Jul 23, 2025
126f5cf
fix: thx 까치git add . accept 속성으로 확장자 제한 걸기
jw0202058 Jul 23, 2025
6682728
fix: 효율추구하기
jw0202058 Jul 24, 2025
2846142
Merge branch 'dev' into feat/#93/post-limit
jw0202058 Jul 24, 2025
217eeab
Merge branch 'dev' into feat/#93/post-limit
jw0202058 Jul 24, 2025
0102abc
Merge remote-tracking branch 'origin/dev' into feat/#93/post-limit
jw0202058 Jul 24, 2025
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
6 changes: 5 additions & 1 deletion src/features/post/components/InputField/index.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
import { MAX_PRICE } from '@/libs/constants';
import * as s from './style.css';
import { useState } from 'react';

interface InputProps<T extends number | string> {
className?: string;
value: T;
setValue: (value: T) => void;
maxLength?: number;
}

const InputField = <T extends number | string>({ className, value, setValue }: InputProps<T>) => {
const InputField = <T extends number | string>({ className, value, setValue, maxLength }: InputProps<T>) => {
const [isFocused, setIsFocused] = useState(false);

const isNumber = typeof value === 'number';
Expand All @@ -19,6 +21,7 @@ const InputField = <T extends number | string>({ className, value, setValue }: I
if (isNumber) {
const number = Number(raw.replace(/,/g, ''));
if (isNaN(number)) return;
if (number > MAX_PRICE) return;
setValue(number as T);
} else {
setValue(raw as T);
Expand All @@ -45,6 +48,7 @@ const InputField = <T extends number | string>({ className, value, setValue }: I
onBlur={handleBlur}
inputMode={isNumber ? 'numeric' : 'text'}
pattern={isNumber ? '[0-9]*' : undefined}
maxLength={maxLength}
/>
);
};
Expand Down
3 changes: 2 additions & 1 deletion src/features/post/components/StepFunnel/Step3/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import Token from '@/common/components/Token';
import InputField from '../../InputField';
import { useStep3Store } from '@/features/post/stores/Step3Store';
import { useStep1Store } from '@/features/post/stores/Step1Store';
import { MAX_LOCATION } from '@/libs/constants';

const Location = () => {
const locationStore = useStep3Store(state => state.location);
Expand All @@ -14,7 +15,7 @@ const Location = () => {
<div className={c.DetailContent}>
<div className={c.DetailContent}>
<span>직거래 장소를 입력해 주세요</span>
<InputField value={locationStore} setValue={locationSetter} />
<InputField value={locationStore} setValue={locationSetter} maxLength={MAX_LOCATION} />
</div>
</div>
);
Expand Down
42 changes: 32 additions & 10 deletions src/features/post/components/StepFunnel/Step5/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import * as c from '../style.css';
import SelectedPhoto from '../../uploadedPhoto';
import UploadFile from '../../UploadFile';
import { useStep5Store } from '@/features/post/stores/Step5Store';
import { ALLOWED_EXTENSIONS, MAX_DESC, MAX_SIZE_BYTES, MAX_SIZE_MB, MAX_TITLE } from '@/libs/constants';

const Step5 = () => {
const fileStore = useStep5Store(state => state.files);
Expand All @@ -23,7 +24,22 @@ const Step5 = () => {

const fileArray = Array.from(files);

const updatedFiles = [...fileStore, ...fileArray];
const validFiles = fileArray.filter(file => {
// TODO: alert 어떻게 띄워줄지 디자인 요청

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

인정 알럿창 필요함

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

알럿

const ext = file.name.split('.').pop()?.toLowerCase();
console.log(ext);
if (!ext || !ALLOWED_EXTENSIONS.includes(ext)) {
alert(`"${file.name}"은(는) 지원하지 않는 확장자입니다.`);
return false;
}
if (file.size > MAX_SIZE_BYTES) {
alert(`"${file.name}"은(는) ${MAX_SIZE_MB}MB를 초과합니다.`);
return false;
}
return true;
});

const updatedFiles = [...fileStore, ...validFiles];
fileSetter(updatedFiles);
};

Expand All @@ -44,18 +60,24 @@ const Step5 = () => {
<header className={c.Head}>상품 소개를 작성해 주세요</header>
<div className={c.Content}>
<div className={c.DetailContent}>
상품명을 입력해 주세요
<InputField value={titleStore} setValue={titleSetter}></InputField>
상품명을 입력해 주세요 ({titleStore.length}/{MAX_TITLE})
<InputField value={titleStore} setValue={titleSetter} maxLength={MAX_TITLE}></InputField>
</div>
<div className={c.DetailContent}>
상품 설명을 입력해 주세요
상품 설명을 입력해 주세요 ({descStore.length}/{MAX_DESC})
<div className={s.ProductDesc}>
<MultilineInputfield onChange={handleDesc} value={descStore} />
<div className={s.SelectPhotoContainer}>
<UploadFile onChange={handleImageUploaded} />
{images.map((file, index) => (
<SelectedPhoto key={index} file={file} onClick={() => removeUploadedImage(index)} />
))}
<MultilineInputfield onChange={handleDesc} value={descStore} maxLength={MAX_DESC} />
<div className={s.PhotoLimit}>
<div className={s.SelectPhotoContainer}>
<UploadFile onChange={handleImageUploaded} />

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이거 UploadFile 까보면 파일 input에 accept?인가? 그런 속성 있을건데
거기에서 아예 확장자 제한을 해버릴 수도 있어요
그러면 탐색기에서 정해진 확장자 파일만 보여줌

근데 얘도 우회할 수 있어서 위 같은 validation 로직을 유지하긴 해야돼요
그치만 이것도 해두면 좀 더 깔끔할듯

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

오 굿 새롭게 알게 된 사실

{images.map((file, index) => (
<SelectedPhoto key={index} file={file} onClick={() => removeUploadedImage(index)} />
))}
</div>
<div className={s.AlertText}>
<span className="mgc_alert_octagon_fill"></span>
사진은 최대 6장까지 등록이 가능해요.
</div>
</div>
</div>
</div>
Expand Down
19 changes: 19 additions & 0 deletions src/features/post/components/StepFunnel/Step5/style.css.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,22 @@ export const SelectPhotoContainer = css({
alignItems: 'center',
flexWrap: 'wrap',
});

export const PhotoLimit = css({
display: 'flex',
flexDir: 'column',
gap: '1rem',
});

export const AlertText = css({
display: 'flex',
alignItems: 'center',
gap: '0.25rem',
color: '80',
fontFamily: 'Pretendard',
fontSize: '0.75rem',
fontStyle: 'normal',
fontWeight: '400',
lineHeight: 'normal',
letterSpacing: '-0.03rem',
});
9 changes: 8 additions & 1 deletion src/features/post/components/UploadFile/index.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { ALLOWED_EXTENSIONS } from '@/libs/constants';
import * as s from './style.css';

interface UploadPhotoProps {
Expand All @@ -7,7 +8,13 @@ interface UploadPhotoProps {
const UploadFile = ({ onChange }: UploadPhotoProps) => {
return (
<label className={s.SelectedPhotoBtn}>
<input type="file" accept="image/*" multiple onChange={onChange} className={s.Input} />
<input
type="file"
accept={ALLOWED_EXTENSIONS.map(val => '.' + val).join()}
multiple
onChange={onChange}
className={s.Input}
/>
<div className="mgc_camera_2_fill" />
</label>
);
Expand Down
3 changes: 2 additions & 1 deletion src/features/post/stores/Step5Store.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { MAX_FILE_LENGTH } from '@/libs/constants';
import { create } from 'zustand';

// 상품명, 상품설명, 사진
Expand Down Expand Up @@ -25,7 +26,7 @@ export const useStep5Store = create<Step5Store>((set, get) => ({

isBtnValid: () => {
const { title, desc, files } = get();
return title.trim() !== '' && desc.trim() !== '' && files.length !== 0;
return title.trim() !== '' && desc.trim() !== '' && files.length !== 0 && files.length <= MAX_FILE_LENGTH;
},

reset: () => {
Expand Down
7 changes: 7 additions & 0 deletions src/libs/constants/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,8 @@
export const MAX_PRICE = 999999;
export const MAX_LOCATION = 100;
export const MAX_TITLE = 64;
export const MAX_DESC = 1000;
export const ALLOWED_EXTENSIONS = ['jpg', 'jpeg', 'png', 'webp'];
export const MAX_SIZE_MB = 5;
export const MAX_SIZE_BYTES = MAX_SIZE_MB * 1024 * 1024;
export const MAX_FILE_LENGTH = 6;