< Summary

Information
Class: item-form.tsx
Assembly: app.components.items
File(s): /home/runner/work/ClutterStock/ClutterStock/frontend/app/components/items/item-form.tsx
Tag: 58_25416222083
Line coverage
0%
Covered lines: 0
Uncovered lines: 9
Coverable lines: 9
Total lines: 81
Line coverage: 0%
Branch coverage
0%
Covered branches: 0
Total branches: 4
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/components/items/item-form.tsx

#LineLine coverage
 1import { Form, Link } from "react-router";
 2import type { ItemResponse } from "~/api/client";
 3import { fieldError } from "~/lib/forms";
 4
 5type ItemFormProps = {
 6  title: string;
 7  submitLabel: string;
 8  error?: string;
 9  fieldErrors?: Record<string, string[]>;
 10  item?: ItemResponse | null;
 11  roomId: number;
 12  cancelTo: string;
 13};
 14
 015export function ItemForm({ title, submitLabel, error, fieldErrors, item, roomId: _roomId, cancelTo }: ItemFormProps) {
 016  const nameError = fieldError(fieldErrors, "name");
 017  const descriptionError = fieldError(fieldErrors, "description");
 018  const categoryError = fieldError(fieldErrors, "category");
 019  const notesError = fieldError(fieldErrors, "notes");
 020  if (item === null) {
 021    return (
 22      <div className="card-padded">
 23        <p className="text-muted">Item not found.</p>
 24        <Link to={cancelTo} className="link-text" style={{ display: "inline-block", marginTop: 8 }}>
 25          Back to items
 26        </Link>
 27      </div>
 28    );
 29  }
 30
 031  return (
 32    <div className="card-padded">
 33      <h2 className="card-title">{title}</h2>
 34      <Form method="post" className="form-group">
 35        {error && <p className="text-error">{error}</p>}
 36        <div className="form-field">
 37          <label htmlFor="name" className="form-label">Name</label>
 38          <input id="name" name="name" type="text" required autoFocus={!item}
 39            defaultValue={item?.name ?? ""} className="form-input" placeholder="e.g. Vintage Lamp"
 40            aria-invalid={nameError ? true : undefined} />
 41          {nameError && <p className="text-error" style={{ marginTop: 4 }}>{nameError}</p>}
 42        </div>
 43        <div className="form-field">
 44          <label htmlFor="description" className="form-label">Description (optional)</label>
 45          <textarea id="description" name="description" rows={2}
 46            defaultValue={item?.description ?? ""} className="form-input" placeholder="e.g. Brass table lamp, 1980s"
 47            aria-invalid={descriptionError ? true : undefined} />
 48          {descriptionError && <p className="text-error" style={{ marginTop: 4 }}>{descriptionError}</p>}
 49        </div>
 50        <div className="form-field">
 51          <label htmlFor="category" className="form-label">Category (optional)</label>
 52          <input id="category" name="category" type="text"
 53            defaultValue={item?.category ?? ""} className="form-input" placeholder="e.g. Electronics, Furniture"
 54            aria-invalid={categoryError ? true : undefined} />
 55          {categoryError && <p className="text-error" style={{ marginTop: 4 }}>{categoryError}</p>}
 56        </div>
 57        <div className="form-field">
 58          <label htmlFor="notes" className="form-label">Notes (optional)</label>
 59          <textarea id="notes" name="notes" rows={2}
 60            defaultValue={item?.notes ?? ""} className="form-input" placeholder="e.g. Needs new shade"
 61            aria-invalid={notesError ? true : undefined} />
 62          {notesError && <p className="text-error" style={{ marginTop: 4 }}>{notesError}</p>}
 63        </div>
 64        <div className="form-actions">
 65          <button type="submit" className="btn-primary">{submitLabel}</button>
 66          <Link to={cancelTo} className="btn-secondary">Cancel</Link>
 67        </div>
 68      </Form>
 69      {item?.id != null && (
 70        <Form
 71          method="post"
 72          style={{ marginTop: 24, paddingTop: 16, borderTop: "1px solid var(--c-border)" }}
 073          onSubmit={(e) => { if (!confirm("Delete this item?")) e.preventDefault(); }}
 74        >
 75          <input type="hidden" name="_action" value="delete" />
 76          <button type="submit" className="btn-danger">Delete item</button>
 77        </Form>
 78      )}
 79    </div>
 80  );
 81}

Methods/Properties

ItemForm()V
(anonymous_1)()V