Init(Core): add to repo and add seeders
This commit is contained in:
59
resources/js/Pages/Auth/ConfirmPassword.jsx
Normal file
59
resources/js/Pages/Auth/ConfirmPassword.jsx
Normal file
@@ -0,0 +1,59 @@
|
||||
import { useEffect } from 'react';
|
||||
import GuestLayout from '@/Layouts/GuestLayout';
|
||||
import InputError from '@/Components/InputError';
|
||||
import InputLabel from '@/Components/InputLabel';
|
||||
import PrimaryButton from '@/Components/PrimaryButton';
|
||||
import TextInput from '@/Components/TextInput';
|
||||
import { Head, useForm } from '@inertiajs/react';
|
||||
|
||||
export default function ConfirmPassword() {
|
||||
const { data, setData, post, processing, errors, reset } = useForm({
|
||||
password: '',
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
reset('password');
|
||||
};
|
||||
}, []);
|
||||
|
||||
const submit = (e) => {
|
||||
e.preventDefault();
|
||||
|
||||
post(route('password.confirm'));
|
||||
};
|
||||
|
||||
return (
|
||||
<GuestLayout>
|
||||
<Head title="Confirm Password" />
|
||||
|
||||
<div className="mb-4 text-sm text-gray-600">
|
||||
This is a secure area of the application. Please confirm your password before continuing.
|
||||
</div>
|
||||
|
||||
<form onSubmit={submit}>
|
||||
<div className="mt-4">
|
||||
<InputLabel htmlFor="password" value="Password" />
|
||||
|
||||
<TextInput
|
||||
id="password"
|
||||
type="password"
|
||||
name="password"
|
||||
value={data.password}
|
||||
className="mt-1 block w-full"
|
||||
isFocused={true}
|
||||
onChange={(e) => setData('password', e.target.value)}
|
||||
/>
|
||||
|
||||
<InputError message={errors.password} className="mt-2" />
|
||||
</div>
|
||||
|
||||
<div className="flex items-center justify-end mt-4">
|
||||
<PrimaryButton className="ml-4" disabled={processing}>
|
||||
Confirm
|
||||
</PrimaryButton>
|
||||
</div>
|
||||
</form>
|
||||
</GuestLayout>
|
||||
);
|
||||
}
|
||||
50
resources/js/Pages/Auth/ForgotPassword.jsx
Normal file
50
resources/js/Pages/Auth/ForgotPassword.jsx
Normal file
@@ -0,0 +1,50 @@
|
||||
import GuestLayout from '@/Layouts/GuestLayout';
|
||||
import InputError from '@/Components/InputError';
|
||||
import PrimaryButton from '@/Components/PrimaryButton';
|
||||
import TextInput from '@/Components/TextInput';
|
||||
import { Head, useForm } from '@inertiajs/react';
|
||||
|
||||
export default function ForgotPassword({ status }) {
|
||||
const { data, setData, post, processing, errors } = useForm({
|
||||
email: '',
|
||||
});
|
||||
|
||||
const submit = (e) => {
|
||||
e.preventDefault();
|
||||
|
||||
post(route('password.email'));
|
||||
};
|
||||
|
||||
return (
|
||||
<GuestLayout>
|
||||
<Head title="Forgot Password" />
|
||||
|
||||
<div className="mb-4 text-sm text-gray-600">
|
||||
Forgot your password? No problem. Just let us know your email address and we will email you a password
|
||||
reset link that will allow you to choose a new one.
|
||||
</div>
|
||||
|
||||
{status && <div className="mb-4 font-medium text-sm text-green-600">{status}</div>}
|
||||
|
||||
<form onSubmit={submit}>
|
||||
<TextInput
|
||||
id="email"
|
||||
type="email"
|
||||
name="email"
|
||||
value={data.email}
|
||||
className="mt-1 block w-full"
|
||||
isFocused={true}
|
||||
onChange={(e) => setData('email', e.target.value)}
|
||||
/>
|
||||
|
||||
<InputError message={errors.email} className="mt-2" />
|
||||
|
||||
<div className="flex items-center justify-end mt-4">
|
||||
<PrimaryButton className="ml-4" disabled={processing}>
|
||||
Email Password Reset Link
|
||||
</PrimaryButton>
|
||||
</div>
|
||||
</form>
|
||||
</GuestLayout>
|
||||
);
|
||||
}
|
||||
97
resources/js/Pages/Auth/Login.jsx
Normal file
97
resources/js/Pages/Auth/Login.jsx
Normal file
@@ -0,0 +1,97 @@
|
||||
import { useEffect } from 'react';
|
||||
import Checkbox from '@/Components/Checkbox';
|
||||
import GuestLayout from '@/Layouts/GuestLayout';
|
||||
import InputError from '@/Components/InputError';
|
||||
import InputLabel from '@/Components/InputLabel';
|
||||
import PrimaryButton from '@/Components/PrimaryButton';
|
||||
import TextInput from '@/Components/TextInput';
|
||||
import { Head, Link, useForm } from '@inertiajs/react';
|
||||
|
||||
export default function Login({ status, canResetPassword }) {
|
||||
const { data, setData, post, processing, errors, reset } = useForm({
|
||||
email: '',
|
||||
password: '',
|
||||
remember: false,
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
reset('password');
|
||||
};
|
||||
}, []);
|
||||
|
||||
const submit = (e) => {
|
||||
e.preventDefault();
|
||||
|
||||
post(route('login'));
|
||||
};
|
||||
|
||||
return (
|
||||
<GuestLayout>
|
||||
<Head title="Log in" />
|
||||
|
||||
{status && <div className="mb-4 font-medium text-sm text-green-600">{status}</div>}
|
||||
|
||||
<form onSubmit={submit}>
|
||||
<div>
|
||||
<InputLabel htmlFor="email" value="Email" />
|
||||
|
||||
<TextInput
|
||||
id="email"
|
||||
type="email"
|
||||
name="email"
|
||||
value={data.email}
|
||||
className="mt-1 block w-full"
|
||||
autoComplete="username"
|
||||
isFocused={true}
|
||||
onChange={(e) => setData('email', e.target.value)}
|
||||
/>
|
||||
|
||||
<InputError message={errors.email} className="mt-2" />
|
||||
</div>
|
||||
|
||||
<div className="mt-4">
|
||||
<InputLabel htmlFor="password" value="Password" />
|
||||
|
||||
<TextInput
|
||||
id="password"
|
||||
type="password"
|
||||
name="password"
|
||||
value={data.password}
|
||||
className="mt-1 block w-full"
|
||||
autoComplete="current-password"
|
||||
onChange={(e) => setData('password', e.target.value)}
|
||||
/>
|
||||
|
||||
<InputError message={errors.password} className="mt-2" />
|
||||
</div>
|
||||
|
||||
<div className="block mt-4">
|
||||
<label className="flex items-center">
|
||||
<Checkbox
|
||||
name="remember"
|
||||
checked={data.remember}
|
||||
onChange={(e) => setData('remember', e.target.checked)}
|
||||
/>
|
||||
<span className="ml-2 text-sm text-gray-600">Remember me</span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center justify-end mt-4">
|
||||
{canResetPassword && (
|
||||
<Link
|
||||
href={route('password.request')}
|
||||
className="underline text-sm text-gray-600 hover:text-gray-900 rounded-md focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500"
|
||||
>
|
||||
Forgot your password?
|
||||
</Link>
|
||||
)}
|
||||
|
||||
<PrimaryButton className="ml-4" disabled={processing}>
|
||||
Log in
|
||||
</PrimaryButton>
|
||||
</div>
|
||||
</form>
|
||||
</GuestLayout>
|
||||
);
|
||||
}
|
||||
117
resources/js/Pages/Auth/Register.jsx
Normal file
117
resources/js/Pages/Auth/Register.jsx
Normal file
@@ -0,0 +1,117 @@
|
||||
import { useEffect } from 'react';
|
||||
import GuestLayout from '@/Layouts/GuestLayout';
|
||||
import InputError from '@/Components/InputError';
|
||||
import InputLabel from '@/Components/InputLabel';
|
||||
import PrimaryButton from '@/Components/PrimaryButton';
|
||||
import TextInput from '@/Components/TextInput';
|
||||
import { Head, Link, useForm } from '@inertiajs/react';
|
||||
|
||||
export default function Register() {
|
||||
const { data, setData, post, processing, errors, reset } = useForm({
|
||||
name: '',
|
||||
email: '',
|
||||
password: '',
|
||||
password_confirmation: '',
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
reset('password', 'password_confirmation');
|
||||
};
|
||||
}, []);
|
||||
|
||||
const submit = (e) => {
|
||||
e.preventDefault();
|
||||
|
||||
post(route('register'));
|
||||
};
|
||||
|
||||
return (
|
||||
<GuestLayout>
|
||||
<Head title="Register" />
|
||||
|
||||
<form onSubmit={submit}>
|
||||
<div>
|
||||
<InputLabel htmlFor="name" value="Name" />
|
||||
|
||||
<TextInput
|
||||
id="name"
|
||||
name="name"
|
||||
value={data.name}
|
||||
className="mt-1 block w-full"
|
||||
autoComplete="name"
|
||||
isFocused={true}
|
||||
onChange={(e) => setData('name', e.target.value)}
|
||||
required
|
||||
/>
|
||||
|
||||
<InputError message={errors.name} className="mt-2" />
|
||||
</div>
|
||||
|
||||
<div className="mt-4">
|
||||
<InputLabel htmlFor="email" value="Email" />
|
||||
|
||||
<TextInput
|
||||
id="email"
|
||||
type="email"
|
||||
name="email"
|
||||
value={data.email}
|
||||
className="mt-1 block w-full"
|
||||
autoComplete="username"
|
||||
onChange={(e) => setData('email', e.target.value)}
|
||||
required
|
||||
/>
|
||||
|
||||
<InputError message={errors.email} className="mt-2" />
|
||||
</div>
|
||||
|
||||
<div className="mt-4">
|
||||
<InputLabel htmlFor="password" value="Password" />
|
||||
|
||||
<TextInput
|
||||
id="password"
|
||||
type="password"
|
||||
name="password"
|
||||
value={data.password}
|
||||
className="mt-1 block w-full"
|
||||
autoComplete="new-password"
|
||||
onChange={(e) => setData('password', e.target.value)}
|
||||
required
|
||||
/>
|
||||
|
||||
<InputError message={errors.password} className="mt-2" />
|
||||
</div>
|
||||
|
||||
<div className="mt-4">
|
||||
<InputLabel htmlFor="password_confirmation" value="Confirm Password" />
|
||||
|
||||
<TextInput
|
||||
id="password_confirmation"
|
||||
type="password"
|
||||
name="password_confirmation"
|
||||
value={data.password_confirmation}
|
||||
className="mt-1 block w-full"
|
||||
autoComplete="new-password"
|
||||
onChange={(e) => setData('password_confirmation', e.target.value)}
|
||||
required
|
||||
/>
|
||||
|
||||
<InputError message={errors.password_confirmation} className="mt-2" />
|
||||
</div>
|
||||
|
||||
<div className="flex items-center justify-end mt-4">
|
||||
<Link
|
||||
href={route('login')}
|
||||
className="underline text-sm text-gray-600 hover:text-gray-900 rounded-md focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500"
|
||||
>
|
||||
Already registered?
|
||||
</Link>
|
||||
|
||||
<PrimaryButton className="ml-4" disabled={processing}>
|
||||
Register
|
||||
</PrimaryButton>
|
||||
</div>
|
||||
</form>
|
||||
</GuestLayout>
|
||||
);
|
||||
}
|
||||
90
resources/js/Pages/Auth/ResetPassword.jsx
Normal file
90
resources/js/Pages/Auth/ResetPassword.jsx
Normal file
@@ -0,0 +1,90 @@
|
||||
import { useEffect } from 'react';
|
||||
import GuestLayout from '@/Layouts/GuestLayout';
|
||||
import InputError from '@/Components/InputError';
|
||||
import InputLabel from '@/Components/InputLabel';
|
||||
import PrimaryButton from '@/Components/PrimaryButton';
|
||||
import TextInput from '@/Components/TextInput';
|
||||
import { Head, useForm } from '@inertiajs/react';
|
||||
|
||||
export default function ResetPassword({ token, email }) {
|
||||
const { data, setData, post, processing, errors, reset } = useForm({
|
||||
token: token,
|
||||
email: email,
|
||||
password: '',
|
||||
password_confirmation: '',
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
reset('password', 'password_confirmation');
|
||||
};
|
||||
}, []);
|
||||
|
||||
const submit = (e) => {
|
||||
e.preventDefault();
|
||||
|
||||
post(route('password.store'));
|
||||
};
|
||||
|
||||
return (
|
||||
<GuestLayout>
|
||||
<Head title="Reset Password" />
|
||||
|
||||
<form onSubmit={submit}>
|
||||
<div>
|
||||
<InputLabel htmlFor="email" value="Email" />
|
||||
|
||||
<TextInput
|
||||
id="email"
|
||||
type="email"
|
||||
name="email"
|
||||
value={data.email}
|
||||
className="mt-1 block w-full"
|
||||
autoComplete="username"
|
||||
onChange={(e) => setData('email', e.target.value)}
|
||||
/>
|
||||
|
||||
<InputError message={errors.email} className="mt-2" />
|
||||
</div>
|
||||
|
||||
<div className="mt-4">
|
||||
<InputLabel htmlFor="password" value="Password" />
|
||||
|
||||
<TextInput
|
||||
id="password"
|
||||
type="password"
|
||||
name="password"
|
||||
value={data.password}
|
||||
className="mt-1 block w-full"
|
||||
autoComplete="new-password"
|
||||
isFocused={true}
|
||||
onChange={(e) => setData('password', e.target.value)}
|
||||
/>
|
||||
|
||||
<InputError message={errors.password} className="mt-2" />
|
||||
</div>
|
||||
|
||||
<div className="mt-4">
|
||||
<InputLabel htmlFor="password_confirmation" value="Confirm Password" />
|
||||
|
||||
<TextInput
|
||||
type="password"
|
||||
name="password_confirmation"
|
||||
value={data.password_confirmation}
|
||||
className="mt-1 block w-full"
|
||||
autoComplete="new-password"
|
||||
onChange={(e) => setData('password_confirmation', e.target.value)}
|
||||
/>
|
||||
|
||||
<InputError message={errors.password_confirmation} className="mt-2" />
|
||||
</div>
|
||||
|
||||
<div className="flex items-center justify-end mt-4">
|
||||
<PrimaryButton className="ml-4" disabled={processing}>
|
||||
Reset Password
|
||||
</PrimaryButton>
|
||||
</div>
|
||||
</form>
|
||||
</GuestLayout>
|
||||
);
|
||||
}
|
||||
45
resources/js/Pages/Auth/VerifyEmail.jsx
Normal file
45
resources/js/Pages/Auth/VerifyEmail.jsx
Normal file
@@ -0,0 +1,45 @@
|
||||
import GuestLayout from '@/Layouts/GuestLayout';
|
||||
import PrimaryButton from '@/Components/PrimaryButton';
|
||||
import { Head, Link, useForm } from '@inertiajs/react';
|
||||
|
||||
export default function VerifyEmail({ status }) {
|
||||
const { post, processing } = useForm({});
|
||||
|
||||
const submit = (e) => {
|
||||
e.preventDefault();
|
||||
|
||||
post(route('verification.send'));
|
||||
};
|
||||
|
||||
return (
|
||||
<GuestLayout>
|
||||
<Head title="Email Verification" />
|
||||
|
||||
<div className="mb-4 text-sm text-gray-600">
|
||||
Thanks for signing up! Before getting started, could you verify your email address by clicking on the
|
||||
link we just emailed to you? If you didn't receive the email, we will gladly send you another.
|
||||
</div>
|
||||
|
||||
{status === 'verification-link-sent' && (
|
||||
<div className="mb-4 font-medium text-sm text-green-600">
|
||||
A new verification link has been sent to the email address you provided during registration.
|
||||
</div>
|
||||
)}
|
||||
|
||||
<form onSubmit={submit}>
|
||||
<div className="mt-4 flex items-center justify-between">
|
||||
<PrimaryButton disabled={processing}>Resend Verification Email</PrimaryButton>
|
||||
|
||||
<Link
|
||||
href={route('logout')}
|
||||
method="post"
|
||||
as="button"
|
||||
className="underline text-sm text-gray-600 hover:text-gray-900 rounded-md focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500"
|
||||
>
|
||||
Log Out
|
||||
</Link>
|
||||
</div>
|
||||
</form>
|
||||
</GuestLayout>
|
||||
);
|
||||
}
|
||||
46
resources/js/Pages/Categories/Index.jsx
Normal file
46
resources/js/Pages/Categories/Index.jsx
Normal file
@@ -0,0 +1,46 @@
|
||||
import Layout from '@/Layouts/Layout';
|
||||
import Searchbar from '@/Components/Searchbar';
|
||||
import CreateButton from '@/Components/CreateButton';
|
||||
import CategoryForm from '@/Components/CategoryForm';
|
||||
import CategoryCard from '@/Components/CategoryCard';
|
||||
|
||||
import { useState } from 'react'
|
||||
import { router } from '@inertiajs/react'
|
||||
|
||||
export default function Index({ categories }){
|
||||
|
||||
let [createOpen, setCreateOpen] = useState(false);
|
||||
|
||||
function handleCancel(){
|
||||
setCreateOpen(false);
|
||||
}
|
||||
function handleCreateClick(){
|
||||
setCreateOpen(true);
|
||||
}
|
||||
|
||||
function handleCreate(){
|
||||
setCreateOpen(false);
|
||||
router.refresh();
|
||||
}
|
||||
const category_list = categories.map((category) => (
|
||||
<CategoryCard category={ category } />
|
||||
));
|
||||
|
||||
return (
|
||||
<div className="relative flex flex-col h-full w-full space-y-6">
|
||||
{createOpen ? <div className="flex items-center justify-center absolute top-0 z-50 backdrop-blur h-full w-full rounded-lg backdrop-brightness-75">
|
||||
<CategoryForm onCancel = {handleCancel}/>
|
||||
</div> : ''}
|
||||
<div className="flex justify-between h-fit">
|
||||
<Searchbar />
|
||||
<CreateButton onClick={ handleCreateClick } title="افزودن دسته بندی"/>
|
||||
</div>
|
||||
<div className="grid grid-cols-2 gap-8 ">
|
||||
{category_list}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Index.layout = page => <Layout children={page} />
|
||||
19
resources/js/Pages/Content/Index.jsx
Normal file
19
resources/js/Pages/Content/Index.jsx
Normal file
@@ -0,0 +1,19 @@
|
||||
import Layout from '@/Layouts/Layout';
|
||||
import Searchbar from '@/Components/Searchbar';
|
||||
import CreateButton from '@/Components/CreateButton';
|
||||
import ProductForm from '@/Components/ProductForm';
|
||||
import ProductTable from '@/Components/ProductTable';
|
||||
|
||||
import { useState } from 'react'
|
||||
import { router } from '@inertiajs/react'
|
||||
|
||||
export default function Index({ contents }){
|
||||
|
||||
return (
|
||||
<div className="relative flex flex-col h-full w-full space-y-6">
|
||||
hello
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Index.layout = page => <Layout children={page} />
|
||||
13
resources/js/Pages/Dashboard.jsx
Normal file
13
resources/js/Pages/Dashboard.jsx
Normal file
@@ -0,0 +1,13 @@
|
||||
|
||||
import Layout from '@/Layouts/Layout';
|
||||
|
||||
|
||||
export default function Dashboard({ data, visits }) {
|
||||
return (
|
||||
<div className="grid grid-cols-12 grid-rows-12 gap-6 h-full w-full">
|
||||
Hello
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Dashboard.layout = page => <Layout children={page} />
|
||||
53
resources/js/Pages/Products/Index.jsx
Normal file
53
resources/js/Pages/Products/Index.jsx
Normal file
@@ -0,0 +1,53 @@
|
||||
import Layout from '@/Layouts/Layout';
|
||||
import Searchbar from '@/Components/Searchbar';
|
||||
import CreateButton from '@/Components/CreateButton';
|
||||
import ProductForm from '@/Components/ProductForm';
|
||||
import ProductTable from '@/Components/ProductTable';
|
||||
|
||||
import { useState } from 'react'
|
||||
import { router } from '@inertiajs/react'
|
||||
|
||||
export default function Index({ products, links, categories }){
|
||||
|
||||
let [createOpen, setCreateOpen] = useState(false);
|
||||
|
||||
function handleCancel(){
|
||||
setCreateOpen(false);
|
||||
}
|
||||
function handleCreateClick(){
|
||||
setCreateOpen(true);
|
||||
}
|
||||
|
||||
function handleCreate(){
|
||||
setCreateOpen(false);
|
||||
router.refresh();
|
||||
}
|
||||
|
||||
const product_list = products.map((product) => (
|
||||
<div className="flex flex-col items-center justify-center bg-white rounded-lg w-full h-full">
|
||||
{product.images[0] ? <img src={ product.images[0].thumbnail } alt={ product.images[0].alt } className="h-52 w-full object-cover rounded-t-lg shadow-md" /> : null}
|
||||
<div className="p-4 py-6 flex flex-col items-center justify-center space-y-4">
|
||||
<span className="text-xl">{product.title}</span>
|
||||
<span className="text-gray-600 text-center">{product.description}</span>
|
||||
</div>
|
||||
</div>
|
||||
));
|
||||
|
||||
return (
|
||||
<div className="relative flex flex-col h-full w-full space-y-6">
|
||||
{createOpen ? <div className="flex items-center justify-center absolute top-0 z-10 backdrop-blur h-full w-full rounded-lg backdrop-brightness-75">
|
||||
<ProductForm onCancel = {handleCancel} categories={ categories }/>
|
||||
</div> : ''}
|
||||
<div className="flex justify-between h-fit">
|
||||
<Searchbar />
|
||||
<CreateButton onClick={ handleCreateClick } title="افزودن محصول"/>
|
||||
</div>
|
||||
<div className="grid grid-cols-4 gap-8">
|
||||
{product_list}
|
||||
</div>
|
||||
<ProductTable items={ products } links={ links } title="محصولات" />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Index.layout = page => <Layout children={page} />
|
||||
36
resources/js/Pages/Profile/Edit.jsx
Normal file
36
resources/js/Pages/Profile/Edit.jsx
Normal file
@@ -0,0 +1,36 @@
|
||||
import AuthenticatedLayout from '@/Layouts/AuthenticatedLayout';
|
||||
import DeleteUserForm from './Partials/DeleteUserForm';
|
||||
import UpdatePasswordForm from './Partials/UpdatePasswordForm';
|
||||
import UpdateProfileInformationForm from './Partials/UpdateProfileInformationForm';
|
||||
import { Head } from '@inertiajs/react';
|
||||
|
||||
export default function Edit({ auth, mustVerifyEmail, status }) {
|
||||
return (
|
||||
<AuthenticatedLayout
|
||||
user={auth.user}
|
||||
header={<h2 className="font-semibold text-xl text-gray-800 leading-tight">Profile</h2>}
|
||||
>
|
||||
<Head title="Profile" />
|
||||
|
||||
<div className="py-12">
|
||||
<div className="max-w-7xl mx-auto sm:px-6 lg:px-8 space-y-6">
|
||||
<div className="p-4 sm:p-8 bg-white shadow sm:rounded-lg">
|
||||
<UpdateProfileInformationForm
|
||||
mustVerifyEmail={mustVerifyEmail}
|
||||
status={status}
|
||||
className="max-w-xl"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="p-4 sm:p-8 bg-white shadow sm:rounded-lg">
|
||||
<UpdatePasswordForm className="max-w-xl" />
|
||||
</div>
|
||||
|
||||
<div className="p-4 sm:p-8 bg-white shadow sm:rounded-lg">
|
||||
<DeleteUserForm className="max-w-xl" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</AuthenticatedLayout>
|
||||
);
|
||||
}
|
||||
99
resources/js/Pages/Profile/Partials/DeleteUserForm.jsx
Normal file
99
resources/js/Pages/Profile/Partials/DeleteUserForm.jsx
Normal file
@@ -0,0 +1,99 @@
|
||||
import { useRef, useState } from 'react';
|
||||
import DangerButton from '@/Components/DangerButton';
|
||||
import InputError from '@/Components/InputError';
|
||||
import InputLabel from '@/Components/InputLabel';
|
||||
import Modal from '@/Components/Modal';
|
||||
import SecondaryButton from '@/Components/SecondaryButton';
|
||||
import TextInput from '@/Components/TextInput';
|
||||
import { useForm } from '@inertiajs/react';
|
||||
|
||||
export default function DeleteUserForm({ className = '' }) {
|
||||
const [confirmingUserDeletion, setConfirmingUserDeletion] = useState(false);
|
||||
const passwordInput = useRef();
|
||||
|
||||
const {
|
||||
data,
|
||||
setData,
|
||||
delete: destroy,
|
||||
processing,
|
||||
reset,
|
||||
errors,
|
||||
} = useForm({
|
||||
password: '',
|
||||
});
|
||||
|
||||
const confirmUserDeletion = () => {
|
||||
setConfirmingUserDeletion(true);
|
||||
};
|
||||
|
||||
const deleteUser = (e) => {
|
||||
e.preventDefault();
|
||||
|
||||
destroy(route('profile.destroy'), {
|
||||
preserveScroll: true,
|
||||
onSuccess: () => closeModal(),
|
||||
onError: () => passwordInput.current.focus(),
|
||||
onFinish: () => reset(),
|
||||
});
|
||||
};
|
||||
|
||||
const closeModal = () => {
|
||||
setConfirmingUserDeletion(false);
|
||||
|
||||
reset();
|
||||
};
|
||||
|
||||
return (
|
||||
<section className={`space-y-6 ${className}`}>
|
||||
<header>
|
||||
<h2 className="text-lg font-medium text-gray-900">Delete Account</h2>
|
||||
|
||||
<p className="mt-1 text-sm text-gray-600">
|
||||
Once your account is deleted, all of its resources and data will be permanently deleted. Before
|
||||
deleting your account, please download any data or information that you wish to retain.
|
||||
</p>
|
||||
</header>
|
||||
|
||||
<DangerButton onClick={confirmUserDeletion}>Delete Account</DangerButton>
|
||||
|
||||
<Modal show={confirmingUserDeletion} onClose={closeModal}>
|
||||
<form onSubmit={deleteUser} className="p-6">
|
||||
<h2 className="text-lg font-medium text-gray-900">
|
||||
Are you sure you want to delete your account?
|
||||
</h2>
|
||||
|
||||
<p className="mt-1 text-sm text-gray-600">
|
||||
Once your account is deleted, all of its resources and data will be permanently deleted. Please
|
||||
enter your password to confirm you would like to permanently delete your account.
|
||||
</p>
|
||||
|
||||
<div className="mt-6">
|
||||
<InputLabel htmlFor="password" value="Password" className="sr-only" />
|
||||
|
||||
<TextInput
|
||||
id="password"
|
||||
type="password"
|
||||
name="password"
|
||||
ref={passwordInput}
|
||||
value={data.password}
|
||||
onChange={(e) => setData('password', e.target.value)}
|
||||
className="mt-1 block w-3/4"
|
||||
isFocused
|
||||
placeholder="Password"
|
||||
/>
|
||||
|
||||
<InputError message={errors.password} className="mt-2" />
|
||||
</div>
|
||||
|
||||
<div className="mt-6 flex justify-end">
|
||||
<SecondaryButton onClick={closeModal}>Cancel</SecondaryButton>
|
||||
|
||||
<DangerButton className="ml-3" disabled={processing}>
|
||||
Delete Account
|
||||
</DangerButton>
|
||||
</div>
|
||||
</form>
|
||||
</Modal>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
113
resources/js/Pages/Profile/Partials/UpdatePasswordForm.jsx
Normal file
113
resources/js/Pages/Profile/Partials/UpdatePasswordForm.jsx
Normal file
@@ -0,0 +1,113 @@
|
||||
import { useRef } from 'react';
|
||||
import InputError from '@/Components/InputError';
|
||||
import InputLabel from '@/Components/InputLabel';
|
||||
import PrimaryButton from '@/Components/PrimaryButton';
|
||||
import TextInput from '@/Components/TextInput';
|
||||
import { useForm } from '@inertiajs/react';
|
||||
import { Transition } from '@headlessui/react';
|
||||
|
||||
export default function UpdatePasswordForm({ className = '' }) {
|
||||
const passwordInput = useRef();
|
||||
const currentPasswordInput = useRef();
|
||||
|
||||
const { data, setData, errors, put, reset, processing, recentlySuccessful } = useForm({
|
||||
current_password: '',
|
||||
password: '',
|
||||
password_confirmation: '',
|
||||
});
|
||||
|
||||
const updatePassword = (e) => {
|
||||
e.preventDefault();
|
||||
|
||||
put(route('password.update'), {
|
||||
preserveScroll: true,
|
||||
onSuccess: () => reset(),
|
||||
onError: (errors) => {
|
||||
if (errors.password) {
|
||||
reset('password', 'password_confirmation');
|
||||
passwordInput.current.focus();
|
||||
}
|
||||
|
||||
if (errors.current_password) {
|
||||
reset('current_password');
|
||||
currentPasswordInput.current.focus();
|
||||
}
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<section className={className}>
|
||||
<header>
|
||||
<h2 className="text-lg font-medium text-gray-900">Update Password</h2>
|
||||
|
||||
<p className="mt-1 text-sm text-gray-600">
|
||||
Ensure your account is using a long, random password to stay secure.
|
||||
</p>
|
||||
</header>
|
||||
|
||||
<form onSubmit={updatePassword} className="mt-6 space-y-6">
|
||||
<div>
|
||||
<InputLabel htmlFor="current_password" value="Current Password" />
|
||||
|
||||
<TextInput
|
||||
id="current_password"
|
||||
ref={currentPasswordInput}
|
||||
value={data.current_password}
|
||||
onChange={(e) => setData('current_password', e.target.value)}
|
||||
type="password"
|
||||
className="mt-1 block w-full"
|
||||
autoComplete="current-password"
|
||||
/>
|
||||
|
||||
<InputError message={errors.current_password} className="mt-2" />
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<InputLabel htmlFor="password" value="New Password" />
|
||||
|
||||
<TextInput
|
||||
id="password"
|
||||
ref={passwordInput}
|
||||
value={data.password}
|
||||
onChange={(e) => setData('password', e.target.value)}
|
||||
type="password"
|
||||
className="mt-1 block w-full"
|
||||
autoComplete="new-password"
|
||||
/>
|
||||
|
||||
<InputError message={errors.password} className="mt-2" />
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<InputLabel htmlFor="password_confirmation" value="Confirm Password" />
|
||||
|
||||
<TextInput
|
||||
id="password_confirmation"
|
||||
value={data.password_confirmation}
|
||||
onChange={(e) => setData('password_confirmation', e.target.value)}
|
||||
type="password"
|
||||
className="mt-1 block w-full"
|
||||
autoComplete="new-password"
|
||||
/>
|
||||
|
||||
<InputError message={errors.password_confirmation} className="mt-2" />
|
||||
</div>
|
||||
|
||||
<div className="flex items-center gap-4">
|
||||
<PrimaryButton disabled={processing}>Save</PrimaryButton>
|
||||
|
||||
<Transition
|
||||
show={recentlySuccessful}
|
||||
enter="transition ease-in-out"
|
||||
enterFrom="opacity-0"
|
||||
leave="transition ease-in-out"
|
||||
leaveTo="opacity-0"
|
||||
>
|
||||
<p className="text-sm text-gray-600">Saved.</p>
|
||||
</Transition>
|
||||
</div>
|
||||
</form>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
import InputError from '@/Components/InputError';
|
||||
import InputLabel from '@/Components/InputLabel';
|
||||
import PrimaryButton from '@/Components/PrimaryButton';
|
||||
import TextInput from '@/Components/TextInput';
|
||||
import { Link, useForm, usePage } from '@inertiajs/react';
|
||||
import { Transition } from '@headlessui/react';
|
||||
|
||||
export default function UpdateProfileInformation({ mustVerifyEmail, status, className = '' }) {
|
||||
const user = usePage().props.auth.user;
|
||||
|
||||
const { data, setData, patch, errors, processing, recentlySuccessful } = useForm({
|
||||
name: user.name,
|
||||
email: user.email,
|
||||
});
|
||||
|
||||
const submit = (e) => {
|
||||
e.preventDefault();
|
||||
|
||||
patch(route('profile.update'));
|
||||
};
|
||||
|
||||
return (
|
||||
<section className={className}>
|
||||
<header>
|
||||
<h2 className="text-lg font-medium text-gray-900">Profile Information</h2>
|
||||
|
||||
<p className="mt-1 text-sm text-gray-600">
|
||||
Update your account's profile information and email address.
|
||||
</p>
|
||||
</header>
|
||||
|
||||
<form onSubmit={submit} className="mt-6 space-y-6">
|
||||
<div>
|
||||
<InputLabel htmlFor="name" value="Name" />
|
||||
|
||||
<TextInput
|
||||
id="name"
|
||||
className="mt-1 block w-full"
|
||||
value={data.name}
|
||||
onChange={(e) => setData('name', e.target.value)}
|
||||
required
|
||||
isFocused
|
||||
autoComplete="name"
|
||||
/>
|
||||
|
||||
<InputError className="mt-2" message={errors.name} />
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<InputLabel htmlFor="email" value="Email" />
|
||||
|
||||
<TextInput
|
||||
id="email"
|
||||
type="email"
|
||||
className="mt-1 block w-full"
|
||||
value={data.email}
|
||||
onChange={(e) => setData('email', e.target.value)}
|
||||
required
|
||||
autoComplete="username"
|
||||
/>
|
||||
|
||||
<InputError className="mt-2" message={errors.email} />
|
||||
</div>
|
||||
|
||||
{mustVerifyEmail && user.email_verified_at === null && (
|
||||
<div>
|
||||
<p className="text-sm mt-2 text-gray-800">
|
||||
Your email address is unverified.
|
||||
<Link
|
||||
href={route('verification.send')}
|
||||
method="post"
|
||||
as="button"
|
||||
className="underline text-sm text-gray-600 hover:text-gray-900 rounded-md focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500"
|
||||
>
|
||||
Click here to re-send the verification email.
|
||||
</Link>
|
||||
</p>
|
||||
|
||||
{status === 'verification-link-sent' && (
|
||||
<div className="mt-2 font-medium text-sm text-green-600">
|
||||
A new verification link has been sent to your email address.
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="flex items-center gap-4">
|
||||
<PrimaryButton disabled={processing}>Save</PrimaryButton>
|
||||
|
||||
<Transition
|
||||
show={recentlySuccessful}
|
||||
enter="transition ease-in-out"
|
||||
enterFrom="opacity-0"
|
||||
leave="transition ease-in-out"
|
||||
leaveTo="opacity-0"
|
||||
>
|
||||
<p className="text-sm text-gray-600">Saved.</p>
|
||||
</Transition>
|
||||
</div>
|
||||
</form>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
52
resources/js/Pages/Properties/Index.jsx
Normal file
52
resources/js/Pages/Properties/Index.jsx
Normal file
@@ -0,0 +1,52 @@
|
||||
import Layout from '@/Layouts/Layout';
|
||||
import Searchbar from '@/Components/Searchbar';
|
||||
import CreateButton from '@/Components/CreateButton';
|
||||
|
||||
|
||||
import { useState } from 'react'
|
||||
import { router } from '@inertiajs/react'
|
||||
|
||||
export default function Index({ products, links, categories }){
|
||||
|
||||
let [createOpen, setCreateOpen] = useState(false);
|
||||
|
||||
function handleCancel(){
|
||||
setCreateOpen(false);
|
||||
}
|
||||
function handleCreateClick(){
|
||||
setCreateOpen(true);
|
||||
}
|
||||
|
||||
function handleCreate(){
|
||||
setCreateOpen(false);
|
||||
router.refresh();
|
||||
}
|
||||
|
||||
const product_list = products.map((product) => (
|
||||
<div className="flex flex-col items-center justify-center bg-white rounded-lg w-full h-full">
|
||||
{product.images[0] ? <img src={ product.images[0].thumbnail } alt={ product.images[0].alt } className="h-52 w-full object-cover rounded-t-lg shadow-md" /> : null}
|
||||
<div className="p-4 py-6 flex flex-col items-center justify-center space-y-4">
|
||||
<span className="text-xl">{product.title}</span>
|
||||
<span className="text-gray-600 text-center">{product.description}</span>
|
||||
</div>
|
||||
</div>
|
||||
));
|
||||
|
||||
return (
|
||||
<div className="relative flex flex-col h-full w-full space-y-6">
|
||||
{createOpen ? <div className="flex items-center justify-center absolute top-0 z-10 backdrop-blur h-full w-full rounded-lg backdrop-brightness-75">
|
||||
<ProductForm onCancel = {handleCancel} categories={ categories }/>
|
||||
</div> : ''}
|
||||
<div className="flex justify-between h-fit">
|
||||
<Searchbar />
|
||||
<CreateButton onClick={ handleCreateClick } title="افزودن محصول"/>
|
||||
</div>
|
||||
<div className="grid grid-cols-4 gap-8">
|
||||
{product_list}
|
||||
</div>
|
||||
<ProductTable items={ products } links={ links } title="محصولات" />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Index.layout = page => <Layout children={page} />
|
||||
Reference in New Issue
Block a user