Skip to content

Commit

Permalink
Merge pull request #671 from hngprojects/feat/HNG-147-super-admin-pro…
Browse files Browse the repository at this point in the history
…duct-list-page

Feat/hng 147 super admin product list page
  • Loading branch information
Samadeen authored Jul 25, 2024
2 parents c62d598 + 944549c commit dda353c
Show file tree
Hide file tree
Showing 10 changed files with 768 additions and 5 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
import { Button } from "~/components/common/common-button";
import { Input } from "~/components/common/input";
import {
Dialog,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
DialogTrigger,
} from "~/components/ui/dialog";
import { Label } from "~/components/ui/label";
import { Textarea } from "~/components/ui/textarea";

interface AddProductModalProperties {
children: React.ReactNode;
}
const AddProductModal = ({ children }: AddProductModalProperties) => {
return (
<Dialog>
<DialogTrigger asChild>{children}</DialogTrigger>
<DialogContent className="flex h-fit max-h-[500px] flex-col gap-[23px] overflow-y-auto rounded-none border bg-white p-6 sm:max-w-[500px]">
<DialogHeader className="inline-flex flex-col items-start justify-start">
<DialogTitle className="text-lg font-bold text-neutral-950">
Add new product
</DialogTitle>
<DialogDescription className="text-xs leading-3 text-slate-500">
Create a new product
</DialogDescription>
</DialogHeader>
<div className="flex flex-col gap-3 px-2">
<div className="items-left flex flex-col gap-1">
<Label
htmlFor="productname"
className="left-0 text-left text-sm font-medium text-slate-900"
>
Product name
</Label>
<Input
id="productname"
required
placeholder="@Joh Doe"
className="col-span-3 inline-flex h-10 items-start justify-start gap-2"
/>
</div>
<div className="items-left flex flex-col gap-1">
<Label
htmlFor="productdescription"
className="left-0 text-left text-sm font-medium text-slate-900"
>
Product Description
</Label>
<Textarea
id="productdescription"
required
placeholder="add product description"
className="col-span-3 inline-flex h-10 items-start justify-start gap-2 border bg-transparent text-primary focus:outline-none focus:ring-1 focus:ring-primary focus-visible:ring-1 focus-visible:ring-primary focus-visible:ring-offset-0"
/>
</div>
<div className="items-left flex flex-col gap-1">
<Label
htmlFor="price"
className="left-0 text-left text-sm font-medium text-slate-900"
>
Price
</Label>
<Input
type="number"
id="price"
required
placeholder="e.g 2000.00"
className="col-span-3 inline-flex h-10 items-start justify-start gap-2"
/>
</div>
<div className="items-left flex flex-col gap-1">
<Label
htmlFor="quantity"
className="left-0 text-left text-sm font-medium text-slate-900"
>
Quantity
</Label>
<Input
type="number"
id="quantity"
required
placeholder="e.g 1000"
className="col-span-3 inline-flex h-10 items-start justify-start gap-2"
/>
</div>
<div className="items-left flex flex-col gap-1">
<span className="left-0 text-left text-sm font-medium text-slate-900">
Upload Images
</span>
<Button className="w-48" variant={"subtle"} size={"sm"}>
Choose file No file choosen
</Button>
<div className="mt-4 inline-flex h-[56px] items-start justify-start gap-[15px]">
<div className="h-14 w-14 rounded bg-neutral-50" />
<div className="h-14 w-14 rounded bg-neutral-50" />
<div className="h-14 w-14 rounded bg-neutral-50" />
</div>
</div>
</div>
<DialogFooter>
<Button variant={"primary"} type="submit">
Add Product
</Button>
</DialogFooter>
</DialogContent>
</Dialog>
);
};

export default AddProductModal;
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import { fireEvent, render, screen } from "@testing-library/react";
import { describe, expect, it } from "vitest";

import AddProductModal from "./add-product-modal";

describe("addProductModal", () => {
it("renders the modal with correct title and description", async () => {
expect.hasAssertions();
render(
<AddProductModal>
<button>Open Modal</button>
</AddProductModal>,
);

// Check if the trigger button is rendered
expect(screen.getByText("Open Modal")).toBeInTheDocument();

// Open the modal
fireEvent.click(screen.getByText("Open Modal"));

// Check if the modal title and description are rendered
await expect(
screen.findByText("Add new product"),
).resolves.toBeInTheDocument();
await expect(
screen.findByText("Create a new product"),
).resolves.toBeInTheDocument();
});

it("renders form fields", async () => {
expect.hasAssertions();
render(
<AddProductModal>
<button>Open Modal</button>
</AddProductModal>,
);

// Open the modal
fireEvent.click(screen.getByText("Open Modal"));

// Check if form fields are rendered
await expect(
screen.findByLabelText("Product name"),
).resolves.toBeInTheDocument();
await expect(
screen.findByLabelText("Product Description"),
).resolves.toBeInTheDocument();
await expect(screen.findByLabelText("Price")).resolves.toBeInTheDocument();
await expect(
screen.findByLabelText("Quantity"),
).resolves.toBeInTheDocument();
await expect(
screen.findByText("Upload Images"),
).resolves.toBeInTheDocument();
});

it("renders submit button", async () => {
expect.hasAssertions();
render(
<AddProductModal>
<button>Open Modal</button>
</AddProductModal>,
);

// Open the modal
fireEvent.click(screen.getByText("Open Modal"));

// Check if the submit button is rendered
await expect(
screen.findByRole("button", { name: "Add Product" }),
).resolves.toBeInTheDocument();
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { fireEvent, render, screen } from "@testing-library/react";
import { describe, expect, it, vi } from "vitest";

import DeleteDialog from "./delete-dialog";

describe("deleteDialog", () => {
it("renders the dialog with correct content", () => {
expect.hasAssertions();
const onClose = vi.fn();
render(<DeleteDialog onClose={onClose} />);

expect(screen.getByText("Are you absolutely sure?")).toBeInTheDocument();
expect(
screen.getByText(
"This action cannot be undone. This will permanently delete this product from the database.",
),
).toBeInTheDocument();
expect(screen.getByRole("button", { name: /cancel/i })).toBeInTheDocument();
expect(screen.getByRole("button", { name: /delete/i })).toBeInTheDocument();
});

it("calls onClose when Cancel button is clicked", () => {
expect.hasAssertions();
const onClose = vi.fn();
render(<DeleteDialog onClose={onClose} />);

fireEvent.click(screen.getByRole("button", { name: /cancel/i }));
expect(onClose).toHaveBeenCalledTimes(1);
});

it("calls onClose when Delete button is clicked", () => {
expect.hasAssertions();
const onClose = vi.fn();
render(<DeleteDialog onClose={onClose} />);

fireEvent.click(screen.getByRole("button", { name: /delete/i }));
expect(onClose).toHaveBeenCalledTimes(1);
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { Button } from "~/components/common/common-button";
import {
Dialog,
DialogContent,
DialogDescription,
DialogHeader,
DialogTitle,
} from "~/components/ui/dialog";

const DeleteDialog = ({ onClose }: { onClose: () => void }) => {
return (
<Dialog open onOpenChange={onClose}>
<DialogContent>
<DialogHeader>
<DialogTitle className="text-lg font-semibold leading-7 text-slate-900">
Are you absolutely sure?
</DialogTitle>
<DialogDescription className="text-sm font-normal leading-tight text-slate-500">
This action cannot be undone. This will permanently delete this
product from the database.
</DialogDescription>
</DialogHeader>
<div className="flex w-full">
<Button
variant="outline"
className="ml-auto flex items-center justify-center gap-2.5 rounded-md px-4 py-2 text-sm font-medium leading-normal"
onClick={onClose}
>
Cancel
</Button>
<Button
onClick={onClose}
className="ml-2 flex items-center justify-center gap-2.5 rounded-md bg-red-600 px-4 py-2 text-sm font-medium leading-normal text-white"
>
Delete
</Button>
</div>
</DialogContent>
</Dialog>
);
};

export default DeleteDialog;
Loading

0 comments on commit dda353c

Please sign in to comment.