feat: New design and optimization

This commit is contained in:
2025-10-27 13:23:05 +05:45
parent 63777cb3c1
commit db9315ad22
44 changed files with 2877 additions and 336 deletions

View File

@@ -7,13 +7,14 @@ import FilePondPluginImageExifOrientation from 'filepond-plugin-image-exif-orien
import FilePondPluginImagePreview from 'filepond-plugin-image-preview';
import 'filepond-plugin-image-preview/dist/filepond-plugin-image-preview.css';
import 'filepond/dist/filepond.min.css';
import { useState } from 'react';
import { useEffect, useState } from 'react';
import { FilePond, registerPlugin } from 'react-filepond';
import { toast } from 'sonner';
registerPlugin(FilePondPluginImageExifOrientation, FilePondPluginImagePreview);
export default function CarouselAdd() {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const [file, setFile] = useState<any | null>(null);
const { data, setData, post, processing, errors, wasSuccessful } = useForm({
@@ -21,12 +22,14 @@ export default function CarouselAdd() {
image_url: null as File | null,
});
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
useEffect(() => {
if (file) {
setData('image_url', file.file);
}
}, [file, setData]);
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
post('/carousel', {
forceFormData: true,
@@ -72,7 +75,7 @@ export default function CarouselAdd() {
}}
allowMultiple={false}
maxFiles={1}
name="image_url" // Change this to match your backend expectation
name="image_url"
instantUpload={false}
storeAsFile={true}
labelIdle='Drag & Drop your image or <span class="filepond--label-action">Browse</span>'
@@ -84,7 +87,11 @@ export default function CarouselAdd() {
)}
</div>
<Button type="submit" disabled={processing}>
<Button
type="submit"
disabled={processing}
className="cursor-pointer"
>
{processing ? 'Uploading...' : 'Submit'}
</Button>
</form>

View File

@@ -31,7 +31,9 @@ export default function Carousel({
Carousel
</h1>
<Link href={dashboardcarousel.add()}>
<Button>Add Image</Button>
<Button className="cursor-pointer">
Add Image
</Button>
</Link>
</div>
<Table>

View File

@@ -0,0 +1,162 @@
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import {
Select,
SelectContent,
SelectGroup,
SelectItem,
SelectTrigger,
SelectValue,
} from '@/components/ui/select';
import AppLayout from '@/layouts/app-layout';
import dashboard from '@/routes/dashboard';
import { Head, useForm } from '@inertiajs/react';
import FilePondPluginImageExifOrientation from 'filepond-plugin-image-exif-orientation';
import FilePondPluginImagePreview from 'filepond-plugin-image-preview';
import 'filepond-plugin-image-preview/dist/filepond-plugin-image-preview.css';
import 'filepond/dist/filepond.min.css';
import { useEffect, useState } from 'react';
import { FilePond, registerPlugin } from 'react-filepond';
import { toast } from 'sonner';
registerPlugin(FilePondPluginImageExifOrientation, FilePondPluginImagePreview);
export default function CarouselAdd() {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const [file, setFile] = useState<any | null>(null);
// const [type, setType] = useState<string>('traditional');
const { data, setData, post, processing, errors, wasSuccessful } = useForm({
title: '',
type: 'traditional',
image_url: null as File | null,
});
useEffect(() => {
if (file) {
setData('image_url', file.file);
}
}, [file, setData]);
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
post(dashboard.product.add().url, {
forceFormData: true,
});
if (wasSuccessful) {
toast.success('Product added successfully');
}
};
return (
<AppLayout>
<Head title="Add Product Image" />
<section className="flex flex-col gap-8 px-8 py-8">
<h1 className="text-lg font-semibold tracking-tight">
Add Product Image
</h1>
<form
onSubmit={handleSubmit}
method="POST"
encType="multipart/formdata"
>
<div className="flex items-center gap-4">
<div className="flex w-full flex-col gap-4">
<Label htmlFor="title">Title</Label>
<Input
type="text"
id="title"
value={data.title}
onChange={(e) =>
setData('title', e.target.value)
}
className="rounded border p-2"
/>
{errors.title && (
<span className="text-red-600">
{errors.title}
</span>
)}
</div>
<div className="flex w-full flex-col gap-4">
<Label htmlFor="title">Type</Label>
<Select
value={data.type}
onValueChange={(e) => {
console.log(e);
setData('type', e);
}}
>
<SelectTrigger>
<SelectValue placeholder="Select a type" />
</SelectTrigger>
<SelectContent>
<SelectGroup>
<SelectItem value="traditional">
Traditional
</SelectItem>
<SelectItem value="modern">
Modern
</SelectItem>
<SelectItem value="bespoke">
Bespoke
</SelectItem>
<SelectItem value="abstract">
Abstract
</SelectItem>
<SelectItem value="art">
Art in carpet
</SelectItem>
</SelectGroup>
</SelectContent>
</Select>
{/* <Input
type="text"
id="title"
value={data.alt}
onChange={(e) => setData('alt', e.target.value)}
className="rounded border p-2"
/>
{errors.alt && (
<span className="text-red-600">{errors.alt}</span>
)} */}
</div>
</div>
<div className="mt-4">
<Label>Image</Label>
<FilePond
files={file ? [file] : []}
onupdatefiles={(fileItems) => {
setFile(fileItems[0] || null);
}}
allowMultiple={false}
maxFiles={1}
name="image_url"
instantUpload={false}
storeAsFile={true}
labelIdle='Drag & Drop your image or <span class="filepond--label-action">Browse</span>'
/>
{errors.image_url && (
<span className="text-red-600">
{errors.image_url}
</span>
)}
</div>
<Button
type="submit"
disabled={processing}
className="cursor-pointer"
>
{processing ? 'Uploading...' : 'Submit'}
</Button>
</form>
</section>
</AppLayout>
);
}

View File

@@ -0,0 +1,82 @@
import { Button } from '@/components/ui/button';
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from '@/components/ui/table';
import AppLayout from '@/layouts/app-layout';
import dashboard from '@/routes/dashboard';
import { Head, Link } from '@inertiajs/react';
import { Pencil, Trash2 } from 'lucide-react';
export default function Product({
product,
}: {
product: [{ title: string; type: string; image_url: string }];
}) {
return (
<AppLayout
breadcrumbs={[
{ title: 'Products', href: dashboard.product.index().url },
]}
>
<Head title="Products" />
<section className="flex flex-col gap-8 px-8 py-8">
<div className="flex items-center justify-between">
<h1 className="text-xl font-semibold tracking-tight">
Products
</h1>
<Link href={dashboard.product.add()}>
<Button className="cursor-pointer">Add Image</Button>
</Link>
</div>
<Table>
<TableHeader>
<TableRow>
<TableHead className="w-[80px]">S.N.</TableHead>
<TableHead className="w-48">Image</TableHead>
<TableHead>Title</TableHead>
<TableHead className="w-24">Type</TableHead>
<TableHead className="text-right">Action</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{product.map((item, index) => (
<TableRow key={index}>
<TableCell className="font-medium">
{index + 1}
</TableCell>
<TableCell>
<img
src={item.image_url}
alt={item.title}
className="aspect-video w-24 rounded-md object-cover object-center"
/>
</TableCell>
<TableCell>{item.title}</TableCell>
<TableCell>{item.type}</TableCell>
<TableCell className="text-right">
<div className="flex items-center justify-end gap-2">
<Link href="">
<Pencil size={18} />
</Link>
<Link href="">
<Trash2
size={18}
color={'#D2042D'}
/>
</Link>
</div>
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</section>
</AppLayout>
);
}

View File

@@ -1,16 +1,82 @@
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from '@/components/ui/table';
import AppLayout from '@/layouts/app-layout';
import testimonial from '@/routes/testimonial';
import { Head } from '@inertiajs/react';
import { index } from '@/routes/testimonial';
import { Head, Link } from '@inertiajs/react';
import { Pencil, Trash2 } from 'lucide-react';
export default function Testimonial() {
export default function Testimonial({
testimonial,
}: {
testimonial: [
{ name: string; description: string; location: string; image: string },
];
}) {
return (
<>
<AppLayout
breadcrumbs={[
{ title: 'testimonial', href: testimonial.index().url },
]}
breadcrumbs={[{ title: 'Testimonial', href: index().url }]}
>
<Head title={'Testimonials'}></Head>
<section className="flex flex-col gap-8 px-8 py-8">
<div className="flex items-center justify-between">
<h1 className="text-xl font-semibold tracking-tight">
Testimonial
</h1>
</div>
<Table>
<TableHeader>
<TableRow>
<TableHead className="w-[80px]">S.N.</TableHead>
<TableHead className="w-48">Image</TableHead>
<TableHead>Name</TableHead>
<TableHead>Location</TableHead>
<TableHead>Description</TableHead>
<TableHead className="text-right">
Action
</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{testimonial.map((item, index) => (
<TableRow key={index}>
<TableCell className="font-medium">
{index + 1}
</TableCell>
<TableCell>
<img
src={item.image}
alt={item.name}
className="aspect-video w-24 rounded-md object-cover object-center"
/>
</TableCell>
<TableCell>{item.name}</TableCell>
<TableCell>{item.location}</TableCell>
<TableCell>{item.description}</TableCell>
<TableCell className="text-right">
<div className="flex items-center justify-end gap-2">
<Link href="">
<Pencil size={18} />
</Link>
<Link href="">
<Trash2
size={18}
color={'#D2042D'}
/>
</Link>
</div>
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</section>
</AppLayout>
</>
);