Skip to content
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

More details in metadata (show) card #1253

Merged
merged 8 commits into from
Feb 13, 2025
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
57 changes: 40 additions & 17 deletions apps/frontend/app/components/media.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
import { useInViewport } from "@mantine/hooks";
import {
EntityLot,
MediaLot,
PersonDetailsDocument,
SeenState,
UserMetadataGroupDetailsDocument,
Expand All @@ -30,7 +31,7 @@ import {
IconStarFilled,
} from "@tabler/icons-react";
import { useQuery } from "@tanstack/react-query";
import type { ReactNode } from "react";
import { useMemo, type ReactNode } from "react";
import { Form, Link } from "react-router";
import { $path } from "safe-routes";
import { match } from "ts-pattern";
Expand Down Expand Up @@ -140,7 +141,7 @@ export const MetadataDisplayItem = (props: {
noLeftLabel?: boolean;
}) => {
const [_r, setEntityToReview] = useReviewEntity();
const [_, setMetadataToUpdate, isMetadataToUpdateLoading] =
const [_m, setMetadataToUpdate, isMetadataToUpdateLoading] =
useMetadataProgressUpdate();
const userPreferences = useUserPreferences();
const { ref, inViewport } = useInViewport();
Expand All @@ -150,13 +151,46 @@ export const MetadataDisplayItem = (props: {
props.metadataId,
inViewport,
);

const averageRating = userMetadataDetails?.averageRating;
const completedHistory = (userMetadataDetails?.history || []).filter(
(h) => h.state === SeenState.Completed,
);
const currentProgress = userMetadataDetails?.history.find(
(h) => h.state === SeenState.InProgress,
)?.progress;
const reasons = userMetadataDetails?.mediaReason?.filter((r) =>
[
UserToMediaReason.Finished,
UserToMediaReason.Watchlist,
UserToMediaReason.Owned,
].includes(r),
);
const hasInteracted = userMetadataDetails?.hasInteracted;

const leftLabel = useMemo(() => {
if (props.noLeftLabel || !metadataDetails || !userMetadataDetails)
return null;

const inProgress = userMetadataDetails.inProgress;
if (inProgress) {
if (inProgress.podcastExtraInformation)
return `EP-${inProgress.podcastExtraInformation.episode}`;
if (inProgress.showExtraInformation)
return `S${inProgress.showExtraInformation.season}-E${inProgress.showExtraInformation.episode}`;
}

const nextEntry = userMetadataDetails.nextEntry;
if (nextEntry) {
if (metadataDetails.lot === MediaLot.Show)
return `S${nextEntry.season}-E${nextEntry.episode}`;
if (metadataDetails.lot === MediaLot.Podcast)
return `EP-${nextEntry.episode}`;
}

return metadataDetails.publishYear;
}, [metadataDetails, userMetadataDetails]);

const surroundReason = (
idx: number,
data: readonly [UserToMediaReason, ReactNode],
Expand All @@ -167,14 +201,6 @@ export const MetadataDisplayItem = (props: {
</ThemeIcon>
</Tooltip>
);
const reasons = userMetadataDetails?.mediaReason?.filter((r) =>
[
UserToMediaReason.Finished,
UserToMediaReason.Watchlist,
UserToMediaReason.Owned,
].includes(r),
);
const hasInteracted = userMetadataDetails?.hasInteracted;

return (
<BaseMediaDisplayItem
Expand All @@ -184,15 +210,12 @@ export const MetadataDisplayItem = (props: {
isLoading={isMetadataDetailsLoading}
name={props.name ?? metadataDetails?.title}
imageUrl={metadataDetails?.assets.images.at(0)}
highlightImage={userMetadataDetails?.recentlyConsumed}
highlightImage={userMetadataDetails?.isRecentlyConsumed}
onImageClickBehavior={$path("/media/item/:id", { id: props.metadataId })}
labels={
metadataDetails
? {
left:
props.noLeftLabel !== true
? metadataDetails.publishYear
: undefined,
left: leftLabel,
right:
props.rightLabel ||
(props.rightLabelLot
Expand Down Expand Up @@ -319,7 +342,7 @@ export const MetadataGroupDisplayItem = (props: {
isLoading={isMetadataDetailsLoading}
name={metadataDetails?.details.title}
imageOverlay={{ topRight: props.topRight }}
highlightImage={userMetadataGroupDetails?.recentlyConsumed}
highlightImage={userMetadataGroupDetails?.isRecentlyConsumed}
onImageClickBehavior={$path("/media/groups/item/:id", {
id: props.metadataGroupId,
})}
Expand Down Expand Up @@ -372,7 +395,7 @@ export const PersonDisplayItem = (props: {
name={personDetails?.details.name}
isLoading={isPersonDetailsLoading}
imageOverlay={{ topRight: props.topRight }}
highlightImage={userPersonDetails?.recentlyConsumed}
highlightImage={userPersonDetails?.isRecentlyConsumed}
imageUrl={personDetails?.details.displayImages.at(0)}
onImageClickBehavior={$path("/media/people/item/:id", {
id: props.personId,
Expand Down
1 change: 1 addition & 0 deletions apps/frontend/app/routes/_dashboard.calendar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ const CalendarEvent = (props: {
<ApplicationGrid>
{props.data.events.map((calEvent) => (
<MetadataDisplayItem
noLeftLabel
key={calEvent.calendarEventId}
altName={calEvent.metadataText}
metadataId={calEvent.metadataId}
Expand Down
2 changes: 1 addition & 1 deletion apps/frontend/app/routes/api.auth.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export const loader = async ({ request }: Route.LoaderArgs) => {
GetOidcTokenDocument,
input,
);
console.log("OIDC token response:", getOidcToken);
console.log("OIDC token response:", { getOidcToken });
const oidcInput = {
email: getOidcToken.email,
issuerId: getOidcToken.subject,
Expand Down
4 changes: 2 additions & 2 deletions apps/website/app/entry.server.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { writeFileSync } from "node:fs";
import { PassThrough } from "node:stream";
import { createReadableStreamFromReadable } from "@react-router/node";
import { migrate } from "drizzle-orm/postgres-js/migrator";
Expand All @@ -8,8 +9,7 @@ import {
type EntryContext,
ServerRouter,
} from "react-router";
import { db, serverVariables, TEMP_DIRECTORY } from "./lib/config.server";
import { writeFileSync } from "node:fs";
import { TEMP_DIRECTORY, db, serverVariables } from "./lib/config.server";

migrate(db, { migrationsFolder: "app/drizzle/migrations" }).catch((error) => {
console.error("Database migrations failed", error);
Expand Down
4 changes: 2 additions & 2 deletions apps/website/app/lib/config.server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -117,15 +117,15 @@ export const sendEmail = async (
});
const html = await render(element, { pretty: true });
const text = await render(element, { plainText: true });
console.log(`Sending email to ${recipient} with subject ${subject}`);
console.log("Sending email:", { recipient, subject });
const resp = await client.sendMail({
text,
html,
subject,
to: recipient,
from: serverVariables.SERVER_SMTP_MAILBOX,
});
console.log(`Sent email to ${recipient} with subject ${subject}`);
console.log("Sent email:", { recipient, subject });
return resp.messageId;
};

Expand Down
3 changes: 2 additions & 1 deletion apps/website/app/routes/_index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ export const action = async ({ request }: Route.ActionArgs) => {
const { email } = processSubmission(formData, emailSchema);
const otpCode = generateOtp(6);
otpCodesCache.set(email, otpCode);
console.log(`OTP code for ${email} is ${otpCode}`);
console.log("OTP code generated:", { email, otpCode });
await sendEmail(
email,
LoginCodeEmail.subject,
Expand All @@ -111,6 +111,7 @@ export const action = async ({ request }: Route.ActionArgs) => {
const customerId = dbCustomer.at(0)?.id;
if (!customerId)
throw new Error("There was an error registering the user.");
console.log("Customer login successful:", { customerId });
return redirect($path("/me"), {
headers: {
"set-cookie": await websiteAuthCookie.serialize(customerId),
Expand Down
1 change: 1 addition & 0 deletions apps/website/app/routes/callback.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ export const loader = async ({ request }: Route.LoaderArgs) => {
})
.otherwise((value) => value.id);
if (!customerId) throw new Error("There was an error registering the user.");
console.log("Customer login successful:", { customerId });
return redirect($path("/me"), {
headers: { "set-cookie": await websiteAuthCookie.serialize(customerId) },
});
Expand Down
16 changes: 8 additions & 8 deletions apps/website/app/routes/paddle-webhook.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,17 +47,15 @@ export const action = async ({ request }: Route.ActionArgs) => {

const { eventType, data } = eventData;

console.log(`Received event: ${eventType}`);
console.log("Received event:", { eventType });

if (eventType === EventName.TransactionCompleted) {
const paddleCustomerId = data.customerId;
if (!paddleCustomerId)
return Response.json({
error: "No customer ID found in transaction completed event",
});
console.log(
`Received transaction completed event for customer id: ${paddleCustomerId}`,
);
console.log("Received transaction completed event", { paddleCustomerId });
let customer = await db.query.customers.findFirst({
where: eq(customers.paddleCustomerId, paddleCustomerId),
});
Expand All @@ -80,9 +78,11 @@ export const action = async ({ request }: Route.ActionArgs) => {
if (!priceId) return Response.json({ error: "Price ID not found" });

const { planType, productType } = getProductAndPlanTypeByPriceId(priceId);
console.log(
`Customer ${paddleCustomerId} purchased ${productType} with plan type ${planType}`,
);
console.log("Customer purchased plan:", {
paddleCustomerId,
productType,
planType,
});

const { email, oidcIssuerId } = customer;
const renewOn = getRenewOnFromPlanType(planType);
Expand Down Expand Up @@ -148,7 +148,7 @@ export const action = async ({ request }: Route.ActionArgs) => {
} else {
const renewal = getRenewOnFromPlanType(customer.planType);
const renewOn = renewal ? formatDateToNaiveDate(renewal) : undefined;
console.log(`Updating customer with renewOn: ${renewOn}`);
console.log("Updating customer with renewOn", { renewOn });
await db
.update(customers)
.set({ renewOn, hasCancelled: null })
Expand Down
12 changes: 6 additions & 6 deletions crates/models/dependent/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -345,32 +345,32 @@ pub struct CoreDetails {

#[derive(SimpleObject)]
pub struct UserPersonDetails {
pub recently_consumed: bool,
pub reviews: Vec<ReviewItem>,
pub is_recently_consumed: bool,
pub collections: Vec<collection::Model>,
}

#[derive(SimpleObject)]
pub struct UserMetadataGroupDetails {
pub recently_consumed: bool,
pub reviews: Vec<ReviewItem>,
pub is_recently_consumed: bool,
pub collections: Vec<collection::Model>,
}

#[derive(SimpleObject)]
pub struct UserMetadataDetails {
/// Whether this media has been interacted with
pub has_interacted: bool,
/// Whether this media has been recently interacted with
pub recently_consumed: bool,
/// The public reviews of this media.
pub reviews: Vec<ReviewItem>,
/// The number of users who have seen this media.
pub seen_by_all_count: usize,
/// The number of times this user has seen this media.
pub seen_by_user_count: usize,
/// The seen history of this media.
pub history: Vec<seen::Model>,
/// The number of times this user has seen this media.
pub seen_by_user_count: usize,
/// Whether this media has been recently interacted with
pub is_recently_consumed: bool,
/// The average rating of this media in this service.
pub average_rating: Option<Decimal>,
/// The seen item if it is in progress.
Expand Down
12 changes: 6 additions & 6 deletions crates/services/miscellaneous/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -622,7 +622,7 @@ ORDER BY RANDOM() LIMIT 10;
} else {
None
};
let recently_consumed =
let is_recently_consumed =
get_entity_recently_consumed(&user_id, &metadata_id, EntityLot::Metadata, &self.0)
.await?;
Ok(UserMetadataDetails {
Expand All @@ -634,8 +634,8 @@ ORDER BY RANDOM() LIMIT 10;
show_progress,
average_rating,
podcast_progress,
recently_consumed,
seen_by_user_count,
is_recently_consumed,
seen_by_all_count: seen_by,
has_interacted: user_to_meta.is_some(),
media_reason: user_to_meta.and_then(|n| n.media_reason),
Expand All @@ -650,12 +650,12 @@ ORDER BY RANDOM() LIMIT 10;
let reviews = item_reviews(&user_id, &person_id, EntityLot::Person, true, &self.0).await?;
let collections =
entity_in_collections(&self.0.db, &user_id, &person_id, EntityLot::Person).await?;
let recently_consumed =
let is_recently_consumed =
get_entity_recently_consumed(&user_id, &person_id, EntityLot::Person, &self.0).await?;
Ok(UserPersonDetails {
reviews,
collections,
recently_consumed,
is_recently_consumed,
})
}

Expand All @@ -679,7 +679,7 @@ ORDER BY RANDOM() LIMIT 10;
&self.0,
)
.await?;
let recently_consumed = get_entity_recently_consumed(
let is_recently_consumed = get_entity_recently_consumed(
&user_id,
&metadata_group_id,
EntityLot::MetadataGroup,
Expand All @@ -689,7 +689,7 @@ ORDER BY RANDOM() LIMIT 10;
Ok(UserMetadataGroupDetails {
reviews,
collections,
recently_consumed,
is_recently_consumed,
})
}

Expand Down
Loading
Loading