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

118 checklist #214

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
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
39 changes: 39 additions & 0 deletions app/atoms/checklists.new.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import type { ChangeEvent } from "react";
import { atom } from "jotai";
import { verifyAccept } from "~/utils";

export const titleAtom = atom("Untitled Checklist");
export const updateTitleAtom = atom(
null,
(_get, set, event: ChangeEvent<HTMLInputElement>) =>
set(titleAtom, event.target.value)
);

export const fileErrorAtom = atom<string | undefined>(undefined);

/** Validates the file atom */
export const validateFileAtom = atom(
null,
(_get, set, event: ChangeEvent<HTMLInputElement>) => {
set(fileErrorAtom, () => {
const file = event?.target?.files?.[0];
if (file) {
const allowedType = verifyAccept(file.type, event.target.accept);
const allowedSize = file.size < 4_000_000;

if (!allowedType) {
event.target.value = "";
return `Allowed file types are: PNG, JPG or JPEG`;
}

if (!allowedSize) {
/** Clean the field */
event.target.value = "";
return "Max file size is 4MB";
}

return undefined;
}
});
}
);
87 changes: 87 additions & 0 deletions app/components/checklists/form.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import { Form, useNavigation } from "@remix-run/react";
import { useAtom, useAtomValue } from "jotai";
import {
fileErrorAtom,
updateTitleAtom,
validateFileAtom,
} from "~/atoms/checklists.new";
import { isFormProcessing } from "~/utils";
import FormRow from "../forms/form-row";
import Input from "../forms/input";
import { Button } from "../shared";
import { Spinner } from "../shared/spinner";

/** Pass props of the values to be used as default for the form fields */
interface Props {
title?: any;
description?: any;
}

export const NewChecklistForm = ({ title, description }: Props) => {
const navigation = useNavigation();
const disabled = isFormProcessing(navigation.state);

const fileError = useAtomValue(fileErrorAtom);
const [, validateFile] = useAtom(validateFileAtom);
const [, updateTitle] = useAtom(updateTitleAtom);

return (
<Form
method="post"
className="flex w-full flex-col gap-2"
encType="multipart/form-data"
>
<FormRow rowLabel={"Name"} className="border-b-0">
<Input
label="Name"
hideLabel
name="name"
disabled={disabled}
autoFocus
onChange={updateTitle}
className="w-full"
defaultValue={title || undefined}
required
/>
</FormRow>

<div>
<FormRow rowLabel="Description">
<Input
inputType="textarea"
label="Description"
name="description"
defaultValue={description || ""}
placeholder="Add a description for your asset."
disabled={disabled}
data-test-id="itemDescription"
className="w-full"
/>
</FormRow>
</div>
<FormRow rowLabel={"Thumbnail"}>
<div>
<p>Accepts PNG, JPG or JPEG (max.4 MB)</p>
<Input
disabled={disabled}
accept="image/png,.png,image/jpeg,.jpg,.jpeg"
name="thumbnail"
type="file"
onChange={validateFile}
label={"thumbnail"}
hideLabel
error={fileError}
className="mt-2"
inputClassName="border-0 shadow-none p-0 rounded-none"
/>
</div>
</FormRow>

<div className="text-right">
<Button type="submit" disabled={disabled}>
{disabled ? <Spinner /> : "Save"}
</Button>
</div>
</Form>
);
};
42 changes: 42 additions & 0 deletions app/components/icons/library.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -799,3 +799,45 @@ export const LocationMarkerIcon = (props: SVGProps<SVGSVGElement>) => (
/>
</svg>
);

export function CheckboxIcon(props: SVGProps<SVGSVGElement>) {
return (
<svg
width="21"
height="20"
viewBox="0 0 21 20"
fill="none"
xmlns="http://www.w3.org/2000/svg"
{...props}
>
<path
d="M7 9L10 12L20 2M14 1H5.8C4.11984 1 3.27976 1 2.63803 1.32698C2.07354 1.6146 1.6146 2.07354 1.32698 2.63803C1 3.27976 1 4.11984 1 5.8V14.2C1 15.8802 1 16.7202 1.32698 17.362C1.6146 17.9265 2.07354 18.3854 2.63803 18.673C3.27976 19 4.11984 19 5.8 19H14.2C15.8802 19 16.7202 19 17.362 18.673C17.9265 18.3854 18.3854 17.9265 18.673 17.362C19 16.7202 19 15.8802 19 14.2V10"
stroke="#667085"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
);
}

export function MinusSquareIcon(props: SVGProps<SVGSVGElement>) {
return (
<svg
width="18"
height="18"
viewBox="0 0 18 18"
fill="none"
xmlns="http://www.w3.org/2000/svg"
{...props}
>
<path
d="M5.66667 9H12.3333M5.5 16.5H12.5C13.9001 16.5 14.6002 16.5 15.135 16.2275C15.6054 15.9878 15.9878 15.6054 16.2275 15.135C16.5 14.6002 16.5 13.9001 16.5 12.5V5.5C16.5 4.09987 16.5 3.3998 16.2275 2.86502C15.9878 2.39462 15.6054 2.01217 15.135 1.77248C14.6002 1.5 13.9001 1.5 12.5 1.5H5.5C4.09987 1.5 3.3998 1.5 2.86502 1.77248C2.39462 2.01217 2.01217 2.39462 1.77248 2.86502C1.5 3.3998 1.5 4.09987 1.5 5.5V12.5C1.5 13.9001 1.5 14.6002 1.77248 15.135C2.01217 15.6054 2.39462 15.9878 2.86502 16.2275C3.3998 16.5 4.09987 16.5 5.5 16.5Z"
stroke="#475467"
strokeWidth="1.66667"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
);
}
6 changes: 6 additions & 0 deletions app/components/layout/sidebar/menu-items.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
QuestionsIcon,
SettingsIcon,
TagsIcon,
CheckboxIcon,
} from "~/components/icons/library";
import { CrispButton } from "~/components/marketing/crisp";
import type { loader } from "~/routes/_layout+/_layout";
Expand Down Expand Up @@ -35,6 +36,11 @@ const menuItemsTop = [
to: "locations",
label: "Locations (beta)",
},
{
icon: <CheckboxIcon />,
to: "checklists",
label: "Checklists",
},
];
const menuItemsBottom = [
{
Expand Down
107 changes: 107 additions & 0 deletions app/routes/_layout+/checklists.$checklistId._index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
import type { LoaderArgs } from "@remix-run/node";
import { json } from "@remix-run/node";
import { MinusSquareIcon, TrashIcon } from "~/components/icons";
import { List } from "~/components/list";
import { Badge } from "~/components/shared";
import { Td, Th } from "~/components/table";
import { requireAuthSession } from "~/modules/auth";

export async function loader({ request }: LoaderArgs) {
await requireAuthSession(request);
const title = "Checklist";
const header = {
title,
};
const items: any[] = [
{
id: "S349a002e",
title: "General Lighting Equipment",
mainImage: "/images/asset-placeholder.jpg",
},
{
id: "S349a002f",
title: "Threeway Camera Production",
mainImage: "/images/asset-placeholder.jpg",
},
{
id: "S349a002g",
title: "In-House Workstations",
mainImage: "/images/asset-placeholder.jpg",
},
{
id: "S349a002h",
title: "Camera Equipment",
mainImage: "/images/asset-placeholder.jpg",
},
];
const totalItems = 4;
const perPage = 8;
const page = 1;
const prev = "";
const next = "";
const totalPages = 1;
const modelName = {
singular: "checklist",
plural: "checklists",
};
return json({
header,
items,
totalItems,
page,
prev,
next,
perPage,
totalPages,
modelName,
});
}

export default function InspectChecklist() {
return (
<div className="mt-8 flex flex-1 flex-col md:mx-0 md:gap-2">
<List
ItemComponent={ChecklistContent}
headerChildren={
<>
<Th className="hidden md:table-cell">Category</Th>
<Th className="hidden md:table-cell"> </Th>
</>
}
/>
</div>
);
}

function ChecklistContent({ item }: { item: any }) {
return (
<>
<Td className="w-full p-0 md:p-0">
<div className="flex justify-between gap-3 p-4 md:justify-normal md:px-6">
<div className="flex items-center gap-3">
<div className="flex h-12 w-12 items-center justify-center">
<img
src={item.mainImage}
alt="img"
className="h-10 w-10 rounded-[4px] object-cover"
/>
</div>
<div className="flex flex-row items-center gap-2 md:flex-col md:items-start md:gap-0">
<div className="font-medium">{item.title}</div>
</div>
</div>

<button className="block md:hidden">
<TrashIcon />
</button>
</div>
</Td>
<Td className="hidden md:table-cell">
<Badge color="#175CD3">office</Badge>
</Td>
<Td className="hidden text-left md:table-cell">
<MinusSquareIcon />
</Td>
</>
);
}
97 changes: 97 additions & 0 deletions app/routes/_layout+/checklists.$checklistId.history.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
import type { LoaderArgs } from "@remix-run/node";
import { json } from "@remix-run/node";
import { List } from "~/components/list";
import { Badge } from "~/components/shared";
import { Td, Th } from "~/components/table";
import { requireAuthSession } from "~/modules/auth";

export async function loader({ request }: LoaderArgs) {
await requireAuthSession(request);
const title = "Checklists History";
const header = {
title,
};
const items = [
{
id: "1",
date: "Jan 6, 2022",
isCompleted: false,
totalItems: 8,
completedItems: 4,
},
{
id: "2",
date: "Jan 6, 2022",
isCompleted: true,
totalItems: 8,
completedItems: 8,
},
{
id: "3",
date: "Jan 6, 2022",
isCompleted: true,
totalItems: 8,
completedItems: 8,
},
{
id: "4",
date: "Jan 5, 2022",
isCompleted: true,
totalItems: 8,
completedItems: 8,
},
];
const totalItems = 4;
const perPage = 8;
const page = 1;
const prev = "";
const next = "";
const totalPages = 1;
const modelName = {
singular: "date",
plural: "dates",
};
return json({
header,
items,
totalItems,
page,
prev,
next,
perPage,
totalPages,
modelName,
});
}

export default function ChecklistHistory() {
return (
<div className="mt-8 flex flex-1 flex-col md:mx-0 md:gap-2">
<List
ItemComponent={RowContent}
headerChildren={
<>
<Th>Status</Th>
<Th>Result</Th>
</>
}
/>
</div>
);
}

function RowContent({ item }: { item: any }) {
return (
<>
<Td className="w-full">
<div className="font-medium">{item.date}</div>
</Td>
<Td>
<Badge color="#027A48">Completed</Badge>
</Td>
<Td className="text-left">
<Badge color="#027A48">8/8</Badge>
</Td>
</>
);
}
Loading
Loading