Skip to content

Commit

Permalink
chore: extract residents card to a component
Browse files Browse the repository at this point in the history
  • Loading branch information
alevidals committed Apr 5, 2024
1 parent 78fe5e2 commit d6a290b
Show file tree
Hide file tree
Showing 4 changed files with 105 additions and 91 deletions.
6 changes: 3 additions & 3 deletions src/__tests__/e2e/planets.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,9 @@ test("should create a new planet and show it on the list", async ({ page }) => {
await page
.getByText("NameDiameterClimatesTerrainsResidentsSave changes")
.click();
await page.locator('input[name="climates\\.0\\.climate"]').fill("arid");
await page.locator('input[name="terrains\\.0\\.terrain"]').click();
await page.locator('input[name="terrains\\.0\\.terrain"]').fill("desert");
await page.locator('input[name="climates.0.climate"]').fill("arid");
await page.locator('input[name="terrains.0.terrain"]').click();
await page.locator('input[name="terrains.0.terrain"]').fill("desert");
await page.getByRole("button", { name: "Save changes" }).click();

await page
Expand Down
92 changes: 4 additions & 88 deletions src/app/planets/[id]/page.tsx
Original file line number Diff line number Diff line change
@@ -1,61 +1,17 @@
"use client";

import { Heading } from "@/components/heading";
import {
Card,
CardContent,
CardDescription,
CardHeader,
CardTitle,
} from "@/components/ui/card";
import { ResidentCard } from "@/components/resident-card";
import { useMediaQuery } from "@/hooks/use-media-query";
import { planetsAtom } from "@/lib/atoms";
import {
IconGenderFemale,
IconGenderHermaphrodite,
IconGenderMale,
IconQuestionMark,
IconRobot,
} from "@tabler/icons-react";
import { useAtomValue } from "jotai";
import Image from "next/image";
import { notFound } from "next/navigation";
import type { ReactNode } from "react";

type Props = {
params: { id: string };
};

function getGenderInfo(gender: string | undefined) {
if (!gender)
return {
name: "unknown",
icon: <IconQuestionMark />,
};

if (["male", "female", "hermaphrodite"].includes(gender)) {
let icon: ReactNode;

if (gender === "male") {
icon = <IconGenderMale />;
} else if (gender === "female") {
icon = <IconGenderFemale />;
} else {
icon = <IconGenderHermaphrodite />;
}

return {
name: gender,
icon,
};
}

return {
name: "droid",
icon: <IconRobot />,
};
}

export default function PlanetsPage({ params }: Props) {
const isDesktop = useMediaQuery("(min-width: 768px)");

Expand Down Expand Up @@ -148,49 +104,9 @@ export default function PlanetsPage({ params }: Props) {
</Heading>
{planet.residents.length > 0 ? (
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-4 mt-2">
{planet.residents.map((resident) => {
const genderInfo = getGenderInfo(resident.gender);

return (
<Card key={resident.id}>
<CardHeader className="flex flex-row items-center gap-x-4">
<div>{genderInfo.icon}</div>
<div className="break-all">
<CardTitle>{resident.name}</CardTitle>
<CardDescription className="capitalize">
{genderInfo.name}
</CardDescription>
</div>
</CardHeader>
<CardContent>
<div className="flex items-center gap-x-2">
<p className="font-bold">Eye color:</p>
<p>{resident.eyeColor ?? "-"}</p>
</div>
<div className="flex items-center gap-x-2">
<p className="font-bold">Hair color:</p>
<p>{resident.hairColor ?? "-"}</p>
</div>
<div className="flex items-center gap-x-2">
<p className="font-bold">Skin color:</p>
<p>{resident.skinColor ?? "-"}</p>
</div>
<div className="flex items-center gap-x-2">
<p className="font-bold">Height:</p>
<p>{resident.height ?? "-"}</p>
</div>
<div className="flex items-center gap-x-2">
<p className="font-bold">Mass:</p>
<p>{resident.mass ?? "-"}</p>
</div>
<div className="flex items-center gap-x-2">
<p className="font-bold">Birth year</p>
<p>{resident.birthYear ?? "-"}</p>
</div>
</CardContent>
</Card>
);
})}
{planet.residents.map((resident) => (
<ResidentCard key={resident.id} resident={resident} />
))}
</div>
) : (
<p className="text-center">There are no residents on this planet.</p>
Expand Down
96 changes: 96 additions & 0 deletions src/components/resident-card.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
import {
Card,
CardContent,
CardDescription,
CardHeader,
CardTitle,
} from "@/components/ui/card";
import type { Resident } from "@/lib/types";
import {
IconGenderFemale,
IconGenderHermaphrodite,
IconGenderMale,
IconQuestionMark,
IconRobot,
} from "@tabler/icons-react";
import type { ReactNode } from "react";

type Props = {
resident: Resident;
};

function getGenderInfo(gender: string | undefined) {
if (!gender)
return {
name: "unknown",
icon: <IconQuestionMark />,
};

if (["male", "female", "hermaphrodite"].includes(gender)) {
let icon: ReactNode;

if (gender === "male") {
icon = <IconGenderMale />;
} else if (gender === "female") {
icon = <IconGenderFemale />;
} else {
icon = <IconGenderHermaphrodite />;
}

return {
name: gender,
icon,
};
}

return {
name: "droid",
icon: <IconRobot />,
};
}

export function ResidentCard(props: Props) {
const { resident } = props;

const genderInfo = getGenderInfo(resident.gender);

return (
<Card key={resident.id}>
<CardHeader className="flex flex-row items-center gap-x-4">
<div>{genderInfo.icon}</div>
<div className="break-all">
<CardTitle>{resident.name}</CardTitle>
<CardDescription className="capitalize">
{genderInfo.name}
</CardDescription>
</div>
</CardHeader>
<CardContent>
<div className="flex items-center gap-x-2">
<p className="font-bold">Eye color:</p>
<p>{resident.eyeColor ?? "-"}</p>
</div>
<div className="flex items-center gap-x-2">
<p className="font-bold">Hair color:</p>
<p>{resident.hairColor ?? "-"}</p>
</div>
<div className="flex items-center gap-x-2">
<p className="font-bold">Skin color:</p>
<p>{resident.skinColor ?? "-"}</p>
</div>
<div className="flex items-center gap-x-2">
<p className="font-bold">Height:</p>
<p>{resident.height ?? "-"}</p>
</div>
<div className="flex items-center gap-x-2">
<p className="font-bold">Mass:</p>
<p>{resident.mass ?? "-"}</p>
</div>
<div className="flex items-center gap-x-2">
<p className="font-bold">Birth year</p>
<p>{resident.birthYear ?? "-"}</p>
</div>
</CardContent>
</Card>
);
}
2 changes: 2 additions & 0 deletions src/lib/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import type { z } from "zod";

export type Planet = Awaited<ReturnType<typeof getPlanets>>[number];

export type Resident = Planet["residents"][number];

export type OrderByField =
| ""
| "name"
Expand Down

0 comments on commit d6a290b

Please sign in to comment.