Skip to content
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
3 changes: 2 additions & 1 deletion next.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ const nextConfig: NextConfig = {
remotePatterns: [
{
protocol: 'https',
hostname: 'storage.googleapis.com',
hostname: 'api.wishpool.store',
pathname: '/image/**',
},
],
},
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"private": true,
"packageManager": "[email protected]",
"scripts": {
"dev": "next dev",
"dev": "next dev --webpack",
"build": "next build --webpack",
"start": "next start",
"lint": "eslint .",
Expand Down
1 change: 1 addition & 0 deletions src/api/domain/join/types.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
export type GiftItemDto = {
itemUrl: string;
itemName: string;
imageUrl?: string;
};

export type WishpoolJoinRequest = {
Expand Down
3 changes: 2 additions & 1 deletion src/app/pick/list/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,13 @@ const ListPage = () => {
<span>{items.length}개</span>
</div>
<section className="grid grid-cols-2 gap-[1.1rem]">
{items.map(({ giftId, itemName, itemUrl }) => (
{items.map(({ giftId, itemName, itemUrl, imageUrl }) => (
<GiftCard
key={giftId}
giftId={giftId}
itemName={itemName}
itemUrl={itemUrl}
imageUrl={imageUrl}
/>
))}
</section>
Expand Down
3 changes: 2 additions & 1 deletion src/app/pick/preview/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,13 +48,14 @@ const PreviewPage = () => {
<h1 className="text-blue-primary caption1">최종 점검</h1>
<h2 className="head1 text-text">최종 선택한 선물</h2>
<section className="my-[2.8rem] space-y-[1.2rem]">
{pickedItems.map(({ giftId, itemName, itemUrl }) => (
{pickedItems.map(({ giftId, itemName, itemUrl, imageUrl }) => (
<GiftCard
key={giftId}
size="big"
giftId={giftId}
itemName={itemName}
itemUrl={itemUrl}
imageUrl={imageUrl}
/>
))}
</section>
Expand Down
3 changes: 2 additions & 1 deletion src/app/pick/select/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ const SelectPage = () => {
className="no-scrollbar bg-blue-5 flex snap-x snap-mandatory gap-[2.4rem] overflow-x-auto overflow-y-hidden px-[2rem] pt-[7rem] pb-[5rem]"
>
<div aria-hidden className="w-[calc(50vw-9rem)] shrink-0 snap-none" />
{items.map(({ giftId, itemName, itemUrl }, i) => (
{items.map(({ giftId, itemName, itemUrl, imageUrl }, i) => (
<CarouselCard
key={giftId}
giftId={giftId}
Expand All @@ -61,6 +61,7 @@ const SelectPage = () => {
itemName={itemName}
itemUrl={itemUrl}
onRemove={handleRemove}
imageUrl={imageUrl}
/>
))}
<div aria-hidden className="w-[calc(50vw-9rem)] shrink-0 snap-none" />
Expand Down
6 changes: 3 additions & 3 deletions src/app/wishpool/(viewer)/[id]/date/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,9 @@ const DatePage = () => {
pickDate: endDate,
});

const chosenUrl = res.chosenUrl;
sessionStorage.setItem('chosenUrl', chosenUrl);
router.push(PATH.WISHPOOL_INVITE(wishpoolId));
router.push(
PATH.WISHPOOL_INVITE(wishpoolId) + `?chosenUrl=${res.chosenUrl}`,
);
} catch {
alert('선물 고르기 마감일 설정에 실패했습니다.');
}
Expand Down
1 change: 1 addition & 0 deletions src/app/wishpool/(viewer)/[id]/final/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ const FinalPage = () => {
giftId={giftId}
itemName={giftName}
itemUrl={giftImage}
imageUrl={giftImage}
/>
),
)}
Expand Down
1 change: 1 addition & 0 deletions src/app/wishpool/(viewer)/[id]/gifts/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ const GiftPage = () => {
guest={gift.guest || ''}
itemName={gift.itemName}
itemUrl={gift.itemUrl}
imageUrl={gift.imageUrl}
/>
))}
</div>
Expand Down
3 changes: 2 additions & 1 deletion src/app/wishpool/(viewer)/[id]/invite/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import invite from '@/assets/images/invite.png';
import WishpoolShareSection from '@/components/common/WishpoolShareBox';
import { PATH } from '@/constants/common/path';
import { useGetWishpoolId } from '@/hooks/common/useGetWishpoolId';
import { useGetChosenUrl } from '@/hooks/pick/useGetChosenUrl';
import { ShareSectionType } from '@/types/common/ShareSectionType';

const getOrigin = () => {
Expand All @@ -17,7 +18,7 @@ const getOrigin = () => {
const InvitePage = () => {
const content = 'invite' as ShareSectionType;

const chosenUrl = sessionStorage.getItem('chosenUrl') || '';
const chosenUrl = useGetChosenUrl();
const origin = getOrigin();
const inviteUrl = `${origin}${PATH.PICK_INVITE}?chosenUrl=${chosenUrl}`;

Expand Down
2 changes: 2 additions & 0 deletions src/app/wishpool/join/[id]/add/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -99,8 +99,10 @@ const AddPage = () => {
maxLength={20}
valueItemName={gift.itemName}
valueLink={gift.itemUrl}
valueImageUrl={gift.imageUrl}
onChangeItemName={(v) => handleGiftChange(idx, 'itemName', v)}
onChangeLink={(v) => handleGiftChange(idx, 'itemUrl', v)}
onChangeImage={(v) => handleGiftChange(idx, 'imageUrl', v)}
onRemove={() => removeGift(idx)}
/>
</div>
Expand Down
25 changes: 18 additions & 7 deletions src/app/wishpool/join/[id]/preview/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ import GiftCardImage from '@/assets/images/gift-card.png';
import Button from '@/components/common/Button';
import UserTag from '@/components/common/UserTag';
import { PATH } from '@/constants/common/path';
import { WISHPOOL_IMAGE_BASE_URL } from '@/constants/wishpool/image';
import { useGetWishpoolId } from '@/hooks/common/useGetWishpoolId';

const PreviewPage = () => {
const router = useRouter();
const wishpoolId = useGetWishpoolId();
Expand Down Expand Up @@ -63,12 +63,23 @@ const PreviewPage = () => {
key={`${gift.itemName}-${idx}`}
className="flex flex-col items-center justify-center"
>
<Image
src={GiftCardImage}
alt="선물 카드 이미지"
width={155}
height={155}
/>
{gift.imageUrl ? (
<div className="relative h-[15.5rem] w-[15.5rem]">
<Image
src={`${WISHPOOL_IMAGE_BASE_URL}/${gift.imageUrl}`}
alt="등록 선물 이미지"
fill
className="object-cover"
/>
</div>
) : (
<Image
src={GiftCardImage}
alt="기본 선물 이미지"
width={155}
height={155}
/>
)}
<span className="subtitle2 text-text mt-[0.7rem] mb-[1rem] line-clamp-2 h-[4.8rem] text-center">
{gift.itemName}
</span>
Expand Down
2 changes: 2 additions & 0 deletions src/assets/icons/iconMap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import CalendarIcon from '@/assets/icons/svg/icon_calender.svg';
import CameraIcon from '@/assets/icons/svg/icon_camera.svg';
import CancelIcon from '@/assets/icons/svg/icon_cancel.svg';
import CheerIcon from '@/assets/icons/svg/icon_cheer.svg';
import DeleteIcon from '@/assets/icons/svg/icon_delete.svg';
import DotIcon from '@/assets/icons/svg/icon_dot.svg';
import DownIcon from '@/assets/icons/svg/icon_down.svg';
import GiftIcon from '@/assets/icons/svg/icon_gift.svg';
Expand Down Expand Up @@ -54,6 +55,7 @@ export const iconMap = {
next: NextIcon,
ribbon: RibbonIcon,
loading: LoadingIcon,
delete: DeleteIcon,
} as const;

export type IconName = keyof typeof iconMap;
4 changes: 4 additions & 0 deletions src/assets/icons/svg/icon_delete.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
110 changes: 84 additions & 26 deletions src/components/common/Form/GiftField.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
import { GiftItemDto } from '@/api/domain/join/types';
import Image from 'next/image';
import { useEffect, useRef } from 'react';

import Icon from '@/components/common/Icon';
import { WISHPOOL_IMAGE_BASE_URL } from '@/constants/wishpool/image';
import { useImageUpload } from '@/hooks/wishpool/useImageUpload';
import { patchGift } from '@/utils/wishpool/viewer/manageGifts';

type GiftFieldProps = {
index: number;
Expand All @@ -8,35 +13,12 @@
maxLength?: number;
valueItemName: string;
valueLink: string;
valueImageUrl?: string | null;
onChangeItemName: (v: string) => void;
onChangeLink: (v: string) => void;
onChangeImage: (v: string) => void;
onRemove: () => void;
};
const STORAGE_KEY = 'wishpool_gifts';

function readGifts(): GiftItemDto[] {
try {
const raw = sessionStorage.getItem(STORAGE_KEY);
if (!raw) return [];
const parsed = JSON.parse(raw);
return Array.isArray(parsed) ? parsed : [];
} catch {
return [];
}
}

function writeGifts(next: GiftItemDto[]) {
sessionStorage.setItem(STORAGE_KEY, JSON.stringify(next));
}

function patchGift(index: number, patch: Partial<GiftItemDto>) {
const current = readGifts();

const base: GiftItemDto = current[index] ?? { itemName: '', itemUrl: '' };
const next = [...current];
next[index] = { ...base, ...patch };
writeGifts(next);
}

const GiftField = ({
index,
Expand All @@ -45,10 +27,16 @@
maxLength,
valueItemName,
valueLink,
valueImageUrl,
onChangeItemName,
onChangeLink,
onChangeImage,
onRemove,
}: GiftFieldProps) => {
const fileInputRef = useRef<HTMLInputElement>(null);
const { isUploading, preview, imageKey, handleImageChange, reset } =
useImageUpload();

const handleNameChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const newItemName = e.target.value;
onChangeItemName(newItemName);
Expand All @@ -61,6 +49,23 @@
patchGift(index, { itemUrl: newUrlName });
};

useEffect(() => {
if (!imageKey) return;
onChangeImage(imageKey);
patchGift(index, { imageUrl: imageKey });
}, [imageKey]);

Check warning on line 56 in src/components/common/Form/GiftField.tsx

View workflow job for this annotation

GitHub Actions / build

React Hook useEffect has missing dependencies: 'index' and 'onChangeImage'. Either include them or remove the dependency array. If 'onChangeImage' changes too often, find the parent component that defines it and wrap that definition in useCallback

Check warning on line 56 in src/components/common/Form/GiftField.tsx

View workflow job for this annotation

GitHub Actions / build

React Hook useEffect has missing dependencies: 'index' and 'onChangeImage'. Either include them or remove the dependency array. If 'onChangeImage' changes too often, find the parent component that defines it and wrap that definition in useCallback

const handleDeleteImage = () => {
reset();
onChangeImage('');
patchGift(index, { imageUrl: '' });
};

const imageSrc = valueImageUrl
? `${WISHPOOL_IMAGE_BASE_URL}/${valueImageUrl}`
: null;

const displayImageSrc = preview ?? imageSrc;
return (
<>
<div className="mt-[4rem] mb-[0.8rem] flex justify-between">
Expand Down Expand Up @@ -100,6 +105,59 @@
className="body1 flex h-[5.6rem] w-full rounded-[12px] border border-gray-400 px-[1.6rem] py-[1.6rem] placeholder:text-gray-400 focus:border-gray-400 focus:outline-none"
/>
</div>
<input
ref={fileInputRef}
type="file"
accept="image/*"
className="hidden"
onChange={handleImageChange}
disabled={isUploading}
/>

<div className="mt-[1.2rem]">
{displayImageSrc ? (
<div className="relative">
<Image
src={displayImageSrc}
alt="선물 이미지 미리보기"
width={82}
height={82}
className="h-[8.2rem] w-[8.2rem] rounded-[12px] border border-gray-400"
/>
<span className="absolute top-[0.6rem] left-[6rem]">
<button
type="button"
onClick={() => handleDeleteImage()}
aria-label="선물 이미지 삭제"
>
<Icon name="delete" width={16} height={16} />
</button>
</span>
</div>
) : (
<div className="mt-[1.2rem]">
<div className="flex h-[5.6rem] w-full gap-[1.2rem] rounded-[12px] border border-gray-400 px-[1.6rem] py-[1.6rem] focus:border-gray-400 focus:outline-none">
<button
type="button"
onClick={() => fileInputRef.current?.click()}
aria-label="선물 이미지 추가"
disabled={isUploading}
>
<Icon
name="photo"
width={24}
height={24}
className="text-gray-600"
/>
</button>
<p className="body1 text-text">선물 사진 추가</p>
</div>
<p className="caption2 text-blue-primary mt-[0.8rem]">
*사진을 추가하지 않을 때는 기본 이미지로 보여줄게요.
</p>
</div>
)}
</div>
</>
);
};
Expand Down
8 changes: 6 additions & 2 deletions src/components/pick/list/GiftCard.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import Image from 'next/image';

import { useGetWishpoolImage } from '@/api/domain/detail/hooks';
import GiftCardImage from '@/assets/images/gift-card.png';
import type { GiftCardType } from '@/types/common/giftCardType';

Expand All @@ -13,16 +14,19 @@ const GiftCard = ({
size = 'small',
giftId,
itemName,
//itemUrl,
imageUrl,
}: GiftCardProps) => {
const isSmall = size === 'small';

const { data: imageData } = useGetWishpoolImage(imageUrl);
const finalSrc = imageData && imageData.key ? imageData.key : GiftCardImage;

return (
<div
className={`bg-background-01 flex grow-1 flex-col items-center gap-[2.4rem] rounded-[16px] ${isSmall ? 'p-[2.2rem]' : 'p-[6.4rem]'}`}
>
<Image
src={GiftCardImage}
src={finalSrc}
alt={`선물 카드 이미지 - ${giftId}`}
width={isSmall ? 126 : 170}
height={isSmall ? 126 : 170}
Expand Down
Loading
Loading