diff --git a/public/icon/PickCha2.svg b/public/icon/PickCha2.svg new file mode 100644 index 00000000..3087ece3 --- /dev/null +++ b/public/icon/PickCha2.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/src/actions/external/getHtmlJustWatch.ts b/src/actions/external/getHtmlJustWatch.ts index 6ea4b116..69d1d7ea 100644 --- a/src/actions/external/getHtmlJustWatch.ts +++ b/src/actions/external/getHtmlJustWatch.ts @@ -7,7 +7,7 @@ import { ProviderInfo } from '@/types/justwatch/providers'; export const getHtmlJustWatch = async (moviename: string) => { const encode = encodeURIComponent(moviename); - const res = await fetch(`https://www.justwatch.com/kr/검색?q=${encode}`, { + const res = await fetch(`https://www.justwatch.com/kr/search?content_type=movie&q=${encode}`, { //.json말고 .text해야해서 그냥 fetch로 cache: 'force-cache', headers: { @@ -20,15 +20,39 @@ export const getHtmlJustWatch = async (moviename: string) => { const $ = cheerio.load(html); const providers: ProviderInfo[] = []; - $('.buybox-row a').each((_, el) => { - const $el = $(el); - const url = $el.attr('href') || ''; - const logo = $el.find('img').attr('src'); - - if (url.startsWith('http') && !providers.some((p) => p.logo === logo)) { - providers.push({ url, logo }); - } - }); - - return providers; + let matched = false; + const allowedProviders = ['netflix', 'watcha', 'disney', 'wavve']; + + const firstTitleRow = $('.title-list-row__row').first(); + + //검색 결과의 첫번째 항목 + const title = firstTitleRow.find('.title-list-row__column-header').text().trim(); + + // 검색어가 영화 제목에 '포함' 되어 있는지? + if (title.toLowerCase().includes(moviename.toLowerCase())) { + matched = true; + + //첫번째 항목 안의 프로바이더들 중 + firstTitleRow.find('.buybox-row a').each((_, el) => { + const $el = $(el); + const url = $el.attr('href') || ''; + const logo = $el.find('img').attr('src'); + + const lowerUrl = url.toLowerCase(); + if ( + allowedProviders.some((p) => lowerUrl.includes(p)) && //[넷플, 디즈니, 웨이브, 왓챠만] + url.startsWith('http') && + !providers.some((p) => p.logo === logo) + ) { + const providerName = allowedProviders.find((p) => lowerUrl.includes(p)); + const alreadyAdded = providers.some((p) => p.url.toLowerCase().includes(providerName!)); + + if (!alreadyAdded) { + providers.push({ url, logo }); + } + } + }); + } + + return matched ? providers : []; }; diff --git a/src/actions/profile/getUserInfo.ts b/src/actions/profile/getUserInfo.ts index e15b0121..8096b168 100644 --- a/src/actions/profile/getUserInfo.ts +++ b/src/actions/profile/getUserInfo.ts @@ -19,13 +19,9 @@ export const getMyInfo = async () => { }; export const getUserInfo = async (userid: number) => { - const session = await auth(); - const accessToken = session?.accessToken; - return await fetcher(`${process.env.API_BASE_URL}/${process.env.TEST_TEAM_ID}/users/${userid}`, { method: 'GET', headers: { - Authorization: `Bearer ${accessToken}`, 'Content-Type': 'application/json', }, cache: 'no-store', diff --git a/src/app/(profile)/(component)/Activities.tsx b/src/app/(profile)/(component)/Activities.tsx index 1a3fb172..f9a0b52e 100644 --- a/src/app/(profile)/(component)/Activities.tsx +++ b/src/app/(profile)/(component)/Activities.tsx @@ -22,12 +22,12 @@ const Activities = async ({ userid }: Props) => {
- {RoundaverageRating} + {RoundaverageRating}
-
+
{data.reviewCount}
diff --git a/src/app/(profile)/(component)/ProfileUpdateForm.tsx b/src/app/(profile)/(component)/ProfileUpdateForm.tsx index 7e00f6b5..7dae075b 100644 --- a/src/app/(profile)/(component)/ProfileUpdateForm.tsx +++ b/src/app/(profile)/(component)/ProfileUpdateForm.tsx @@ -4,7 +4,6 @@ import { useState } from 'react'; import { zodResolver } from '@hookform/resolvers/zod'; import { useSession } from 'next-auth/react'; -import { useErrorBoundary } from 'react-error-boundary'; import { Controller, useForm } from 'react-hook-form'; import { patchProfileInfo } from '@/actions/profile/patchProfileInfo'; @@ -17,7 +16,6 @@ import { useUserInfoStore } from '@/store/userInfoStore'; import { profileSchema, type ProfileFormValues } from '@/types/profile/profileUpdateSchema'; const ProfileUpdateForm = () => { - const { showBoundary } = useErrorBoundary(); const { update } = useSession(); const closeModal = useModalStore((state) => state.closeModal); const [isLoading, setIsLoading] = useState(false); @@ -26,6 +24,8 @@ const ProfileUpdateForm = () => { const description = useUserInfoStore((state) => state.description); const image = useUserInfoStore((state) => state.image); + const [err, setError] = useState(false); + const { register, handleSubmit, @@ -63,8 +63,8 @@ const ProfileUpdateForm = () => { }); closeModal(); - } catch (err) { - showBoundary(err); + } catch { + setError(true); } finally { setIsLoading(false); } @@ -86,6 +86,9 @@ const ProfileUpdateForm = () => { maxLength={10} defaultValue={nickname} {...register('nickname')} + setError={setError} + errorMessage={err ? ' ' : ''} + className={err ? 'animate-shake' : ''} /> { {...register('description')} /> -
diff --git a/src/app/(profile)/(component)/StatisticsCard.tsx b/src/app/(profile)/(component)/StatisticsCard.tsx index 19adaf0d..558fae68 100644 --- a/src/app/(profile)/(component)/StatisticsCard.tsx +++ b/src/app/(profile)/(component)/StatisticsCard.tsx @@ -7,7 +7,7 @@ interface Props { const ActivityCard = ({ title, children }: Props) => { return ( -
+

{title}

diff --git a/src/app/testTrailer/StreamingIcon.tsx b/src/app/testTrailer/StreamingIcon.tsx index 8e7c21ac..510a49bf 100644 --- a/src/app/testTrailer/StreamingIcon.tsx +++ b/src/app/testTrailer/StreamingIcon.tsx @@ -13,8 +13,8 @@ interface Props { export const StreamingIcon = ({ providers }: Props) => { return ( -
-

감상하기

+
+

{`바로 감상하기`}

{providers.map((item) => ( ( if (maxLength) e.target.value = truncated(e.target.value, maxLength); return e.target.value.length; }); - setError && setError(false); + if (setError) setError(false); props.onChange?.(e); }} />