Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
d21d26e
docs: Search -> Explore 넀이밍
junghyungo Aug 11, 2025
c294d7a
Merge branch 'develop' of https://github.com/KUIT-BARO/BARO-FRONTEND …
junghyungo Aug 16, 2025
4bc50a9
feat: 탐색 νŽ˜μ΄μ§€ κ΅¬ν˜„
junghyungo Aug 16, 2025
9835e11
feat: ν•€ 등둝 νŽ˜μ΄μ§€ κ΅¬ν˜„
junghyungo Aug 16, 2025
6ee9382
feat: ν•€ μ—΄λžŒ νŽ˜μ΄μ§€ κ΅¬ν˜„
junghyungo Aug 17, 2025
bb832b4
style: css μˆ˜μ •
junghyungo Aug 17, 2025
ee78151
feat: λͺ©μ—… 데이터 μΆ”κ°€
junghyungo Aug 17, 2025
b7666fe
code review: ν•€ μ €μž₯ λ²„νŠΌ μ ‘κ·Όμ„± 보강
junghyungo Aug 17, 2025
a76fd90
code review: μž₯μ†Œ 이미지 쑰건뢀 λ Œλ”λ§
junghyungo Aug 17, 2025
ecded4d
code review: μΉ΄ν…Œκ³ λ¦¬ λ Œλ”λ§ key μΆ”κ°€
junghyungo Aug 17, 2025
d488399
code review: review ν•„λ“œ 제거
junghyungo Aug 17, 2025
d346425
code review: 경둜 인코딩
junghyungo Aug 17, 2025
9fa2fa2
feat: PlaceReview μ»΄ν¬λ„ŒνŠΈ Star μΆ”κ°€
junghyungo Aug 17, 2025
70cf9ab
fix: Develop 브랜치 Pull & Conflicts μˆ˜μ •
junghyungo Aug 20, 2025
e4597b1
fix: conflict μˆ˜μ •
junghyungo Aug 21, 2025
ed1bf90
fix: PopupOverlay import 경둜 μˆ˜μ •
junghyungo Aug 21, 2025
d2138dd
code review: ConfirmPopup rfc μˆ˜μ •
junghyungo Aug 21, 2025
2201fa1
code review: PlacePins νŽ˜μ΄μ§€ placeName κΈ°λ³Έκ°’ μˆ˜μ •;
junghyungo Aug 21, 2025
f78c22b
code review: handlePinClick 데이터 νƒ€μž… μˆ˜μ •
junghyungo Aug 21, 2025
90b9456
code review: PinReviewInput κΈ€μžμˆ˜ μ œν•œ μˆ˜μ •
junghyungo Aug 21, 2025
4d82f14
code review: 핀등둝 νŽ˜μ΄μ§€ 별점 μž…λ ₯ μˆ˜μ •
junghyungo Aug 21, 2025
9bd3e76
code review: zod μˆ˜μ •
junghyungo Aug 21, 2025
8541a88
code review: ExploreData -> PinListData
junghyungo Aug 21, 2025
2c37069
code review: css μˆ˜μ •
junghyungo Aug 21, 2025
5f3eb63
feat: 이미지 νƒ€μž… μœ νš¨μ„± 검증
junghyungo Sep 7, 2025
352e8e5
code reivew: 리뷰 κΈ€μžμˆ˜ μ œν•œ μˆ˜μ •
junghyungo Sep 7, 2025
9c84eaf
code review: λ°˜ν™˜λ˜λŠ” categoryIds 인덱슀 μˆ˜μ •
junghyungo Sep 7, 2025
0ae65b0
code review: 쿼리슀트링 μˆ˜μ •
junghyungo Sep 7, 2025
1f34fba
code review: ν•€ λͺ©λ‘ νŽ˜μ΄μ§€ 헀더 μ•„μ΄μ½˜ μˆ˜μ •
junghyungo Sep 7, 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
41 changes: 41 additions & 0 deletions src/pages/explore/Explore.css.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { style } from '@vanilla-extract/css';
import { vars } from '@shared/styles/theme.css';

export const exploreWrapper = style({
display: 'flex',
flexDirection: 'column',
minHeight: '100vh',
width: '100%',
});

export const exploreHeader = style({
position: 'sticky',
top: 0,
display: 'flex',
alignItems: 'center',
justifyContent: 'space-between',
width: '100%',
gap: '1rem',
padding: '2rem',
backgroundColor: vars.color.blue0,
zIndex: 10,
});

export const addPinIcon = style({
width: '4rem',
height: '4rem',
});

export const exploreContent = style({
display: 'flex',
flexDirection: 'column',
gap: '1rem',
backgroundColor: vars.color.blue0,
});

export const explorePlaces = style({
display: 'flex',
flexDirection: 'column',
backgroundColor: vars.color.blue0,
flex: 1,
});
14 changes: 14 additions & 0 deletions src/pages/explore/Explore.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import * as styles from '@pages/explore/Explore.css';
import ExploreHeader from '@pages/explore/ExploreHeader';
import ExploreContent from '@pages/explore/ExploreContent';
import ExplorePlaces from '@pages/explore/ExplorePlaces';

export default function Explore() {
return (
<div className={styles.exploreWrapper}>
<ExploreHeader />
<ExploreContent />
<ExplorePlaces />
</div>
);
}
34 changes: 34 additions & 0 deletions src/pages/explore/ExploreContent.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { useState } from 'react';
import * as styles from '@pages/explore/Explore.css';
import CategoryTag from '@shared/components/categoryTag/CategoryTag';
import type { CategoryType } from '@shared/constant/category';
import KakaoMap from '@shared/components/kakaoMap/KakaoMap';
import { MAP_SIZE } from '@shared/components/kakaoMap/constant/mapSize';
import { mockupPinData } from '@shared/components/kakaoMap/mockup';

export default function ExploreContent() {
const [selectedCategory, setSelectedCategory] = useState<CategoryType>('ALL');

const handleCategorySelected = (category: CategoryType) => {
setSelectedCategory(category);
};

// μ„ νƒλœ μΉ΄ν…Œκ³ λ¦¬μ— 따라 Pin Data 필터링
const filteredPinData = selectedCategory === 'ALL'
? mockupPinData
: mockupPinData.filter(pin =>
pin.pinCategories.includes(selectedCategory)
);

return (
<div className={styles.exploreContent}>
<CategoryTag
onTagSelected={handleCategorySelected}
/>
<KakaoMap
size={MAP_SIZE.SMALL}
pinData={filteredPinData}
/>
</div>
);
}
33 changes: 33 additions & 0 deletions src/pages/explore/ExploreHeader.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { useState, type ChangeEvent } from 'react';
import { useNavigate } from 'react-router-dom';
import * as styles from '@pages/explore/Explore.css';
import InputBar from '@shared/components/inputBar/InputBar';
import { IcWriteBlue } from '@svg/index';

export default function ExploreHeader() {
const navigate = useNavigate();
const [searchValue, setSearchValue] = useState('');

const handleInputChange = (e: ChangeEvent<HTMLInputElement>) => {
setSearchValue(e.target.value);
};

const handleAddPinClick = () => {
navigate('/pin/add');
}

return(
<div className={styles.exploreHeader}>
<InputBar
leftIcon='search'
placeholder='μž₯μ†Œλ₯Ό κ²€μƒ‰ν•˜μ„Έμš”'
value={searchValue}
onChange={handleInputChange}
/>
<IcWriteBlue
className={styles.addPinIcon}
onClick={handleAddPinClick}
/>
</div>
)
}
19 changes: 19 additions & 0 deletions src/pages/explore/ExplorePlaces.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import * as styles from '@pages/explore/Explore.css';
import PlaceReviewList from '@shared/components/placeReview/PlaceReview';
import { reviewCategories } from '@pages/explore/mockup';

export default function ExplorePlaces() {
return (
<div className={styles.explorePlaces}>
{reviewCategories.map((category, index) => (
<PlaceReviewList
key={index}
reviewType={category.reviewType}
description={category.description}
places={category.places}
placeReviewSize={category.placeReviewSize}
/>
))}
</div>
);
}
57 changes: 57 additions & 0 deletions src/pages/explore/mockup.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { mockupPlaces, type PlaceData } from '@shared/components/placeReview/mockup';
import type { PinListData } from '@pages/placePins/types/Pins';

interface ReviewCategory {
reviewType: string;
description: string;
places: PlaceData[];
placeReviewSize: 'SMALL' | 'LARGE';
}

export const reviewCategories: ReviewCategory[] = [
{
reviewType: 'BEST',
description: 'μ’‹μ•„μš”λ₯Ό κ°€μž₯ 많이 받은 λͺ…μ†Œ',
places: mockupPlaces,
placeReviewSize: 'SMALL',
},
{
reviewType: 'λΉ„μ¦ˆλ‹ˆμŠ€',
description: 'νšŒμ˜μ™€ 업무에 λ”± λ§žλŠ” μž₯μ†Œ',
places: mockupPlaces,
placeReviewSize: 'LARGE',
},
{
reviewType: 'μŠ€ν„°λ””',
description: '효율적인 곡뢀λ₯Ό μœ„ν•œ 졜적의 μž₯μ†Œ',
places: mockupPlaces,
placeReviewSize: 'LARGE',
},
];

export const mockupExplore: PinListData[] = [
{
pinId: 1,
pin: {
userName: 'μ΄μ§€ν™˜',
userEmail: 'hong@example.com',
profileImage: 'https://example.com/profile.jpg',
review: 'μ•„μ£Ό 쒋은 μž₯μ†Œμ˜€μŠ΅λ‹ˆλ‹€.',
score: 3,
placeName: 'μ„œμšΈ 광진ꡬ 화양동 5-47',
},
categories: ['μ•„λŠ‘ν•œ', 'ν‚€μ¦ˆμ‘΄', 'λΆμ μ΄λŠ”'],
},
{
pinId: 2,
pin: {
userName: 'μ΄μ§€ν™˜',
userEmail: 'hong@example.com',
profileImage: 'https://example.com/profile.jpg',
review: 'μ•„μ£Ό 쒋은 μž₯μ†Œμ˜€μŠ΅λ‹ˆλ‹€.',
score: 2,
placeName: 'μ„œμšΈ 광진ꡬ 화양동 5-47',
},
categories: ['μ•„λŠ‘ν•œ', 'ν‚€μ¦ˆμ‘΄', 'λΆμ μ΄λŠ”'],
},
];
25 changes: 25 additions & 0 deletions src/pages/pinAdd/PinAdd.css.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { style } from '@vanilla-extract/css';
import { vars } from '@styles/theme.css';

export const pinAddWrapper = style({
display: 'flex',
flexDirection: 'column',
width: '100%',
height: '100vh',
background: `var(--Linear, linear-gradient(180deg, ${vars.color.baroBlue} 0%, ${vars.color.blue8} 100%))`,
});

export const submitButton = style({
width: '100%',
marginRight: '2.1rem',
fontSize: vars.font.body_bold_16.fontSize,
fontWeight: vars.font.body_bold_16.fontWeight,
color: vars.color.white,
whiteSpace: 'nowrap',
cursor: 'pointer',
});

export const pinReviewContainer = style({
display: 'flex',
flexDirection: 'column',
});
82 changes: 82 additions & 0 deletions src/pages/pinAdd/PinAdd.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import { useNavigate } from 'react-router-dom';
import { useState } from 'react';
import * as styles from '@pages/pinAdd/PinAdd.css';
import Header from '@shared/components/header/Header';
import Container from '@shared/components/container/Container';
import PinPlaceInput from './component/pinPlaceInput/PinPlaceInput';
import PinPhotoInput from '@pages/pinAdd/component/pinPhotoInput/PinPhotoInput';
import PinReviewInput from '@pages/pinAdd/component/pinReviewInput/PinReviewInput';
import PinScoreInput from '@pages/pinAdd/component/pinScoreInput/PinScoreInput';
import PinCategoriesInput from '@pages/pinAdd/component/pinCategoriesInput/PinCategoriesInput';
import ConfirmPopup from './component/confirmPopup/ConfirmPopup';
import { IcArrowLeft } from '@svg/index';
import {
usePinAddValidation,
convertToApiData
} from '@pages/pinAdd/hook/usePinAddValidation';

export default function PinAdd() {
const navigate = useNavigate();
const { register, watch, formState: { errors }, setValue, handleSubmit } = usePinAddValidation();
const [showConfirmPopup, setShowConfirmPopup] = useState(false);

const watchedValues = watch();

const handleBackClick = () => {
navigate(-1);
};

const handleSubmitClick = () => {
handleSubmit(() => {
setShowConfirmPopup(true);
})();
};

const handleConfirmClick = () => {
const apiData = convertToApiData(watchedValues);
console.info(apiData);
setShowConfirmPopup(false);
navigate('/explore');
};

const handleConfirmClose = () => {
setShowConfirmPopup(false);
};

return (
<div className={styles.pinAddWrapper}>
<Header
background='baroblue'
leftIcon={() => (
<IcArrowLeft onClick={handleBackClick} />
)}
text='ν•€ μΆ”κ°€'
rightIcon={() => (
<button
type='button'
className={styles.submitButton}
onClick={handleSubmitClick}
>
등둝
</button>
)}
/>
<Container className={styles.pinReviewContainer}>
<PinPlaceInput />
<PinPhotoInput setValue={setValue} errors={errors} />
<PinReviewInput register={register} watch={watch} errors={errors} />
</Container>
<PinScoreInput setValue={setValue} watch={watch} errors={errors} />
<PinCategoriesInput setValue={setValue} watch={watch} errors={errors} />

<ConfirmPopup
open={showConfirmPopup}
onClose={handleConfirmClose}
onConfirm={handleConfirmClick}
score={watchedValues.score}
max={5}
categories={watchedValues.categories}
/>
</div>
);
}
34 changes: 34 additions & 0 deletions src/pages/pinAdd/component/confirmPopup/ConfirmPopup.css.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { style } from '@vanilla-extract/css';
import { vars } from '@shared/styles/theme.css';

export const popupContents = style({
display: 'flex',
flexDirection: 'column',
width: '100%',
padding: '8.2rem 2.4rem 1.4rem 2.4rem',
backgroundColor: vars.color.white,
borderRadius: '16px 16px 0 0',
});

export const reviewWrapper = style({
display: 'flex',
flexDirection: 'column',
alignItems: 'flex-start',
gap: '1.6rem',
});

export const categoriesContainer = style({
display: 'flex',
gap: '0.4rem',
alignItems: 'center',
marginTop: '3.2rem',
});

export const categoriesGrid = style({
display: 'flex',
flexWrap: 'wrap',
alignContent: 'flex-start',
justifyContent: 'space-between',
marginBottom: '4.5rem',
rowGap: '0.8rem',
});
Loading
Loading