INit
Some checks failed
linter / quality (push) Has been cancelled
tests / ci (push) Has been cancelled

This commit is contained in:
Chief-spartan-117
2025-09-28 19:55:43 +05:45
commit 2162084b95
236 changed files with 28717 additions and 0 deletions

View File

@@ -0,0 +1,170 @@
import Layout from '@/layouts/client/layout';
import ourStory from '@asset/img/about/A1PG1ALsIBL._AC_UF894,1000_QL80_.jpg';
import kaleen from '@asset/img/about/kaleen.jpg';
import ns from '@asset/img/about/ns.gif';
import oko from '@asset/img/about/oko.gif';
import { Head } from '@inertiajs/react';
import { HeartHandshake, Lightbulb, Target } from 'lucide-react';
export default function About() {
return (
<>
<Head title="About Us">
<meta
name="description"
content="Experience the finest hand-knotted carpets in Nepal with Soorya Carpet. Each piece is crafted by skilled artisans to deliver unmatched quality, luxury, and timeless design."
/>
</Head>
<Layout>
<section className="mx-auto flex max-w-screen-2xl flex-col gap-32 px-12 py-12 max-sm:px-8">
<div className="grid h-1/2 grid-cols-2 gap-20 overflow-clip max-md:grid-cols-1 max-md:gap-12">
<div className="flex flex-col gap-2">
<h1 className="font-serif text-5xl leading-tight font-medium tracking-tight max-sm:text-4xl">
Our Story: Crafting Legacies Since 1974
</h1>
<div className="flex flex-col gap-4 text-sm max-sm:text-base">
<p>
The story of Soorya Carpet Industries begins
in the early 1970s, when Mr. Laxman Shrestha
and Mrs. Renuka Shrestha left their village
in Dolakha and moved to Kathmandu with the
ambition of building something meaningful.
What started as a small rug-weaving
initiative in a single room eventually grew
into one of Nepals largest carpet
manufacturing enterprises. Through
perseverance and vision, they provided
livelihoods to more than 1,000 skilled and
unskilled workers and made a significant
contribution to the countrys GDP. For over
two decades, Soorya Carpet Industries earned
international recognition, particularly in
Germany, for exporting high-quality,
hand-knotted carpets.
</p>
<p>
By the late 1990s, however, Nepals carpet
industry suffered severe setbacks owing to
economic, social, and political challenges.
Global scrutiny following child labour
controversies in the wider industry, coupled
with the instability caused by the Maoist
insurgency, crippled the sector. Like many
others, Soorya Carpet Industries was forced
to scale down and eventually suspend
production.
</p>
<p>
The industry never quite returned to its
early-1990s mass-scale export peak, yet it
found ways to reinvent itself and stay
relevant. Recognizing this shift, Soorya
Carpet Industries transitioned from
large-scale production to a boutique model,
focusing on the niche luxury segment with
custom-made, limited-edition rugs.
</p>
</div>
</div>
<img
src={ourStory}
alt="Our Story"
className="aspect-[5/3] h-full w-full rounded-xl object-cover object-center"
/>
</div>{' '}
<div className="grid h-1/2 grid-cols-2 gap-20 overflow-clip max-md:grid-cols-1 max-md:gap-12">
<img
src={kaleen}
alt="Kaleen Story"
className="aspect-[5/3] h-full w-full rounded-xl object-cover object-center"
/>
<div className="flex flex-col gap-2">
<h2 className="font-serif text-5xl leading-tight font-medium tracking-tight max-sm:text-4xl">
The Kaleen Rebrand Story: A New Chapter
</h2>
<div className="flex flex-col gap-4 text-sm max-sm:text-base">
<p>
Guided by the aspiration to create premium,
ethical and artistic carpets, this journey
led to the launch of Kaleenour exclusive
designer carpet brand.
</p>
<p>
Kaleen celebrates craftsmanship, artistry,
and ethics. We create bespoke,
limited-edition rugs that range from
time-honoured traditional designs to bold,
innovative forms, all crafted to complement
modern interiors and aesthetics. Our
collections are inspired by beautiful
landscapes of Nepal and the five elements of
life: Fire, Water, Earth, Air, and Metal.
</p>
<p>
Handmade carpets have long been central to
interior designa tradition that remains
timeless. At Kaleen, we are proud to carry
this heritage forward with integrity and
creativity. Our ambition is to build a
strong brand identity, uphold ethical
credibility, and expand into discerning
global markets.
</p>
</div>
</div>
</div>
</section>
<section className="mx-auto flex max-w-screen-2xl flex-col gap-8 px-12 py-12 max-md:px-6">
<h3 className="text-center font-serif text-5xl leading-tight font-medium tracking-tight max-sm:text-4xl">
Our Guiding Principles
</h3>
<div className="flex gap-8 max-md:flex-col">
<div className="flex flex-col items-center gap-4 rounded-xl bg-accent px-8 py-8 text-center max-sm:px-4">
<Lightbulb size={48} color="#5A1A1A" />
<p className="font-serif text-3xl font-semibold">
Our vision
</p>
<p className="text-center">
To be the global leader in luxury handcrafted
carpets, renowned for unparalleled quality,
innovative design, and sustainable practices.
</p>
</div>{' '}
<div className="flex flex-col items-center gap-4 rounded-xl bg-accent px-8 py-8 text-center">
<Target size={48} color="#5A1A1A" />
<p className="font-serif text-3xl font-semibold">
Our Mission
</p>
<p className="text-center">
To meticulously craft exquisite carpets that
enrich lives and spaces, preserving artisanal
heritage while inspiring contemporary design.
</p>
</div>{' '}
<div className="flex flex-col items-center gap-4 rounded-xl bg-accent px-8 py-8 text-center">
<HeartHandshake size={48} color="#5A1A1A" />
<p className="font-serif text-3xl font-semibold">
Our Promise
</p>
<p className="text-center">
We promise exceptional artistry, ethical
sourcing, and personalized service, ensuring
every Kaleen carpet is a timeless masterpiece.
</p>
</div>
</div>
</section>
<section className="mx-auto flex max-w-screen-2xl flex-col gap-8 px-12 py-12">
<h4 className="text-center font-serif text-5xl leading-tight font-medium tracking-tight max-sm:text-4xl">
Our Commitment to Quality & Ethics
</h4>
<div className="flex items-center justify-center gap-8">
<img src={ns} alt="NS Standard" />
<img src={oko} alt="OKO Standard" />
</div>
</section>
</Layout>
</>
);
}

190
resources/js/pages/art.tsx Normal file
View File

@@ -0,0 +1,190 @@
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
import Layout from '@/layouts/client/layout';
import artOfWeaving from '@asset/img/art/IMG_4715.jpg';
import skill from '@asset/img/material/silk balls.jpg';
import skillYarn from '@asset/img/material/silk yarn.jpg';
import woolBall from '@asset/img/material/wool balls.jpg';
import woolYarn from '@asset/img/material/wool yarn.jpg';
import { Head } from '@inertiajs/react';
import { Flower, Hand, Package, Palette, Shirt } from 'lucide-react';
export default function Art() {
return (
<>
<Layout>
<Head title="Art of Weaving" />
<section>
<div className="relative">
<div className="absolute h-full w-full bg-white/70"></div>
<img
src={artOfWeaving}
alt="Art of Weaving"
className="aspect-[16/4] object-cover object-top"
/>
<h1 className="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 font-serif text-7xl font-medium tracking-tight">
The Art of Weaving
</h1>
</div>
<div className="mx-auto flex max-w-screen-2xl flex-col gap-12 px-12 py-12">
<h2 className="text-center font-serif text-4xl font-medium">
Our Craft: From Fiber to Fine Rug
</h2>
<Tabs
defaultValue="wool"
className="grid grid-cols-4 gap-8"
>
<TabsList className="!h-auto w-full flex-col">
<TabsTrigger
value="wool"
className="flex w-full gap-2 py-4"
>
<Shirt size={24} /> Wool Selection & Sorting
</TabsTrigger>
<TabsTrigger
value="dyeing"
className="w-full py-4"
>
<Palette /> Artisan Dyeing
</TabsTrigger>
<TabsTrigger
value="hand"
className="w-full py-4"
>
<Hand /> Hand Weaving
</TabsTrigger>
<TabsTrigger
value="finish"
className="w-full py-4"
>
<Flower /> Finishing & Washing
</TabsTrigger>
<TabsTrigger
value="quality"
className="w-full py-4"
>
<Package /> Quality Control & Packing
</TabsTrigger>
</TabsList>
<div className="col-span-3">
<TabsContent value="wool">
<div className="flex flex-col gap-2">
<p className="font-serif text-2xl font-medium">
Wool Selection & Sorting
</p>
<p>
Careful selection of the finest wool
fibers, meticulously sorted by
quality and texture to ensure only
the best make it into our carpets.
</p>
</div>
</TabsContent>
<TabsContent value="dyeing">
<div className="flex flex-col gap-2">
<p className="font-serif text-2xl font-medium">
Artisan Dyeing
</p>
<p>
Fibers are dyed using traditional
methods and natural pigments,
achieving rich, vibrant, and
enduring colors that tell a story.
</p>
</div>
</TabsContent>
<TabsContent value="hand">
<div className="flex flex-col gap-2">
<p className="font-serif text-2xl font-medium">
Hand Weaving
</p>
<p>
Skilled artisans hand-weave each
knot with precision and passion,
creating intricate patterns and
unparalleled durability.
</p>
</div>
</TabsContent>
<TabsContent value="finish">
<div className="flex flex-col gap-2">
<p className="font-serif text-2xl font-medium">
Finishing & Washing
</p>
<p>
Carpets undergo specialized washing,
shearing, and meticulous
hand-finishing to enhance their
luster and softness.
</p>
</div>
</TabsContent>
<TabsContent value="quality">
<div className="flex flex-col gap-2">
<p className="font-serif text-2xl font-medium">
Quality Control & Packing
</p>
<p>
Each rug passes rigorous quality
checks before being carefully packed
for its journey to your home,
ensuring perfection.
</p>
</div>
</TabsContent>
</div>
</Tabs>
</div>
<div className="mx-auto flex max-w-screen-2xl flex-col gap-12 px-12 py-8">
<h3 className="text-center font-serif text-4xl font-medium">
Exquisite Materials
</h3>
<div className="grid grid-cols-4 gap-6">
<div className="flex flex-col items-center gap-2">
<img
src={skill}
alt="Skill ball"
className="aspect-square rounded-lg object-cover object-center"
/>
<p className="font-serif text-lg font-medium">
Skill Ball
</p>
</div>
<div className="flex flex-col items-center gap-2">
<img
src={skillYarn}
alt="Skill yarn"
className="aspect-square rounded-lg object-cover object-center"
/>
<p className="font-serif text-lg font-medium">
Skill Yarn
</p>
</div>
<div className="flex flex-col items-center gap-2">
<img
src={woolBall}
alt="wool ball"
className="aspect-square rounded-lg object-cover object-center"
/>
<p className="font-serif text-lg font-medium">
Wool Ball
</p>
</div>
<div className="flex flex-col items-center gap-2">
<img
src={woolYarn}
alt="wool yarn"
className="aspect-square rounded-lg object-cover object-center"
/>
<p className="font-serif text-lg font-medium">
Wool Yarn
</p>
</div>
</div>
</div>
</section>
</Layout>
</>
);
}

View File

@@ -0,0 +1,52 @@
import InputError from '@/components/input-error';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import AuthLayout from '@/layouts/auth-layout';
import { store } from '@/routes/password/confirm';
import { Form, Head } from '@inertiajs/react';
import { LoaderCircle } from 'lucide-react';
export default function ConfirmPassword() {
return (
<AuthLayout
title="Confirm your password"
description="This is a secure area of the application. Please confirm your password before continuing."
>
<Head title="Confirm password" />
<Form {...store.form()} resetOnSuccess={['password']}>
{({ processing, errors }) => (
<div className="space-y-6">
<div className="grid gap-2">
<Label htmlFor="password">Password</Label>
<Input
id="password"
type="password"
name="password"
placeholder="Password"
autoComplete="current-password"
autoFocus
/>
<InputError message={errors.password} />
</div>
<div className="flex items-center">
<Button
className="w-full"
disabled={processing}
data-test="confirm-password-button"
>
{processing && (
<LoaderCircle className="h-4 w-4 animate-spin" />
)}
Confirm password
</Button>
</div>
</div>
)}
</Form>
</AuthLayout>
);
}

View File

@@ -0,0 +1,69 @@
// Components
import PasswordResetLinkController from '@/actions/App/Http/Controllers/Auth/PasswordResetLinkController';
import { login } from '@/routes';
import { Form, Head } from '@inertiajs/react';
import { LoaderCircle } from 'lucide-react';
import InputError from '@/components/input-error';
import TextLink from '@/components/text-link';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import AuthLayout from '@/layouts/auth-layout';
export default function ForgotPassword({ status }: { status?: string }) {
return (
<AuthLayout
title="Forgot password"
description="Enter your email to receive a password reset link"
>
<Head title="Forgot password" />
{status && (
<div className="mb-4 text-center text-sm font-medium text-green-600">
{status}
</div>
)}
<div className="space-y-6">
<Form {...PasswordResetLinkController.store.form()}>
{({ processing, errors }) => (
<>
<div className="grid gap-2">
<Label htmlFor="email">Email address</Label>
<Input
id="email"
type="email"
name="email"
autoComplete="off"
autoFocus
placeholder="email@example.com"
/>
<InputError message={errors.email} />
</div>
<div className="my-6 flex items-center justify-start">
<Button
className="w-full"
disabled={processing}
data-test="email-password-reset-link-button"
>
{processing && (
<LoaderCircle className="h-4 w-4 animate-spin" />
)}
Email password reset link
</Button>
</div>
</>
)}
</Form>
<div className="space-x-1 text-center text-sm text-muted-foreground">
<span>Or, return to</span>
<TextLink href={login()}>log in</TextLink>
</div>
</div>
</AuthLayout>
);
}

View File

@@ -0,0 +1,115 @@
import AuthenticatedSessionController from '@/actions/App/Http/Controllers/Auth/AuthenticatedSessionController';
import InputError from '@/components/input-error';
import TextLink from '@/components/text-link';
import { Button } from '@/components/ui/button';
import { Checkbox } from '@/components/ui/checkbox';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import AuthLayout from '@/layouts/auth-layout';
import { register } from '@/routes';
import { request } from '@/routes/password';
import { Form, Head } from '@inertiajs/react';
import { LoaderCircle } from 'lucide-react';
interface LoginProps {
status?: string;
canResetPassword: boolean;
}
export default function Login({ status, canResetPassword }: LoginProps) {
return (
<AuthLayout
title="Log in to your account"
description="Enter your email and password below to log in"
>
<Head title="Log in" />
<Form
{...AuthenticatedSessionController.store.form()}
resetOnSuccess={['password']}
className="flex flex-col gap-6"
>
{({ processing, errors }) => (
<>
<div className="grid gap-6">
<div className="grid gap-2">
<Label htmlFor="email">Email address</Label>
<Input
id="email"
type="email"
name="email"
required
autoFocus
tabIndex={1}
autoComplete="email"
placeholder="email@example.com"
/>
<InputError message={errors.email} />
</div>
<div className="grid gap-2">
<div className="flex items-center">
<Label htmlFor="password">Password</Label>
{canResetPassword && (
<TextLink
href={request()}
className="ml-auto text-sm"
tabIndex={5}
>
Forgot password?
</TextLink>
)}
</div>
<Input
id="password"
type="password"
name="password"
required
tabIndex={2}
autoComplete="current-password"
placeholder="Password"
/>
<InputError message={errors.password} />
</div>
<div className="flex items-center space-x-3">
<Checkbox
id="remember"
name="remember"
tabIndex={3}
/>
<Label htmlFor="remember">Remember me</Label>
</div>
<Button
type="submit"
className="mt-4 w-full"
tabIndex={4}
disabled={processing}
data-test="login-button"
>
{processing && (
<LoaderCircle className="h-4 w-4 animate-spin" />
)}
Log in
</Button>
</div>
<div className="text-center text-sm text-muted-foreground">
Don't have an account?{' '}
<TextLink href={register()} tabIndex={5}>
Sign up
</TextLink>
</div>
</>
)}
</Form>
{status && (
<div className="mb-4 text-center text-sm font-medium text-green-600">
{status}
</div>
)}
</AuthLayout>
);
}

View File

@@ -0,0 +1,117 @@
import RegisteredUserController from '@/actions/App/Http/Controllers/Auth/RegisteredUserController';
import { login } from '@/routes';
import { Form, Head } from '@inertiajs/react';
import { LoaderCircle } from 'lucide-react';
import InputError from '@/components/input-error';
import TextLink from '@/components/text-link';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import AuthLayout from '@/layouts/auth-layout';
export default function Register() {
return (
<AuthLayout
title="Create an account"
description="Enter your details below to create your account"
>
<Head title="Register" />
<Form
{...RegisteredUserController.store.form()}
resetOnSuccess={['password', 'password_confirmation']}
disableWhileProcessing
className="flex flex-col gap-6"
>
{({ processing, errors }) => (
<>
<div className="grid gap-6">
<div className="grid gap-2">
<Label htmlFor="name">Name</Label>
<Input
id="name"
type="text"
required
autoFocus
tabIndex={1}
autoComplete="name"
name="name"
placeholder="Full name"
/>
<InputError
message={errors.name}
className="mt-2"
/>
</div>
<div className="grid gap-2">
<Label htmlFor="email">Email address</Label>
<Input
id="email"
type="email"
required
tabIndex={2}
autoComplete="email"
name="email"
placeholder="email@example.com"
/>
<InputError message={errors.email} />
</div>
<div className="grid gap-2">
<Label htmlFor="password">Password</Label>
<Input
id="password"
type="password"
required
tabIndex={3}
autoComplete="new-password"
name="password"
placeholder="Password"
/>
<InputError message={errors.password} />
</div>
<div className="grid gap-2">
<Label htmlFor="password_confirmation">
Confirm password
</Label>
<Input
id="password_confirmation"
type="password"
required
tabIndex={4}
autoComplete="new-password"
name="password_confirmation"
placeholder="Confirm password"
/>
<InputError
message={errors.password_confirmation}
/>
</div>
<Button
type="submit"
className="mt-2 w-full"
tabIndex={5}
data-test="register-user-button"
>
{processing && (
<LoaderCircle className="h-4 w-4 animate-spin" />
)}
Create account
</Button>
</div>
<div className="text-center text-sm text-muted-foreground">
Already have an account?{' '}
<TextLink href={login()} tabIndex={6}>
Log in
</TextLink>
</div>
</>
)}
</Form>
</AuthLayout>
);
}

View File

@@ -0,0 +1,96 @@
import NewPasswordController from '@/actions/App/Http/Controllers/Auth/NewPasswordController';
import { Form, Head } from '@inertiajs/react';
import { LoaderCircle } from 'lucide-react';
import InputError from '@/components/input-error';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import AuthLayout from '@/layouts/auth-layout';
interface ResetPasswordProps {
token: string;
email: string;
}
export default function ResetPassword({ token, email }: ResetPasswordProps) {
return (
<AuthLayout
title="Reset password"
description="Please enter your new password below"
>
<Head title="Reset password" />
<Form
{...NewPasswordController.store.form()}
transform={(data) => ({ ...data, token, email })}
resetOnSuccess={['password', 'password_confirmation']}
>
{({ processing, errors }) => (
<div className="grid gap-6">
<div className="grid gap-2">
<Label htmlFor="email">Email</Label>
<Input
id="email"
type="email"
name="email"
autoComplete="email"
value={email}
className="mt-1 block w-full"
readOnly
/>
<InputError
message={errors.email}
className="mt-2"
/>
</div>
<div className="grid gap-2">
<Label htmlFor="password">Password</Label>
<Input
id="password"
type="password"
name="password"
autoComplete="new-password"
className="mt-1 block w-full"
autoFocus
placeholder="Password"
/>
<InputError message={errors.password} />
</div>
<div className="grid gap-2">
<Label htmlFor="password_confirmation">
Confirm password
</Label>
<Input
id="password_confirmation"
type="password"
name="password_confirmation"
autoComplete="new-password"
className="mt-1 block w-full"
placeholder="Confirm password"
/>
<InputError
message={errors.password_confirmation}
className="mt-2"
/>
</div>
<Button
type="submit"
className="mt-4 w-full"
disabled={processing}
data-test="reset-password-button"
>
{processing && (
<LoaderCircle className="h-4 w-4 animate-spin" />
)}
Reset password
</Button>
</div>
)}
</Form>
</AuthLayout>
);
}

View File

@@ -0,0 +1,131 @@
import InputError from '@/components/input-error';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import {
InputOTP,
InputOTPGroup,
InputOTPSlot,
} from '@/components/ui/input-otp';
import { OTP_MAX_LENGTH } from '@/hooks/use-two-factor-auth';
import AuthLayout from '@/layouts/auth-layout';
import { store } from '@/routes/two-factor/login';
import { Form, Head } from '@inertiajs/react';
import { REGEXP_ONLY_DIGITS } from 'input-otp';
import { useMemo, useState } from 'react';
export default function TwoFactorChallenge() {
const [showRecoveryInput, setShowRecoveryInput] = useState<boolean>(false);
const [code, setCode] = useState<string>('');
const authConfigContent = useMemo<{
title: string;
description: string;
toggleText: string;
}>(() => {
if (showRecoveryInput) {
return {
title: 'Recovery Code',
description:
'Please confirm access to your account by entering one of your emergency recovery codes.',
toggleText: 'login using an authentication code',
};
}
return {
title: 'Authentication Code',
description:
'Enter the authentication code provided by your authenticator application.',
toggleText: 'login using a recovery code',
};
}, [showRecoveryInput]);
const toggleRecoveryMode = (clearErrors: () => void): void => {
setShowRecoveryInput(!showRecoveryInput);
clearErrors();
setCode('');
};
return (
<AuthLayout
title={authConfigContent.title}
description={authConfigContent.description}
>
<Head title="Two-Factor Authentication" />
<div className="space-y-6">
<Form
{...store.form()}
className="space-y-4"
resetOnError
resetOnSuccess={!showRecoveryInput}
>
{({ errors, processing, clearErrors }) => (
<>
{showRecoveryInput ? (
<>
<Input
name="recovery_code"
type="text"
placeholder="Enter recovery code"
autoFocus={showRecoveryInput}
required
/>
<InputError
message={errors.recovery_code}
/>
</>
) : (
<div className="flex flex-col items-center justify-center space-y-3 text-center">
<div className="flex w-full items-center justify-center">
<InputOTP
name="code"
maxLength={OTP_MAX_LENGTH}
value={code}
onChange={(value) => setCode(value)}
disabled={processing}
pattern={REGEXP_ONLY_DIGITS}
>
<InputOTPGroup>
{Array.from(
{ length: OTP_MAX_LENGTH },
(_, index) => (
<InputOTPSlot
key={index}
index={index}
/>
),
)}
</InputOTPGroup>
</InputOTP>
</div>
<InputError message={errors.code} />
</div>
)}
<Button
type="submit"
className="w-full"
disabled={processing}
>
Continue
</Button>
<div className="text-center text-sm text-muted-foreground">
<span>or you can </span>
<button
type="button"
className="cursor-pointer text-foreground underline decoration-neutral-300 underline-offset-4 transition-colors duration-300 ease-out hover:decoration-current! dark:decoration-neutral-500"
onClick={() =>
toggleRecoveryMode(clearErrors)
}
>
{authConfigContent.toggleText}
</button>
</div>
</>
)}
</Form>
</div>
</AuthLayout>
);
}

View File

@@ -0,0 +1,50 @@
// Components
import EmailVerificationNotificationController from '@/actions/App/Http/Controllers/Auth/EmailVerificationNotificationController';
import { logout } from '@/routes';
import { Form, Head } from '@inertiajs/react';
import { LoaderCircle } from 'lucide-react';
import TextLink from '@/components/text-link';
import { Button } from '@/components/ui/button';
import AuthLayout from '@/layouts/auth-layout';
export default function VerifyEmail({ status }: { status?: string }) {
return (
<AuthLayout
title="Verify email"
description="Please verify your email address by clicking on the link we just emailed to you."
>
<Head title="Email verification" />
{status === 'verification-link-sent' && (
<div className="mb-4 text-center text-sm font-medium text-green-600">
A new verification link has been sent to the email address
you provided during registration.
</div>
)}
<Form
{...EmailVerificationNotificationController.store.form()}
className="space-y-6 text-center"
>
{({ processing }) => (
<>
<Button disabled={processing} variant="secondary">
{processing && (
<LoaderCircle className="h-4 w-4 animate-spin" />
)}
Resend verification email
</Button>
<TextLink
href={logout()}
className="mx-auto block text-sm"
>
Log out
</TextLink>
</>
)}
</Form>
</AuthLayout>
);
}

View File

@@ -0,0 +1,186 @@
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from '@/components/ui/select';
import { Textarea } from '@/components/ui/textarea';
import Layout from '@/layouts/client/layout';
import { Form, Head } from '@inertiajs/react';
import { Mail, MapPin, Phone } from 'lucide-react';
export default function Contact() {
return (
<>
<Layout>
<Head title="Contact Us" />
<section className="mx-auto flex max-w-screen-2xl flex-col gap-12 px-12 py-12 max-md:px-8">
<div className="flex flex-col gap-4">
<h1 className="text-center font-serif text-5xl font-medium tracking-tight max-md:text-3xl">
Connect with Kaleen Carpets
</h1>
<p className="text-center text-sm">
We are here to assist you with any inquiries,
bespoke design requests, or partnership
opportunities. <br /> Reach out to our team through
our offices or the contact form below.
</p>
</div>
<div className="flex flex-col gap-8">
<h2 className="text-center font-serif text-3xl font-medium tracking-tight">
Our Global Offices
</h2>
<div className="flex items-start justify-center gap-24 max-md:flex-col max-md:gap-12">
<div className="flex flex-col gap-6">
<div className="flex flex-col gap-1">
<p className="font-serif text-xl font-medium tracking-tight">
Soorya Carpet Industries
</p>
<p className="text-sm text-gray-500">
Our global presence to serve you better.
</p>
</div>
<ul className="flex flex-col gap-2">
<li className="flex items-center gap-2 text-sm">
<MapPin size={16} /> G.P.O Box 1765 2
Swet Binayak Marg Thapathali -11,
Kathmandu, Nepal
</li>{' '}
<li className="flex items-center gap-2 text-sm">
<Phone size={16} /> [+977-1] 4780923,
4783003
</li>{' '}
<li className="flex items-center gap-2 text-sm">
<Mail size={16} />{' '}
sooryacarpets@gmail.com
</li>
</ul>
</div>
<div className="flex flex-col gap-6">
<div className="flex flex-col gap-1">
<p className="font-serif text-xl font-medium tracking-tight">
Kaleen Studio
</p>
<p className="text-sm text-gray-500">
Our global presence to serve you better.
</p>
</div>
<ul className="flex flex-col gap-2">
<li className="flex items-center gap-2 text-sm">
<MapPin size={16} /> Kadel Chautari
Prasuti Griha Marg Ward No. 11,
Babarmahal Kathmandu, Nepal
</li>{' '}
<li className="flex items-center gap-2 text-sm">
<Phone size={16} /> 9802341880
</li>
</ul>
<a
href="https://maps.app.goo.gl/666dbJEfsVvjJ3fu9"
target="_blank"
className="cursor-pointer"
>
<Button
className="w-full cursor-pointer border border-primary text-primary ring-primary"
variant={'outline'}
>
Visit Studio
</Button>
</a>
</div>
</div>
</div>
<div className="mx-auto flex w-full max-w-3xl flex-col gap-8 py-12">
<div className="flex flex-col gap-1">
<h3 className="font-serif text-3xl font-medium">
Send us a Message
</h3>
<p className="text-sm text-gray-500">
Fill out the form below and we'll get back to
you as soon as possible.
</p>
</div>
<Form action={'/'} className="flex flex-col gap-2">
<div>
<Label htmlFor="name">Name</Label>
<Input
placeholder="Full Name"
id="name"
name="name"
/>
</div>
<div>
<Label htmlFor="email">Email</Label>
<Input
placeholder="your.email@example.com"
id="email"
name="email"
/>
</div>{' '}
<div>
<Label htmlFor="email">Email</Label>
<Select>
<SelectTrigger className="w-full">
<SelectValue placeholder="Select an inquiry type" />
</SelectTrigger>
<SelectContent>
<SelectItem value="problem">
Problem in product
</SelectItem>
<SelectItem value="contact">
Contacting
</SelectItem>
</SelectContent>
</Select>
</div>
<div>
<Label htmlFor="message">Message</Label>
<Textarea
id="message"
placeholder="Tell us how can we help you"
/>
</div>
<Button type="submit" className="my-4">
Send Message
</Button>
</Form>
</div>
<div className="flex flex-col items-center gap-8">
<div className="flex flex-col items-center gap-2">
<h4 className="text-center font-serif text-3xl font-medium tracking-tight">
Direct Engagement
</h4>
<p className="text-center text-sm text-gray-500">
Prefer to speak with us directly or send a quick
email? <br /> Our team is ready to assist.
</p>
</div>
<div className="flex items-center gap-4">
<a href="tel:9802341880">
<Button className="cursor-pointer">
<Phone /> Call Us Now
</Button>
</a>
<a href="mailto:info@soory.com">
<Button
variant={'outline'}
className="cursor-pointer border border-primary text-primary ring-primary"
>
<Mail /> Email Our Team
</Button>
</a>
</div>
</div>
</section>
</Layout>
</>
);
}

View File

@@ -0,0 +1,36 @@
import { PlaceholderPattern } from '@/components/ui/placeholder-pattern';
import AppLayout from '@/layouts/app-layout';
import { index } from '@/routes/dashboard';
import { type BreadcrumbItem } from '@/types';
import { Head } from '@inertiajs/react';
const breadcrumbs: BreadcrumbItem[] = [
{
title: 'Dashboard',
href: index().url,
},
];
export default function Dashboard() {
return (
<AppLayout breadcrumbs={breadcrumbs}>
<Head title="Dashboard" />
<div className="flex h-full flex-1 flex-col gap-4 overflow-x-auto rounded-xl p-4">
<div className="grid auto-rows-min gap-4 md:grid-cols-3">
<div className="relative aspect-video overflow-hidden rounded-xl border border-sidebar-border/70 dark:border-sidebar-border">
<PlaceholderPattern className="absolute inset-0 size-full stroke-neutral-900/20 dark:stroke-neutral-100/20" />
</div>
<div className="relative aspect-video overflow-hidden rounded-xl border border-sidebar-border/70 dark:border-sidebar-border">
<PlaceholderPattern className="absolute inset-0 size-full stroke-neutral-900/20 dark:stroke-neutral-100/20" />
</div>
<div className="relative aspect-video overflow-hidden rounded-xl border border-sidebar-border/70 dark:border-sidebar-border">
<PlaceholderPattern className="absolute inset-0 size-full stroke-neutral-900/20 dark:stroke-neutral-100/20" />
</div>
</div>
<div className="relative min-h-[100vh] flex-1 overflow-hidden rounded-xl border border-sidebar-border/70 md:min-h-min dark:border-sidebar-border">
<PlaceholderPattern className="absolute inset-0 size-full stroke-neutral-900/20 dark:stroke-neutral-100/20" />
</div>
</div>
</AppLayout>
);
}

View File

@@ -0,0 +1,94 @@
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import AppLayout from '@/layouts/app-layout';
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 { useState } from 'react';
import { FilePond, registerPlugin } from 'react-filepond';
import { toast } from 'sonner';
registerPlugin(FilePondPluginImageExifOrientation, FilePondPluginImagePreview);
export default function CarouselAdd() {
const [file, setFile] = useState<any | null>(null);
const { data, setData, post, processing, errors, wasSuccessful } = useForm({
alt: '',
image_url: null as File | null,
});
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
if (file) {
setData('image_url', file.file);
}
post('/carousel', {
forceFormData: true,
});
if (wasSuccessful) {
toast.success('Slider image successfully uploaded');
}
};
return (
<AppLayout>
<Head title="Add Carousel" />
<section className="flex flex-col gap-8 px-8 py-8">
<h1 className="text-lg font-semibold tracking-tight">
Add Slider Image
</h1>
<form
onSubmit={handleSubmit}
method="POST"
encType="multipart/formdata"
>
<div className="flex flex-col gap-4">
<Label htmlFor="title">Title</Label>
<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 className="mt-4">
<Label>Image</Label>
<FilePond
files={file ? [file] : []}
onupdatefiles={(fileItems) => {
setFile(fileItems[0] || null);
}}
allowMultiple={false}
maxFiles={1}
name="image_url" // Change this to match your backend expectation
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}>
{processing ? 'Uploading...' : 'Submit'}
</Button>
</form>
</section>
</AppLayout>
);
}

View File

@@ -0,0 +1,83 @@
import { Button } from '@/components/ui/button';
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from '@/components/ui/table';
import AppLayout from '@/layouts/app-layout';
import dashboardcarousel from '@/routes/dashboard/carousel';
import { Head, Link } from '@inertiajs/react';
import { Pencil, Trash2 } from 'lucide-react';
export default function Carousel({
carousel,
}: {
carousel: [{ alt: string; image_url: string }];
}) {
return (
<>
<AppLayout
breadcrumbs={[
{ title: 'Carousel', href: dashboardcarousel.index().url },
]}
>
<Head title="Carousel"></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">
Carousel
</h1>
<Link href={dashboardcarousel.add()}>
<Button>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="text-right">
Action
</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{carousel.map((item, index) => (
<TableRow key={index}>
<TableCell className="font-medium">
{index + 1}
</TableCell>
<TableCell>
<img
src={item.image_url}
alt={item.alt}
className="aspect-video w-24 rounded-md object-cover object-center"
/>
</TableCell>
<TableCell>{item.alt}</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

@@ -0,0 +1,17 @@
import AppLayout from '@/layouts/app-layout';
import testimonial from '@/routes/testimonial';
import { Head } from '@inertiajs/react';
export default function Testimonial() {
return (
<>
<AppLayout
breadcrumbs={[
{ title: 'testimonial', href: testimonial.index().url },
]}
>
<Head title={'Testimonials'}></Head>
</AppLayout>
</>
);
}

View File

@@ -0,0 +1,83 @@
import {
Accordion,
AccordionContent,
AccordionItem,
AccordionTrigger,
} from '@/components/ui/accordion';
import { Button } from '@/components/ui/button';
import Layout from '@/layouts/client/layout';
import { contact } from '@/routes';
import { Head, Link } from '@inertiajs/react';
export default function Faq() {
return (
<>
<Layout>
<Head title="FAQs" />
<section className="mx-auto flex max-w-screen-2xl gap-32 px-12 py-8">
<div className="flex flex-col gap-4">
<div>
<h1 className="font-serif text-4xl font-medium tracking-tight">
Frequently Asked Questions
</h1>
<p>Any question, answered right here</p>
</div>
<Link href={contact()}>
<Button
className="cursor-pointer border border-primary font-serif ring-primary"
variant={'outline'}
>
Contact Now
</Button>
</Link>
</div>
<div className="w-full">
<Accordion
type="single"
collapsible
className="w-full"
defaultValue="item-1"
>
<AccordionItem value="item-1">
<AccordionTrigger className="w-full">
Is it accessible?
</AccordionTrigger>
<AccordionContent>
Yes. It adheres to the WAI-ARIA design
pattern.
</AccordionContent>
</AccordionItem>{' '}
<AccordionItem value="item-2">
<AccordionTrigger className="w-full">
Is it accessible?
</AccordionTrigger>
<AccordionContent>
Yes. It adheres to the WAI-ARIA design
pattern.
</AccordionContent>
</AccordionItem>{' '}
<AccordionItem value="item-3">
<AccordionTrigger className="w-full">
Is it accessible?
</AccordionTrigger>
<AccordionContent>
Yes. It adheres to the WAI-ARIA design
pattern.
</AccordionContent>
</AccordionItem>{' '}
<AccordionItem value="item-4">
<AccordionTrigger className="w-full">
Is it accessible?
</AccordionTrigger>
<AccordionContent>
Yes. It adheres to the WAI-ARIA design
pattern.
</AccordionContent>
</AccordionItem>
</Accordion>
</div>
</section>
</Layout>
</>
);
}

View File

@@ -0,0 +1,30 @@
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
import Layout from '@/layouts/client/layout';
import { Head } from '@inertiajs/react';
export default function Product() {
return (
<>
<Layout>
<Head title="Our Products" />
<section className="mx-auto flex max-w-screen-2xl flex-col gap-8 px-12 py-8">
<h1 className="font-serif text-5xl font-medium tracking-tight">
Our Exquisite Collections
</h1>
<Tabs defaultValue="account" className="w-[400px]">
<TabsList>
<TabsTrigger value="account">Account</TabsTrigger>
<TabsTrigger value="password">Password</TabsTrigger>
</TabsList>
<TabsContent value="account">
Make changes to your account here.
</TabsContent>
<TabsContent value="password">
Change your password here.
</TabsContent>
</Tabs>
</section>
</Layout>
</>
);
}

View File

@@ -0,0 +1,34 @@
import { Head } from '@inertiajs/react';
import AppearanceTabs from '@/components/appearance-tabs';
import HeadingSmall from '@/components/heading-small';
import { type BreadcrumbItem } from '@/types';
import AppLayout from '@/layouts/app-layout';
import SettingsLayout from '@/layouts/settings/layout';
import { edit as editAppearance } from '@/routes/appearance';
const breadcrumbs: BreadcrumbItem[] = [
{
title: 'Appearance settings',
href: editAppearance().url,
},
];
export default function Appearance() {
return (
<AppLayout breadcrumbs={breadcrumbs}>
<Head title="Appearance settings" />
<SettingsLayout>
<div className="space-y-6">
<HeadingSmall
title="Appearance settings"
description="Update your account's appearance settings"
/>
<AppearanceTabs />
</div>
</SettingsLayout>
</AppLayout>
);
}

View File

@@ -0,0 +1,146 @@
import PasswordController from '@/actions/App/Http/Controllers/Settings/PasswordController';
import InputError from '@/components/input-error';
import AppLayout from '@/layouts/app-layout';
import SettingsLayout from '@/layouts/settings/layout';
import { type BreadcrumbItem } from '@/types';
import { Transition } from '@headlessui/react';
import { Form, Head } from '@inertiajs/react';
import { useRef } from 'react';
import HeadingSmall from '@/components/heading-small';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import { edit } from '@/routes/password';
const breadcrumbs: BreadcrumbItem[] = [
{
title: 'Password settings',
href: edit().url,
},
];
export default function Password() {
const passwordInput = useRef<HTMLInputElement>(null);
const currentPasswordInput = useRef<HTMLInputElement>(null);
return (
<AppLayout breadcrumbs={breadcrumbs}>
<Head title="Password settings" />
<SettingsLayout>
<div className="space-y-6">
<HeadingSmall
title="Update password"
description="Ensure your account is using a long, random password to stay secure"
/>
<Form
{...PasswordController.update.form()}
options={{
preserveScroll: true,
}}
resetOnError={[
'password',
'password_confirmation',
'current_password',
]}
resetOnSuccess
onError={(errors) => {
if (errors.password) {
passwordInput.current?.focus();
}
if (errors.current_password) {
currentPasswordInput.current?.focus();
}
}}
className="space-y-6"
>
{({ errors, processing, recentlySuccessful }) => (
<>
<div className="grid gap-2">
<Label htmlFor="current_password">
Current password
</Label>
<Input
id="current_password"
ref={currentPasswordInput}
name="current_password"
type="password"
className="mt-1 block w-full"
autoComplete="current-password"
placeholder="Current password"
/>
<InputError
message={errors.current_password}
/>
</div>
<div className="grid gap-2">
<Label htmlFor="password">
New password
</Label>
<Input
id="password"
ref={passwordInput}
name="password"
type="password"
className="mt-1 block w-full"
autoComplete="new-password"
placeholder="New password"
/>
<InputError message={errors.password} />
</div>
<div className="grid gap-2">
<Label htmlFor="password_confirmation">
Confirm password
</Label>
<Input
id="password_confirmation"
name="password_confirmation"
type="password"
className="mt-1 block w-full"
autoComplete="new-password"
placeholder="Confirm password"
/>
<InputError
message={errors.password_confirmation}
/>
</div>
<div className="flex items-center gap-4">
<Button
disabled={processing}
data-test="update-password-button"
>
Save password
</Button>
<Transition
show={recentlySuccessful}
enter="transition ease-in-out"
enterFrom="opacity-0"
leave="transition ease-in-out"
leaveTo="opacity-0"
>
<p className="text-sm text-neutral-600">
Saved
</p>
</Transition>
</div>
</>
)}
</Form>
</div>
</SettingsLayout>
</AppLayout>
);
}

View File

@@ -0,0 +1,148 @@
import ProfileController from '@/actions/App/Http/Controllers/Settings/ProfileController';
import { send } from '@/routes/verification';
import { type BreadcrumbItem, type SharedData } from '@/types';
import { Transition } from '@headlessui/react';
import { Form, Head, Link, usePage } from '@inertiajs/react';
import DeleteUser from '@/components/delete-user';
import HeadingSmall from '@/components/heading-small';
import InputError from '@/components/input-error';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import AppLayout from '@/layouts/app-layout';
import SettingsLayout from '@/layouts/settings/layout';
import { edit } from '@/routes/profile';
const breadcrumbs: BreadcrumbItem[] = [
{
title: 'Profile settings',
href: edit().url,
},
];
export default function Profile({
mustVerifyEmail,
status,
}: {
mustVerifyEmail: boolean;
status?: string;
}) {
const { auth } = usePage<SharedData>().props;
return (
<AppLayout breadcrumbs={breadcrumbs}>
<Head title="Profile settings" />
<SettingsLayout>
<div className="space-y-6">
<HeadingSmall
title="Profile information"
description="Update your name and email address"
/>
<Form
{...ProfileController.update.form()}
options={{
preserveScroll: true,
}}
className="space-y-6"
>
{({ processing, recentlySuccessful, errors }) => (
<>
<div className="grid gap-2">
<Label htmlFor="name">Name</Label>
<Input
id="name"
className="mt-1 block w-full"
defaultValue={auth.user.name}
name="name"
required
autoComplete="name"
placeholder="Full name"
/>
<InputError
className="mt-2"
message={errors.name}
/>
</div>
<div className="grid gap-2">
<Label htmlFor="email">Email address</Label>
<Input
id="email"
type="email"
className="mt-1 block w-full"
defaultValue={auth.user.email}
name="email"
required
autoComplete="username"
placeholder="Email address"
/>
<InputError
className="mt-2"
message={errors.email}
/>
</div>
{mustVerifyEmail &&
auth.user.email_verified_at === null && (
<div>
<p className="-mt-4 text-sm text-muted-foreground">
Your email address is
unverified.{' '}
<Link
href={send()}
as="button"
className="text-foreground underline decoration-neutral-300 underline-offset-4 transition-colors duration-300 ease-out hover:decoration-current! dark:decoration-neutral-500"
>
Click here to resend the
verification email.
</Link>
</p>
{status ===
'verification-link-sent' && (
<div className="mt-2 text-sm font-medium text-green-600">
A new verification link has
been sent to your email
address.
</div>
)}
</div>
)}
<div className="flex items-center gap-4">
<Button
disabled={processing}
data-test="update-profile-button"
>
Save
</Button>
<Transition
show={recentlySuccessful}
enter="transition ease-in-out"
enterFrom="opacity-0"
leave="transition ease-in-out"
leaveTo="opacity-0"
>
<p className="text-sm text-neutral-600">
Saved
</p>
</Transition>
</div>
</>
)}
</Form>
</div>
<DeleteUser />
</SettingsLayout>
</AppLayout>
);
}

View File

@@ -0,0 +1,137 @@
import HeadingSmall from '@/components/heading-small';
import TwoFactorRecoveryCodes from '@/components/two-factor-recovery-codes';
import TwoFactorSetupModal from '@/components/two-factor-setup-modal';
import { Badge } from '@/components/ui/badge';
import { Button } from '@/components/ui/button';
import { useTwoFactorAuth } from '@/hooks/use-two-factor-auth';
import AppLayout from '@/layouts/app-layout';
import SettingsLayout from '@/layouts/settings/layout';
import { disable, enable, show } from '@/routes/two-factor';
import { type BreadcrumbItem } from '@/types';
import { Form, Head } from '@inertiajs/react';
import { ShieldBan, ShieldCheck } from 'lucide-react';
import { useState } from 'react';
interface TwoFactorProps {
requiresConfirmation?: boolean;
twoFactorEnabled?: boolean;
}
const breadcrumbs: BreadcrumbItem[] = [
{
title: 'Two-Factor Authentication',
href: show.url(),
},
];
export default function TwoFactor({
requiresConfirmation = false,
twoFactorEnabled = false,
}: TwoFactorProps) {
const {
qrCodeSvg,
hasSetupData,
manualSetupKey,
clearSetupData,
fetchSetupData,
recoveryCodesList,
fetchRecoveryCodes,
errors,
} = useTwoFactorAuth();
const [showSetupModal, setShowSetupModal] = useState<boolean>(false);
return (
<AppLayout breadcrumbs={breadcrumbs}>
<Head title="Two-Factor Authentication" />
<SettingsLayout>
<div className="space-y-6">
<HeadingSmall
title="Two-Factor Authentication"
description="Manage your two-factor authentication settings"
/>
{twoFactorEnabled ? (
<div className="flex flex-col items-start justify-start space-y-4">
<Badge variant="default">Enabled</Badge>
<p className="text-muted-foreground">
With two-factor authentication enabled, you will
be prompted for a secure, random pin during
login, which you can retrieve from the
TOTP-supported application on your phone.
</p>
<TwoFactorRecoveryCodes
recoveryCodesList={recoveryCodesList}
fetchRecoveryCodes={fetchRecoveryCodes}
errors={errors}
/>
<div className="relative inline">
<Form {...disable.form()}>
{({ processing }) => (
<Button
variant="destructive"
type="submit"
disabled={processing}
>
<ShieldBan /> Disable 2FA
</Button>
)}
</Form>
</div>
</div>
) : (
<div className="flex flex-col items-start justify-start space-y-4">
<Badge variant="destructive">Disabled</Badge>
<p className="text-muted-foreground">
When you enable two-factor authentication, you
will be prompted for a secure pin during login.
This pin can be retrieved from a TOTP-supported
application on your phone.
</p>
<div>
{hasSetupData ? (
<Button
onClick={() => setShowSetupModal(true)}
>
<ShieldCheck />
Continue Setup
</Button>
) : (
<Form
{...enable.form()}
onSuccess={() =>
setShowSetupModal(true)
}
>
{({ processing }) => (
<Button
type="submit"
disabled={processing}
>
<ShieldCheck />
Enable 2FA
</Button>
)}
</Form>
)}
</div>
</div>
)}
<TwoFactorSetupModal
isOpen={showSetupModal}
onClose={() => setShowSetupModal(false)}
requiresConfirmation={requiresConfirmation}
twoFactorEnabled={twoFactorEnabled}
qrCodeSvg={qrCodeSvg}
manualSetupKey={manualSetupKey}
clearSetupData={clearSetupData}
fetchSetupData={fetchSetupData}
errors={errors}
/>
</div>
</SettingsLayout>
</AppLayout>
);
}

View File

@@ -0,0 +1,117 @@
import { Swiper, Testimonial } from '@/components/pages/Home';
import { Button } from '@/components/ui/button';
import Layout from '@/layouts/client/layout';
import { about } from '@/routes';
import artofWeaving from '@asset/img/carpet/IMG_1301.jpg';
import kaleenCarpet from '@asset/img/carpet/IMG_3401.jpg';
import sooryaCarpet from '@asset/img/carpet/sci trad 31.jpg';
import { Head, Link } from '@inertiajs/react';
import { MoveRight } from 'lucide-react';
export default function Welcome({
data,
}: {
data: { carousel: [{ image_url: string; alt: string }] };
}) {
return (
<>
<Head title="Premium Hand Knotted Carpets in Nepal">
<link rel="preconnect" href="https://fonts.bunny.net" />
<link
href="https://fonts.bunny.net/css?family=instrument-sans:400,500,600"
rel="stylesheet"
/>
<meta
name="description"
content="Experience the finest hand-knotted carpets in Nepal with Soorya Carpet. Each piece is crafted by skilled artisans to deliver unmatched quality, luxury, and timeless design."
/>
</Head>
<Layout>
<div>
<Swiper item={data?.carousel} />
<section className="mx-auto grid max-w-screen-2xl grid-cols-2 gap-20 px-16 py-12">
<img
src={sooryaCarpet}
alt="Soorya Carpet"
className="aspect-video rounded-lg object-cover object-center"
/>
<div className="flex flex-col gap-4">
<div className="flex flex-col gap-1">
<h2 className="font-serif text-3xl font-medium">
Soorya Carpet
</h2>
<p className="text-gray-500">
Discover the journey of Kaleen Carpets, a
testament to enduring craftsmanship,
innovative design, and a commitment to
enriching lives through beautiful artistry.
</p>
</div>
<Link href={about()}>
<Button
variant={'outline'}
className="w-fit cursor-pointer border border-primary bg-transparent font-serif ring-primary"
>
Learn More <MoveRight />
</Button>
</Link>
</div>
</section>
<section className="mx-auto grid max-w-screen-2xl grid-cols-2 gap-20 px-16 py-12">
<div className="flex flex-col gap-4">
<div className="flex flex-col gap-1">
<h3 className="font-serif text-3xl font-medium">
The Kaleen Rebrand
</h3>
<p className="text-gray-500">
In 2015, Kaleen embarked on a transformative
journey, evolving from a traditional
manufacturer to a dynamic, luxury lifestyle
brand.
</p>
</div>
<Button
variant={'outline'}
className="w-fit border border-primary bg-transparent font-serif ring-primary"
>
Learn More <MoveRight />
</Button>
</div>
<img
src={kaleenCarpet}
alt="Kaleen Carpet"
className="aspect-video rounded-lg object-cover object-center"
/>
</section>
<section className="mx-auto grid max-w-screen-2xl grid-cols-2 gap-20 px-16 py-12">
<img
src={artofWeaving}
alt="Art of Weaving"
className="aspect-video rounded-lg object-cover object-center"
/>
<div className="flex flex-col gap-4">
<div className="flex flex-col gap-1">
<h2 className="font-serif text-3xl font-medium">
Art of Weaving
</h2>
<p className="text-gray-500">
Since time immemorial, the art of carpet
making has captured millions of carpet
connoisseurs from around the world and still
continues to do so.
</p>
</div>
<Button
variant={'outline'}
className="w-fit border border-primary bg-transparent font-serif ring-primary"
>
Learn More <MoveRight />
</Button>
</div>
</section>
<Testimonial />
</div>
</Layout>
</>
);
}