-
Notifications
You must be signed in to change notification settings - Fork 4
✨ Feat: 가게 등록 공고 조회 / 무한스크롤 구현 #86
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
2d24f6a
d8e4b5b
066b7fc
a27a12d
0f0c8ec
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| 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' | ||
| /> | ||
| ); | ||
|
||
|
|
||
| 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 ? ( | ||
| <> | ||
|
||
| <Container as='section' isPage className='pt-0'> | ||
| <div className='mt-7 tablet:mt-0'> | ||
|
||
| <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> | ||
| </> | ||
| ); | ||
| }; | ||
|
|
||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
해당부분 export 변경되면서 다른파일에서 모듈을 읽지못하고 있어서 버셀 에러가 발생했습니다 수정부탁드립니다!
파일 : ./src/api/employer.ts:2:8
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 네 수정했습니다!
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |


There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
재영님께서 수정해서 올리시면 신천님께서 다시계속 수정하셔서 이 부분은 커밋하실때 제외하시는게 좋을것 같습니다!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
네 수정했습니다!