Skip to content

Commit 45cb669

Browse files
committed
feat: implement the new review format (html) for mobile support
1 parent 7edf603 commit 45cb669

File tree

17 files changed

+334
-306
lines changed

17 files changed

+334
-306
lines changed

package.json

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -47,27 +47,29 @@
4747
"@radix-ui/react-toggle": "^1.1.1",
4848
"@radix-ui/react-toggle-group": "^1.1.10",
4949
"@radix-ui/react-tooltip": "^1.2.7",
50-
"@recomendapp/types": "^1.0.27",
50+
"@recomendapp/types": "^1.0.29",
5151
"@revenuecat/purchases-js": "^1.16.1",
5252
"@supabase/ssr": "^0.7.0",
5353
"@supabase/supabase-js": "^2.49.8",
5454
"@tanstack/react-query": "^5.79.0",
5555
"@tanstack/react-query-devtools": "^5.79.0",
5656
"@tanstack/react-table": "^8.21.3",
57-
"@tiptap/extension-bold": "^2.12.0",
58-
"@tiptap/extension-bubble-menu": "^2.1.8",
59-
"@tiptap/extension-character-count": "^2.12.0",
60-
"@tiptap/extension-document": "^2.12.0",
61-
"@tiptap/extension-history": "^2.12.0",
62-
"@tiptap/extension-italic": "^2.12.0",
63-
"@tiptap/extension-link": "^2.12.0",
64-
"@tiptap/extension-paragraph": "^2.12.0",
65-
"@tiptap/extension-placeholder": "^2.12.0",
66-
"@tiptap/extension-strike": "^2.12.0",
67-
"@tiptap/extension-text": "^2.12.0",
68-
"@tiptap/extension-underline": "^2.12.0",
69-
"@tiptap/pm": "^2.12.0",
70-
"@tiptap/react": "^2.12.0",
57+
"@tiptap/core": "^3.13.0",
58+
"@tiptap/extension-bold": "^3.13.0",
59+
"@tiptap/extension-bubble-menu": "^3.13.0",
60+
"@tiptap/extension-character-count": "^3.13.0",
61+
"@tiptap/extension-document": "^3.13.0",
62+
"@tiptap/extension-history": "^3.13.0",
63+
"@tiptap/extension-italic": "^3.13.0",
64+
"@tiptap/extension-link": "^3.13.0",
65+
"@tiptap/extension-paragraph": "^3.13.0",
66+
"@tiptap/extension-placeholder": "^3.13.0",
67+
"@tiptap/extension-strike": "^3.13.0",
68+
"@tiptap/extension-text": "^3.13.0",
69+
"@tiptap/extension-underline": "^3.13.0",
70+
"@tiptap/html": "^3.13.0",
71+
"@tiptap/pm": "^3.13.0",
72+
"@tiptap/react": "^3.13.0",
7173
"@types/node": "^22.15.27",
7274
"@types/react": "19.2.5",
7375
"@types/react-dom": "19.2.3",

pnpm-lock.yaml

Lines changed: 191 additions & 142 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/app/[lang]/(app)/film/[film_id]/(default)/_components/MovieDetails.tsx

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { JustWatchWidget } from "@/components/JustWatch/JustWatchWidgetScript";
44
import { Card } from "@/components/ui/card";
55
import { ScrollArea, ScrollBar } from "@/components/ui/scroll-area";
66
import { ImageWithFallback } from "@/components/utils/ImageWithFallback";
7-
import { MediaMovie, MediaMoviePerson, MediaPerson } from "@recomendapp/types";
7+
import { MediaMovie, MediaPerson } from "@recomendapp/types";
88
import { upperFirst } from "lodash";
99
import { useTranslations } from "next-intl";
1010
import { Link } from "@/lib/i18n/navigation";
@@ -34,43 +34,42 @@ export default function MovieDetails({
3434
/>
3535
</div>
3636
{/* CASTING */}
37-
<MovieCast cast={movie.cast} />
37+
<MovieCast movie={movie} />
3838
</div>
3939
);
4040
}
4141

4242
const MovieCast = ({
43-
cast,
43+
movie,
4444
} : {
45-
cast?: MediaMoviePerson[]
45+
movie: MediaMovie
4646
}) => {
4747
const common = useTranslations('common');
4848
return (
4949
<div>
5050
<h2 className="text-lg font-medium">{upperFirst(common('messages.cast'))}</h2>
51-
{(cast && cast?.length > 0) ? (
51+
{(movie.cast && movie.cast?.length > 0) ? (
5252
<ScrollArea>
5353
<div className="flex space-x-4 pb-4">
54-
{cast?.map(({ person, role }, i) => (
55-
<CastPoster key={i} person={person} character={role?.character} />
54+
{movie.cast?.map(({ person }, i) => (
55+
<CastPoster key={i} person={person} />
5656
))}
5757
</div>
5858
<ScrollBar orientation="horizontal" />
5959
</ScrollArea>
6060
) : (
6161
<div className="text-justify text-muted-foreground">{upperFirst(common('messages.no_cast'))}</div>
6262
)}
63-
{/* <CrewModal crew={movie.credits.crew} /> */}
6463
</div>
6564
)
6665
}
6766

6867
function CastPoster({
6968
person,
70-
character,
69+
characters,
7170
} : {
7271
person?: MediaPerson,
73-
character?: string | null,
72+
characters?: string[] | null,
7473
}) {
7574
if (!person) return null;
7675
return (
@@ -92,7 +91,7 @@ function CastPoster({
9291
</div>
9392
<div className="text-center">
9493
<p className="line-clamp-2 break-words">{person.name}</p>
95-
{character ? <p className="line-clamp-2 text-accent-yellow italic text-sm">{character}</p> : null}
94+
{characters ? <p className="line-clamp-2 text-accent-yellow italic text-sm">{characters.join(', ')}</p> : null}
9695
</div>
9796
</Card>
9897
</Link>

src/app/[lang]/(app)/film/[film_id]/(review)/review/[review_id]/_components/MovieReview.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
'use client';
2-
import { JSONContent, MediaPerson, UserReviewMovie } from "@recomendapp/types";
2+
import { MediaPerson, UserReviewMovie } from "@recomendapp/types";
33
import { Button } from "@/components/ui/button";
44
import { cn } from "@/lib/utils";
55
import { Link } from "@/lib/i18n/navigation";
@@ -30,7 +30,7 @@ export const MovieReview = ({
3030
movieId: review?.activity?.movie_id!,
3131
});
3232

33-
const handleSubmit = async (data: { title?: string; body: JSONContent }) => {
33+
const handleSubmit = async (data: { title?: string; body: string }) => {
3434
await upsertReview.mutateAsync({
3535
activityId: review?.id,
3636
...data

src/app/[lang]/(app)/film/[film_id]/(review)/review/[review_id]/page.tsx

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,12 @@ import { truncate, upperFirst } from 'lodash';
55
import { Metadata } from 'next';
66
import { MovieReview } from './_components/MovieReview';
77
import { Review, WithContext } from 'schema-dts';
8-
import { getRawReviewText } from '@/lib/utils';
98
import { siteConfig } from '@/config/site';
109
import { seoLocales } from '@/lib/i18n/routing';
1110
import { SupportedLocale } from '@/translations/locales';
11+
import { generateText } from '@tiptap/core';
12+
import { generateJSON } from '@tiptap/html';
13+
import { EDITOR_EXTENSIONS } from '@/components/tiptap/TiptapExtensions';
1214

1315
export async function generateMetadata(
1416
props: {
@@ -22,14 +24,16 @@ export async function generateMetadata(
2224
const t = await getTranslations({ locale: params.lang as SupportedLocale });
2325
const review = await getReviewMovie(params.review_id, params.lang);
2426
if (!review) return { title: upperFirst(t('common.messages.review_not_found')) };
27+
const tiptapJson = generateJSON(review.body, EDITOR_EXTENSIONS);
28+
const rawText = generateText(tiptapJson, EDITOR_EXTENSIONS);
2529
return {
2630
title: t('pages.review.metadata.title', { title: review.activity?.movie?.title!, username: review.activity?.user?.username! }),
27-
description: truncate(getRawReviewText({ data: review.body }), { length: siteConfig.seo.description.limit }),
31+
description: truncate(rawText, { length: siteConfig.seo.description.limit }),
2832
alternates: seoLocales(params.lang, `/review/${review.id}`),
2933
openGraph: {
3034
siteName: siteConfig.name,
3135
title: t('pages.review.metadata.title', { title: review.activity?.movie?.title!, username: review.activity?.user?.username! }),
32-
description: truncate(getRawReviewText({ data: review.body }), { length: siteConfig.seo.description.limit }),
36+
description: truncate(rawText, { length: siteConfig.seo.description.limit }),
3337
url: `${siteConfig.url}/${params.lang}/review/${params.review_id}`,
3438
images: review.activity?.movie?.poster_url ? [
3539
{ url: review.activity?.movie?.poster_url },
@@ -51,13 +55,15 @@ export default async function ReviewPage(
5155
const params = await props.params;
5256
const review = await getReviewMovie(params.review_id, params.lang);
5357
if (!review) notFound();
58+
const tiptapJson = generateJSON(review.body, EDITOR_EXTENSIONS);
59+
const rawText = generateText(tiptapJson, EDITOR_EXTENSIONS);
5460
const t = await getTranslations({ locale: params.lang as SupportedLocale });
5561
const { movie } = review.activity || {};
5662
const jsonLd: WithContext<Review> = {
5763
'@context': 'https://schema.org',
5864
'@type': 'Review',
5965
name: t('pages.review.metadata.title', { title: movie?.title!, username: review.activity?.user?.username! }),
60-
description: truncate(getRawReviewText({ data: review.body }), { length: siteConfig.seo.description.limit }),
66+
description: truncate(rawText, { length: siteConfig.seo.description.limit }),
6167
datePublished: review.created_at,
6268
dateModified: review.updated_at,
6369
itemReviewed: movie ? {

src/app/[lang]/(app)/film/[film_id]/(review)/review/create/_components/MovieCreateReview.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
'use client';
22

33
import { Button } from '@/components/ui/button';
4-
import { JSONContent, MediaMovie, MediaPerson } from '@recomendapp/types';
4+
import { MediaMovie, MediaPerson } from '@recomendapp/types';
55
import { useAuth } from '@/context/auth-context';
66
import { Link, useRouter } from "@/lib/i18n/navigation";
77
import { cn } from '@/lib/utils';
@@ -36,7 +36,7 @@ export const MovieCreateReview = ({
3636
movieId: movie.id,
3737
});
3838

39-
const handleSubmit = async (data: { title?: string; body: JSONContent }) => {
39+
const handleSubmit = async (data: { title?: string; body: string }) => {
4040
if (!activity) return;
4141
await upsertReview.mutateAsync({
4242
activityId: activity?.id,

src/app/[lang]/(app)/tv-series/[tv_series_id]/(default)/_components/TvSeriesDetails.tsx

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -125,25 +125,25 @@ export default function TvSerieDetails({
125125
)}
126126
</div>
127127
{/* CASTING */}
128-
<SerieCast cast={serie.cast} />
128+
<SerieCast tvSeries={serie} />
129129
</div>
130130
);
131131
}
132132

133133
const SerieCast = ({
134-
cast,
134+
tvSeries,
135135
} : {
136-
cast?: MediaTvSeriesPerson[]
136+
tvSeries: MediaTvSeries
137137
}) => {
138138
const common = useTranslations('common');
139139
return (
140140
<div>
141141
<h2 className="text-lg font-medium">{upperFirst(common('messages.cast'))}</h2>
142-
{(cast && cast?.length > 0) ? (
142+
{(tvSeries.cast && tvSeries.cast?.length > 0) ? (
143143
<ScrollArea>
144144
<div className="flex space-x-4 pb-4">
145-
{cast?.map(({ person, character }, i) => (
146-
<CastPoster key={i} person={person} character={character} />
145+
{tvSeries.cast?.map(({ person }, i) => (
146+
<CastPoster key={i} person={person} />
147147
))}
148148
</div>
149149
<ScrollBar orientation="horizontal" />
@@ -157,10 +157,10 @@ const SerieCast = ({
157157

158158
function CastPoster({
159159
person,
160-
character,
160+
characters,
161161
} : {
162162
person?: MediaPerson,
163-
character?: string | null,
163+
characters?: string[] | null,
164164
}) {
165165
if (!person) return null;
166166
return (
@@ -182,7 +182,7 @@ function CastPoster({
182182
</div>
183183
<div className="text-center">
184184
<p className="line-clamp-2 break-words">{person.name}</p>
185-
{character ? <p className="line-clamp-2 text-accent-yellow italic text-sm">{character}</p> : null}
185+
{characters ? <p className="line-clamp-2 text-accent-yellow italic text-sm">{characters.join(', ')}</p> : null}
186186
</div>
187187
</Card>
188188
</Link>

src/app/[lang]/(app)/tv-series/[tv_series_id]/(review)/review/[review_id]/_components/TvSeriesReview.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
'use client';
2-
import { JSONContent, MediaPerson, UserReviewMovie, UserReviewTvSeries } from "@recomendapp/types";
2+
import { MediaPerson, UserReviewTvSeries } from "@recomendapp/types";
33
import { Button } from "@/components/ui/button";
44
import { cn } from "@/lib/utils";
55
import { Link } from "@/lib/i18n/navigation";
@@ -31,7 +31,7 @@ export const TvSeriesReview = ({
3131
tvSeriesId: review?.activity?.tv_series_id!,
3232
});
3333

34-
const handleSubmit = async (data: { title?: string; body: JSONContent }) => {
34+
const handleSubmit = async (data: { title?: string; body: string }) => {
3535
await upsertReview.mutateAsync({
3636
activityId: review?.id,
3737
...data

src/app/[lang]/(app)/tv-series/[tv_series_id]/(review)/review/[review_id]/page.tsx

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,12 @@ import { Metadata } from 'next';
55
import { getReviewTvSeries } from '@/features/server/reviews';
66
import { TvSeriesReview } from './_components/TvSeriesReview';
77
import { Review, WithContext } from 'schema-dts';
8-
import { getRawReviewText } from '@/lib/utils';
98
import { siteConfig } from '@/config/site';
109
import { seoLocales } from '@/lib/i18n/routing';
1110
import { SupportedLocale } from '@/translations/locales';
11+
import { generateJSON } from '@tiptap/html';
12+
import { EDITOR_EXTENSIONS } from '@/components/tiptap/TiptapExtensions';
13+
import { generateText } from '@tiptap/core';
1214

1315
export async function generateMetadata(
1416
props: {
@@ -22,14 +24,16 @@ export async function generateMetadata(
2224
const t = await getTranslations({ locale: params.lang as SupportedLocale });
2325
const review = await getReviewTvSeries(params.review_id, params.lang);
2426
if (!review) return { title: upperFirst(t('common.messages.review_not_found')) };
27+
const tiptapJson = generateJSON(review.body, EDITOR_EXTENSIONS);
28+
const rawText = generateText(tiptapJson, EDITOR_EXTENSIONS);
2529
return {
2630
title: t('pages.review.metadata.title', { title: review.activity?.tv_series?.name!, username: review.activity?.user?.username! }),
27-
description: truncate(getRawReviewText({ data: review.body }), { length: siteConfig.seo.description.limit }),
31+
description: truncate(rawText, { length: siteConfig.seo.description.limit }),
2832
alternates: seoLocales(params.lang, `/review/${review.id}`),
2933
openGraph: {
3034
siteName: siteConfig.name,
3135
title: t('pages.review.metadata.title', { title: review.activity?.tv_series?.name!, username: review.activity?.user?.username! }),
32-
description: truncate(getRawReviewText({ data: review.body }), { length: siteConfig.seo.description.limit }),
36+
description: truncate(rawText, { length: siteConfig.seo.description.limit }),
3337
url: `${siteConfig.url}/${params.lang}/review/${params.review_id}`,
3438
images: review.activity?.tv_series?.poster_url ? [
3539
{ url: review.activity?.tv_series.poster_url },
@@ -51,13 +55,15 @@ export default async function ReviewPage(
5155
const params = await props.params;
5256
const review = await getReviewTvSeries(params.review_id, params.lang);
5357
if (!review) notFound();
58+
const tiptapJson = generateJSON(review.body, EDITOR_EXTENSIONS);
59+
const rawText = generateText(tiptapJson, EDITOR_EXTENSIONS);
5460
const t = await getTranslations({ locale: params.lang as SupportedLocale });
5561
const { tv_series } = review.activity || {};
5662
const jsonLd: WithContext<Review> = {
5763
'@context': 'https://schema.org',
5864
'@type': 'Review',
5965
name: t('pages.review.metadata.title', { title: tv_series?.name!, username: review.activity?.user?.username! }),
60-
description: truncate(getRawReviewText({ data: review.body }), { length: siteConfig.seo.description.limit }),
66+
description: truncate(rawText, { length: siteConfig.seo.description.limit }),
6167
datePublished: review.created_at,
6268
dateModified: review.updated_at,
6369
itemReviewed: tv_series ? {

src/app/[lang]/(app)/tv-series/[tv_series_id]/(review)/review/create/_components/TvSeriesCreateReview.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
'use client';
22

33
import { Button } from '@/components/ui/button';
4-
import { JSONContent, MediaPerson, MediaTvSeries } from '@recomendapp/types';
4+
import { MediaPerson, MediaTvSeries } from '@recomendapp/types';
55
import { useAuth } from '@/context/auth-context';
66
import { Link, useRouter } from "@/lib/i18n/navigation";
77
import { cn } from '@/lib/utils';
@@ -36,7 +36,7 @@ export const TvSeriesCreateReview = ({
3636
tvSeriesId: tvSeries.id,
3737
});
3838

39-
const handleSubmit = async (data: { title?: string; body: JSONContent }) => {
39+
const handleSubmit = async (data: { title?: string; body: string }) => {
4040
if (!activity) return;
4141
await upsertReview.mutateAsync({
4242
activityId: activity.id,

0 commit comments

Comments
 (0)