< Summary

Information
Class: locations.rooms.items.index.tsx
Assembly: app.routes
File(s): /home/runner/work/ClutterStock/ClutterStock/frontend/app/routes/locations.rooms.items.index.tsx
Tag: 58_25416222083
Line coverage
0%
Covered lines: 0
Uncovered lines: 29
Coverable lines: 29
Total lines: 76
Line coverage: 0%
Branch coverage
0%
Covered branches: 0
Total branches: 19
Branch coverage: 0%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

File(s)

/home/runner/work/ClutterStock/ClutterStock/frontend/app/routes/locations.rooms.items.index.tsx

#LineLine coverage
 1import { Link, redirect } from "react-router";
 2import type { Route } from "./+types/locations.rooms.items.index";
 3import { deleteItem, getLocation, getRoom, getItems } from "~/api/client";
 4import { Breadcrumb } from "~/components/breadcrumb";
 5import { ItemsList } from "~/components/items";
 6
 07export async function loader({ params, request }: Route.LoaderArgs) {
 08  const locationId = Number(params.id);
 09  const roomId = Number(params.roomId);
 010  if (Number.isNaN(locationId) || Number.isNaN(roomId)) {
 011    throw new Response("Not found", { status: 404 });
 12  }
 013  const [location, room, allItems] = await Promise.all([
 14    getLocation(locationId, request),
 15    getRoom(roomId, request),
 16    getItems(request),
 17  ]);
 018  if (!location || !room || room.locationId !== locationId) {
 019    throw new Response("Not found", { status: 404 });
 20  }
 021  const items = allItems.filter((i) => i.roomId === roomId);
 022  return { location, room, items };
 23}
 24
 025export async function action({ request, params }: Route.ActionArgs) {
 026  const locationId = Number(params.id);
 027  const roomId = Number(params.roomId);
 028  if (Number.isNaN(locationId) || Number.isNaN(roomId)) {
 029    throw new Response("Not found", { status: 404 });
 30  }
 031  const formData = await request.formData();
 032  if (formData.get("_action") !== "delete") return null;
 033  const itemId = Number(formData.get("id"));
 034  if (Number.isNaN(itemId)) return null;
 035  await deleteItem(itemId, request);
 036  return redirect(`/locations/${locationId}/rooms/${roomId}/items`);
 37}
 38
 039export function meta({ loaderData }: Route.MetaArgs) {
 040  const roomName = loaderData?.room?.name ?? "Room";
 041  return [{ title: `Items · ${roomName} | ClutterStock` }];
 42}
 43
 044export default function LocationsRoomsItemsIndex({
 45  loaderData,
 46}: Route.ComponentProps) {
 047  const { location, room, items } = loaderData;
 048  const locationId = location.id!;
 049  const roomId = room.id!;
 50
 051  return (
 52    <>
 53      <Breadcrumb
 54        crumbs={[
 55          { label: "Locations", to: "/locations" },
 56          { label: location.name ?? "Location", to: `/locations/${locationId}/edit` },
 57          { label: "Rooms", to: `/locations/${locationId}/rooms` },
 58          { label: room.name ?? "Room", to: `/locations/${locationId}/rooms/${roomId}/edit` },
 59          { label: "Items" },
 60        ]}
 61      />
 62      <div className="page-header">
 63        <h2 className="page-title">Items</h2>
 64        <Link to={`/locations/${locationId}/rooms/${roomId}/items/new`} className="btn-primary">
 65          + Add item
 66        </Link>
 67      </div>
 68      <ItemsList
 69        locationId={locationId}
 70        roomId={roomId}
 71        roomName={room.name ?? "this room"}
 72        items={items}
 73      />
 74    </>
 75  );
 76}