Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
2 changes: 1 addition & 1 deletion src/components/features/noticeList/noticeListSection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ interface NoticeListSectionProps {
}

const NoticeListSection = ({ q, initialFilters }: NoticeListSectionProps) => {
const { notices, isLoading, isInitialized, error, pagination, fetchNotices,reset, filters } =
const { notices, isLoading, isInitialized, error, pagination, fetchNotices, reset, filters } =
useNotices();

useEffect(() => {
Expand Down
2 changes: 1 addition & 1 deletion src/components/layout/footer/footer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import Link from 'next/link';
const Footer = () => {
return (
<footer>
<Container className='max-w-full bg-gray-100'>
<Container className='max-w-full bg-gray-200'>
<div className='mx-auto flex flex-wrap justify-between gap-10 px-5 py-8 desktop:w-[964px]'>
<div className='order-3 flex-grow text-caption font-normal text-gray-500 tablet:order-1 tablet:flex-grow-0 tablet:text-body-m'>
©codeit - 2023
Expand Down
2 changes: 1 addition & 1 deletion src/context/authProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ export const AuthContext = createContext<AuthContextValue | null>(null);
const TOKEN_KEY = 'thejulge_token';
const USER_ID_KEY = 'thejulge_user_id';
const EXPIRES_KEY = 'thejulge_expires_at';
const EXPIRES_DURATION_MS = 10 * 60 * 1000; // 10분
const EXPIRES_DURATION_MS = 1000 * 60 * 1000; // 10분
Copy link
Contributor

Choose a reason for hiding this comment

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

재영님께서 수정해서 올리시면 신천님께서 다시계속 수정하셔서 이 부분은 커밋하실때 제외하시는게 좋을것 같습니다!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

네 수정했습니다!


/** storage helpers */
const isBrowser = () => typeof window !== 'undefined';
Expand Down
183 changes: 131 additions & 52 deletions src/pages/my-shop/index.tsx
Original file line number Diff line number Diff line change
@@ -1,80 +1,159 @@
import { getNotice, getShop } from '@/api/employer';
import { Frame } from '@/components/layout';
import { Button, Notice } from '@/components/ui';
import { Container, Frame } from '@/components/layout';
import { Button, Notice, Post } from '@/components/ui';
import useAuth from '@/hooks/useAuth';
import { NoticeItem, NoticeResponse, ShopItem } from '@/types/myShop';
import Link from 'next/link';
import { useEffect, useState } from 'react';

interface ShopItem {
id: string;
title?: string;
description?: string;
}
import { useCallback, useEffect, useRef, useState } from 'react';

const Myshop = () => {
const { user } = useAuth();
const [shopData, setShopData] = useState({});
const [shopNotice, setShopNotice] = useState({});
const [shopData, setShopData] = useState<ShopItem>({
id: '',
name: '',
category: '',
address1: '',
imageUrl: '',
originalHourlyPay: 0,
description: '',
});
const [shopNotice, setShopNotice] = useState<NoticeItem[]>([]);
const [nextOffset, setNextOffset] = useState<number | null>(0);
const [loading, setLoading] = useState(false);
const observerRef = useRef<HTMLDivElement | null>(null);

useEffect(() => {
if (!user?.shop) return;
const shopId = user.shop.item.id;

const get = async () => {
if (!user?.shop) return;
try {
const [shopRes, noticeRes] = await Promise.all([
getShop(user.shop.item.id),
getNotice(user.shop.item.id, { offset: 0, limit: 6 }),
]);

const shopRes = await getShop(shopId);
const { description, ...rest } = shopRes.item;
const formattedShopData = { ...rest, shopDescription: description };
setShopData(formattedShopData);
setShopNotice(noticeRes);
//console.log('공고 조회:', noticeRes);
setShopData({ ...rest, shopDescription: description });
setShopNotice([]);
setNextOffset(0);
loadMoreNotice();
} catch (error) {
alert(error);
}
};
get();
}, [user]);

const loadMoreNotice = useCallback(async () => {
if (!user?.shop || nextOffset === null || loading) return;
setLoading(true);
try {
const noticeRes: NoticeResponse = await getNotice(user.shop.item.id, {
offset: nextOffset,
limit: 6,
});
setShopNotice(prevShopNotice => {
const newItems = noticeRes.items.map(i => i.item);
const merged = [...prevShopNotice, ...newItems];
const unique = merged.filter(
(item, index, self) => index === self.findIndex(i => i.id === item.id)
);
return unique;
});
setNextOffset(noticeRes.hasNext ? nextOffset + noticeRes.items.length : null);
} catch (error) {
alert(error);
} finally {
setLoading(false);
}
}, [user?.shop, nextOffset, loading]);

useEffect(() => {
if (!observerRef.current) return;
const observer = new IntersectionObserver(
entries => {
if (entries[0].isIntersecting) {
loadMoreNotice();
}
},
{ threshold: 0.5 }
);
observer.observe(observerRef.current);
return () => observer.disconnect();
}, [loadMoreNotice]);

if (!user)
return (
<Frame
title='내 가게'
content='로그인 후 가게를 관리할 수 있습니다.'
buttonText='로그인하기'
href='/login'
/>
);
Copy link
Contributor

Choose a reason for hiding this comment

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

user가 알바생일 경우에는 해당 페이지가 보여지면 안돼니까 그냥 가장 상단에서 role 를 판별해서 사장님이아니면 메인페이지로 보내버리는게 어떨까요? 이부분 동작은 인화님과 동일하게 가져가야할것 같습니다!
(유저는 하나의 내가게로 인식할텐데 어디페이지에서는 노출하고, 어디페이지에서는 메인으로 보내버리므로 통일화 필요)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

네! 게스트일 경우 로그인화면으로 / 알바일 경우 메인페이지로 경고 모달과 함께 리다이렉트 시켰습니다.


if (!user.shop)
return (
<Frame
title='내 가게'
content='내 가게를 소개하고 공고도 등록해 보세요.'
buttonText='가게 등록하기'
href='/my-shop/register'
/>
);

return (
<>
{user?.shop ? (
<>
<Notice notice={shopData} variant='shop'>
<div className='flex gap-2'>
<Button
as={Link}
href='/my-shop/edit'
variant='secondary'
className='h-[38px] flex-1 tablet:h-12'
>
편집하기
</Button>
<Button
as={Link}
href={`/employer/shops/${user.shop.item.id}/notices/register`}
className='h-[38px] flex-1 tablet:h-12'
>
공고 등록하기
</Button>
</div>
</Notice>
<Notice notice={shopData} variant='shop' className='mt-5 tablet:mt-8'>
<div className='flex gap-2'>
<Button
as={Link}
href='/my-shop/edit'
variant='secondary'
className='h-[38px] flex-1 tablet:h-12'
>
편집하기
</Button>
<Button
as={Link}
href={`/employer/shops/${user.shop.item.id}/notices/register`}
className='h-[38px] flex-1 tablet:h-12'
>
공고 등록하기
</Button>
</div>
</Notice>
<section className='mt-10 max-w-full bg-gray-100 tablet:mt-20'>
{shopNotice.length > 0 ? (
<>
Copy link
Contributor

Choose a reason for hiding this comment

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

프래그먼트 태그는 없어도 될 것 같습니다~!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

user 형태에 따라 모달 띄우는 것 때문에 return 내 구조를 조금 바꾸면서 해당 내용 바뀌었습니다!

<Container as='section' isPage className='pt-0'>
<div className='mt-7 tablet:mt-0'>
Copy link
Contributor

Choose a reason for hiding this comment

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

이부분 태그 없애고 container 에 넣을수도 있을것 같습니다!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

네 시멘틱태그 수정했습니다!

<h2 className='mb-4 text-heading-l font-bold tablet:mb-8'>내가 등록한 공고</h2>
<div className='grid grid-cols-2 gap-x-4 gap-y-8 desktop:grid-cols-3'>
{shopNotice.map(item => {
const mergedNotice = {
...item,
imageUrl: shopData.imageUrl,
name: shopData.name,
address1: shopData.address1,
shopId: shopData.id,
originalHourlyPay: shopData.originalHourlyPay,
};
return <Post key={item.id} notice={mergedNotice} />;
})}
</div>
<div ref={observerRef} className='flex h-12 items-center justify-center'>
{loading && <p className='text-gray-500'>불러오는 중...</p>}
</div>
</div>
</Container>
</>
) : (
<Frame
title='등록한 공고'
content='공고를 등록해 보세요.'
buttonText='공고 등록하기'
href='/employer/shops/${user.shop.item.id}/notices/register'
href={`/employer/shops/${user.shop.item.id}/notices/register`}
/>
</>
) : (
<Frame
title='내 가게'
content='내 가게를 소개하고 공고도 등록해 보세요.'
buttonText='가게 등록하기'
href='/my-shop/register'
/>
)}
)}
</section>
</>
);
};
Expand Down
32 changes: 30 additions & 2 deletions src/types/myShop.ts
Copy link
Contributor

Choose a reason for hiding this comment

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

스크린샷 2025-10-18 오후 2 30 40 해당부분 export 변경되면서 다른파일에서 모듈을 읽지못하고 있어서 버셀 에러가 발생했습니다 수정부탁드립니다!

파일 : ./src/api/employer.ts:2:8
내용 : Type error: Module '"/vercel/path0/src/types/myShop"' has no default export. Did you mean to use 'import { RegisterFormData } from "/vercel/path0/src/types/myShop"' instead?
위치 : import RegisterFormData from '@/types/myShop';

Copy link
Contributor Author

Choose a reason for hiding this comment

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

네 수정했습니다!

Copy link
Contributor

@sohyun0 sohyun0 Oct 18, 2025

Choose a reason for hiding this comment

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

./src/components/features/my-shop/registerAddress.tsx:3:8
Type error: Module '"/vercel/path0/src/types/myShop"'
import RegisterFormData from '@/types/myShop';
부분도 수정부탁드립니다!

스크린샷 2025-10-19 오전 2 32 59

이렇게 검색되어서 나오는 부분은 전부 export 수정해주셔야 합니다!

Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
interface RegisterFormData {
export interface RegisterFormData {
name: string;
category?: string;
address1?: string;
Expand All @@ -9,4 +9,32 @@ interface RegisterFormData {
imageUrl?: string;
}

export default RegisterFormData;
export interface ShopItem {
id: string;
name: string;
category: string;
address1: string;
imageUrl: string;
originalHourlyPay: number;
description: string;
}

export interface ShopResponse {
item: ShopItem;
}

export interface NoticeItem {
id: string;
hourlyPay: number;
startsAt: string;
workhour: number;
closed: boolean;
}

export interface NoticeResponse {
offset: number;
limit: number;
count: number;
hasNext: boolean;
items: { item: NoticeItem }[];
}
Loading