Skip to content

Commit

Permalink
fix: account for incomplete drink entries in Contentful
Browse files Browse the repository at this point in the history
  • Loading branch information
wKovacs64 committed Aug 5, 2023
1 parent f3343b7 commit afdd64c
Show file tree
Hide file tree
Showing 8 changed files with 72 additions and 45 deletions.
10 changes: 5 additions & 5 deletions app/routes/_app.$slug.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import NavLink from '~/navigation/nav-link';
import Glass from '~/drinks/glass';
import DrinkSummary from '~/drinks/drink-summary';
import DrinkDetails from '~/drinks/drink-details';
import type { DrinksResponse, EnhancedDrink } from '~/types';
import type { Drink, DrinksResponse, EnhancedDrink } from '~/types';

export const loader = async ({ params, request }: LoaderArgs) => {
if (!params.slug) throw json('Missing slug', 400);
Expand Down Expand Up @@ -65,17 +65,17 @@ export const loader = async ({ params, request }: LoaderArgs) => {

const {
data: {
drinkCollection: { drinks },
drinkCollection: { drinks: maybeDrinks },
},
} = queryResponseJson;

const drinks = maybeDrinks.filter((drink): drink is Drink => Boolean(drink));

if (drinks.length === 0) {
throw json({ message: 'Drink not found' }, 404);
}

const drinksWithPlaceholderImages: Array<EnhancedDrink> =
await withPlaceholderImages(drinks);

const drinksWithPlaceholderImages = await withPlaceholderImages(drinks);
const [enhancedDrink] = drinksWithPlaceholderImages;

if (enhancedDrink.notes) {
Expand Down
5 changes: 3 additions & 2 deletions app/routes/_app._index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { cache } from '~/utils/cache.server';
import { withPlaceholderImages } from '~/utils/placeholder-images.server';
import Nav from '~/navigation/nav';
import DrinkList from '~/drinks/drink-list';
import type { DrinksResponse, EnhancedDrink } from '~/types';
import type { Drink, DrinksResponse, EnhancedDrink } from '~/types';

export type LoaderData = SerializeFrom<typeof loader>;

Expand Down Expand Up @@ -59,10 +59,11 @@ export const loader = async ({ request }: LoaderArgs) => {

const {
data: {
drinkCollection: { drinks },
drinkCollection: { drinks: maybeDrinks },
},
} = queryResponseJson;

const drinks = maybeDrinks.filter((drink): drink is Drink => Boolean(drink));
const drinksWithPlaceholderImages = await withPlaceholderImages(drinks);
const loaderData = { drinks: drinksWithPlaceholderImages };

Expand Down
3 changes: 2 additions & 1 deletion app/routes/_app.search/route.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -82,10 +82,11 @@ export const loader = async ({ request }: LoaderArgs) => {

const {
data: {
drinkCollection: { drinks },
drinkCollection: { drinks: maybeDrinks },
},
} = queryResponseJson;

const drinks = maybeDrinks.filter((drink): drink is Drink => Boolean(drink));
// sort results in the same order as slugs returned from Algolia
drinks.sort((a, b) => slugs.indexOf(a.slug) - slugs.indexOf(b.slug));

Expand Down
6 changes: 4 additions & 2 deletions app/routes/_app.tags.$tag.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import Nav from '~/navigation/nav';
import NavLink from '~/navigation/nav-link';
import NavDivider from '~/navigation/nav-divider';
import DrinkList from '~/drinks/drink-list';
import type { DrinksResponse, EnhancedDrink } from '~/types';
import type { Drink, DrinksResponse, EnhancedDrink } from '~/types';

export const loader = async ({ params, request }: LoaderArgs) => {
if (!params.tag) throw json('Missing tag', 400);
Expand Down Expand Up @@ -67,10 +67,12 @@ export const loader = async ({ params, request }: LoaderArgs) => {

const {
data: {
drinkCollection: { drinks },
drinkCollection: { drinks: maybeDrinks },
},
} = queryResponseJson;

const drinks = maybeDrinks.filter((drink): drink is Drink => Boolean(drink));

if (drinks.length === 0) {
throw json({ message: 'No drinks found' }, 404);
}
Expand Down
5 changes: 3 additions & 2 deletions app/routes/_app.tags._index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { getEnvVars } from '~/utils/env.server';
import { mergeMeta } from '~/utils/meta';
import { fetchGraphQL } from '~/utils/graphql.server';
import { cache } from '~/utils/cache.server';
import type { DrinkTagsResponse } from '~/types';
import type { Drink, DrinkTagsResponse } from '~/types';

export type LoaderData = SerializeFrom<typeof loader>;

Expand Down Expand Up @@ -52,10 +52,11 @@ export const loader = async ({ request }: LoaderArgs) => {

const {
data: {
drinkCollection: { drinks },
drinkCollection: { drinks: maybeDrinks },
},
} = queryResponseJson;

const drinks = maybeDrinks.filter((drink): drink is Drink => Boolean(drink));
const uniqueTags = drinks.reduce<Set<string>>((acc, drink) => {
drink.tags?.forEach((tag) => acc.add(tag));
return acc;
Expand Down
22 changes: 15 additions & 7 deletions app/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ export interface DrinksResponse {
}>;
data: {
drinkCollection: {
drinks: Array<Drink>;
drinks: Array<Drink | null>;
} | null;
};
}
Expand All @@ -28,20 +28,28 @@ export type DrinkTagsResponse = DrinksResponse & {
};
};

// Most of the fields will be null if you start to create a new Drink in
// Contentful without finishing it.
export interface Drink {
title: string;
title: string | null;
slug: string;
image: {
url: string;
};
ingredients: Array<string>;
calories: number;
} | null;
ingredients: Array<string> | null;
calories: number | null;
notes?: string;
tags?: Array<string>;
}

export interface EnhancedDrink extends Drink {
image: Drink['image'] & {
export interface EnhancedDrink {
title: NonNullable<Drink['title']>;
slug: Drink['slug'];
image: NonNullable<Drink['image']> & {
blurDataUrl: string;
};
ingredients: NonNullable<Drink['ingredients']>;
calories: NonNullable<Drink['calories']>;
notes?: Drink['notes'];
tags?: Drink['tags'];
}
64 changes: 39 additions & 25 deletions app/utils/placeholder-images.server.ts
Original file line number Diff line number Diff line change
@@ -1,29 +1,43 @@
import { makeImageUrl } from '~/core/image';
import type { Drink } from '~/types';
import type { Drink, EnhancedDrink } from '~/types';

export async function withPlaceholderImages(drinks: Array<Drink>) {
return Promise.all(
drinks.map(async (drink) => {
const blurredImageUrl = makeImageUrl({
baseImageUrl: drink.image.url,
width: 10,
quality: 90,
format: 'webp',
});
const blurredImageResponse = await fetch(blurredImageUrl);
const blurredImageArrayBuffer = await blurredImageResponse.arrayBuffer();
const blurredImageBase64String = btoa(
String.fromCharCode(...new Uint8Array(blurredImageArrayBuffer)),
);
const blurDataUrl = `data:image/webp;base64,${blurredImageBase64String}`;
export async function withPlaceholderImages(
drinks: Array<Drink>,
): Promise<Array<EnhancedDrink>> {
return (
await Promise.all(
drinks.map(async (drink) => {
if (
drink.title === null ||
drink.ingredients === null ||
drink.calories === null ||
!drink.image?.url
) {
return null;
}

return {
...drink,
image: {
...drink.image,
blurDataUrl,
},
};
}),
);
const blurredImageUrl = makeImageUrl({
baseImageUrl: drink.image.url,
width: 10,
quality: 90,
format: 'webp',
});
const blurredImageResponse = await fetch(blurredImageUrl);
const blurredImageArrayBuffer =
await blurredImageResponse.arrayBuffer();
const blurredImageBase64String = btoa(
String.fromCharCode(...new Uint8Array(blurredImageArrayBuffer)),
);
const blurDataUrl = `data:image/webp;base64,${blurredImageBase64String}`;

return {
...drink,
image: {
...drink.image,
blurDataUrl,
},
};
}),
)
).filter((drink): drink is EnhancedDrink => drink !== null);
}
2 changes: 1 addition & 1 deletion app/utils/prime-content-cache.server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ export async function primeContentCache() {
allDrinksDataFnArgs,
);
const allDrinksData: AllDrinksLoaderData = await allDrinksResponse.json();
const { drinks } = allDrinksData;
const drinks = allDrinksData.drinks.filter(Boolean);

// 3. Load and cache each individual drink
const allSlugs = drinks.map(({ slug }) => slug);
Expand Down

0 comments on commit afdd64c

Please sign in to comment.