initial commit

This commit is contained in:
ferdiansyah783
2025-08-05 12:35:40 +07:00
commit fffa2ead5c
1069 changed files with 118056 additions and 0 deletions
+99
View File
@@ -0,0 +1,99 @@
'use client'
// React Imports
import { useState } from 'react'
// Next Imports
import Link from 'next/link'
import { useParams } from 'next/navigation'
// MUI Imports
import Card from '@mui/material/Card'
import CardContent from '@mui/material/CardContent'
import Button from '@mui/material/Button'
import Grid from '@mui/material/Grid2'
import InputLabel from '@mui/material/InputLabel'
import MenuItem from '@mui/material/MenuItem'
import Switch from '@mui/material/Switch'
// Type Imports
import type { Locale } from '@configs/i18n'
// Component Imports
import SendInvoiceDrawer from '@views/apps/invoice/shared/SendInvoiceDrawer'
import CustomTextField from '@core/components/mui/TextField'
// Util Imports
import { getLocalizedUrl } from '@/utils/i18n'
const AddActions = () => {
// States
const [sendDrawerOpen, setSendDrawerOpen] = useState(false)
// Hooks
const { lang: locale } = useParams()
return (
<Grid container spacing={6}>
<Grid size={{ xs: 12 }}>
<Card>
<CardContent className='flex flex-col gap-4'>
<Button
fullWidth
variant='contained'
className='capitalize'
startIcon={<i className='tabler-send' />}
onClick={() => setSendDrawerOpen(true)}
>
Send Invoice
</Button>
<Button
fullWidth
component={Link}
color='secondary'
variant='tonal'
className='capitalize'
href={getLocalizedUrl('/apps/invoice/preview/4987', locale as Locale)}
>
Preview
</Button>
<Button fullWidth color='secondary' variant='tonal' className='capitalize'>
Save
</Button>
</CardContent>
</Card>
<SendInvoiceDrawer open={sendDrawerOpen} handleClose={() => setSendDrawerOpen(false)} />
</Grid>
<Grid size={{ xs: 12 }}>
<CustomTextField select fullWidth defaultValue='Internet Banking' label='Accept payments via'>
<MenuItem value='Internet Banking'>Internet Banking</MenuItem>
<MenuItem value='Debit Card'>Debit Card</MenuItem>
<MenuItem value='Credit Card'>Credit Card</MenuItem>
<MenuItem value='Paypal'>Paypal</MenuItem>
<MenuItem value='UPI Transfer'>UPI Transfer</MenuItem>
</CustomTextField>
<div className='flex items-center justify-between mbs-3'>
<InputLabel htmlFor='invoice-edit-payment-terms' className='cursor-pointer'>
Payment Terms
</InputLabel>
<Switch defaultChecked id='invoice-edit-payment-terms' />
</div>
<div className='flex items-center justify-between'>
<InputLabel htmlFor='invoice-edit-client-notes' className='cursor-pointer'>
Client Notes
</InputLabel>
<Switch id='invoice-edit-client-notes' />
</div>
<div className='flex items-center justify-between'>
<InputLabel htmlFor='invoice-edit-payment-stub' className='cursor-pointer'>
Payment Stub
</InputLabel>
<Switch id='invoice-edit-payment-stub' />
</div>
</Grid>
</Grid>
)
}
export default AddActions
+372
View File
@@ -0,0 +1,372 @@
'use client'
// React Imports
import { useState } from 'react'
import type { SyntheticEvent } from 'react'
// MUI Imports
import Grid from '@mui/material/Grid2'
import Card from '@mui/material/Card'
import CardContent from '@mui/material/CardContent'
import Typography from '@mui/material/Typography'
import InputAdornment from '@mui/material/InputAdornment'
import Divider from '@mui/material/Divider'
import Button from '@mui/material/Button'
import IconButton from '@mui/material/IconButton'
import MenuItem from '@mui/material/MenuItem'
import Tooltip from '@mui/material/Tooltip'
import InputLabel from '@mui/material/InputLabel'
import useMediaQuery from '@mui/material/useMediaQuery'
import type { Theme } from '@mui/material/styles'
// Third-party Imports
import classnames from 'classnames'
// Type Imports
import type { InvoiceType } from '@/types/apps/invoiceTypes'
import type { FormDataType } from './AddCustomerDrawer'
// Component Imports
import AddCustomerDrawer, { initialFormData } from './AddCustomerDrawer'
import Logo from '@components/layout/shared/Logo'
import CustomTextField from '@core/components/mui/TextField'
// Styled Component Imports
import AppReactDatepicker from '@/libs/styles/AppReactDatepicker'
const AddAction = ({ invoiceData }: { invoiceData?: InvoiceType[] }) => {
// States
const [open, setOpen] = useState(false)
const [count, setCount] = useState(1)
const [selectData, setSelectData] = useState<InvoiceType | null>(null)
const [issuedDate, setIssuedDate] = useState<Date | null | undefined>(null)
const [dueDate, setDueDate] = useState<Date | null | undefined>(null)
const [formData, setFormData] = useState<FormDataType>(initialFormData)
// Hooks
const isBelowMdScreen = useMediaQuery((theme: Theme) => theme.breakpoints.down('md'))
const isBelowSmScreen = useMediaQuery((theme: Theme) => theme.breakpoints.down('sm'))
const onFormSubmit = (data: FormDataType) => {
setFormData(data)
}
const deleteForm = (e: SyntheticEvent) => {
e.preventDefault()
// @ts-ignore
e.target.closest('.repeater-item').remove()
}
return (
<>
<Card>
<CardContent className='sm:!p-12'>
<Grid container spacing={6}>
<Grid size={{ xs: 12 }}>
<div className='p-6 bg-actionHover rounded'>
<div className='flex justify-between gap-4 flex-col sm:flex-row'>
<div className='flex flex-col gap-6'>
<div className='flex items-center gap-2.5'>
<Logo />
</div>
<div>
<Typography color='text.primary'>Office 149, 450 South Brand Brooklyn</Typography>
<Typography color='text.primary'>San Diego County, CA 91905, USA</Typography>
<Typography color='text.primary'>+1 (123) 456 7891, +44 (876) 543 2198</Typography>
</div>
</div>
<div className='flex flex-col gap-2'>
<div className='flex items-center gap-4'>
<Typography variant='h5' className='min-is-[95px]'>
Invoice
</Typography>
<CustomTextField
fullWidth
value={invoiceData?.[0].id}
slotProps={{
input: {
disabled: true,
startAdornment: <InputAdornment position='start'>#</InputAdornment>
}
}}
/>
</div>
<div className='flex items-center'>
<Typography className='min-is-[95px] mie-4' color='text.primary'>
Date Issued:
</Typography>
<AppReactDatepicker
boxProps={{ className: 'is-full' }}
selected={issuedDate}
placeholderText='YYYY-MM-DD'
dateFormat={'yyyy-MM-dd'}
onChange={(date: Date | null) => setIssuedDate(date)}
customInput={<CustomTextField fullWidth />}
/>
</div>
<div className='flex items-center'>
<Typography className='min-is-[95px] mie-4' color='text.primary'>
Date Due:
</Typography>
<AppReactDatepicker
boxProps={{ className: 'is-full' }}
selected={dueDate}
placeholderText='YYYY-MM-DD'
dateFormat={'yyyy-MM-dd'}
onChange={(date: Date | null) => setDueDate(date)}
customInput={<CustomTextField fullWidth />}
/>
</div>
</div>
</div>
</div>
</Grid>
<Grid size={{ xs: 12 }}>
<div className='flex justify-between flex-col gap-4 flex-wrap sm:flex-row'>
<div className='flex flex-col gap-4'>
<Typography className='font-medium' color='text.primary'>
Invoice To:
</Typography>
<CustomTextField
select
className={classnames('min-is-[220px]', { 'is-1/2': isBelowSmScreen })}
value={selectData?.id || ''}
onChange={e => {
setFormData({} as FormDataType)
setSelectData(invoiceData?.slice(0, 5).filter(item => item.id === e.target.value)[0] || null)
}}
>
<MenuItem
className='flex items-center gap-2 !text-success !bg-transparent hover:text-success hover:!bg-[var(--mui-palette-success-lightOpacity)]'
value=''
onClick={() => {
setSelectData(null)
setOpen(true)
}}
>
<i className='tabler-plus text-base' />
Add New Customer
</MenuItem>
{invoiceData?.slice(0, 5).map((invoice: InvoiceType, index) => (
<MenuItem key={index} value={invoice.id}>
{invoice.name}
</MenuItem>
))}
</CustomTextField>
{selectData?.id ? (
<div>
<Typography>{selectData?.name}</Typography>
<Typography>{selectData?.company}</Typography>
<Typography>{selectData?.address}</Typography>
<Typography>{selectData?.contact}</Typography>
<Typography>{selectData?.companyEmail}</Typography>
</div>
) : (
<div>
<Typography>{formData?.name}</Typography>
<Typography>{formData?.company}</Typography>
<Typography>{formData?.address}</Typography>
<Typography>{formData?.contactNumber}</Typography>
<Typography>{formData?.email}</Typography>
</div>
)}
</div>
<div className='flex flex-col gap-4'>
<Typography className='font-medium' color='text.primary'>
Bill To:
</Typography>
<div>
<div className='flex items-center gap-4'>
<Typography className='min-is-[100px]'>Total Due:</Typography>
<Typography>$12,110.55</Typography>
</div>
<div className='flex items-center gap-4'>
<Typography className='min-is-[100px]'>Bank name:</Typography>
<Typography>American Bank</Typography>
</div>
<div className='flex items-center gap-4'>
<Typography className='min-is-[100px]'>Country:</Typography>
<Typography>United States</Typography>
</div>
<div className='flex items-center gap-4'>
<Typography className='min-is-[100px]'>IBAN:</Typography>
<Typography>ETD95476213874685</Typography>
</div>
<div className='flex items-center gap-4'>
<Typography className='min-is-[100px]'>SWIFT code:</Typography>
<Typography>BR91905</Typography>
</div>
</div>
</div>
</div>
</Grid>
<Grid size={{ xs: 12 }}>
<Divider className='border-dashed' />
</Grid>
<Grid size={{ xs: 12 }}>
{Array.from(Array(count).keys()).map((item, index) => (
<div
key={index}
className={classnames('repeater-item flex relative mbe-4 border rounded', {
'mbs-8': !isBelowMdScreen,
'!mbs-14': index !== 0 && !isBelowMdScreen,
'gap-5': isBelowMdScreen
})}
>
<Grid container spacing={5} className='m-0 p-5'>
<Grid size={{ xs: 12, md: 5, lg: 6 }}>
<Typography className='font-medium md:absolute md:-top-8' color='text.primary'>
Item
</Typography>
<CustomTextField select fullWidth defaultValue='App Design' className='mbe-5'>
<MenuItem value='App Design'>App Design</MenuItem>
<MenuItem value='App Customization'>App Customization</MenuItem>
<MenuItem value='ABC Template'>ABC Template</MenuItem>
<MenuItem value='App Development'>App Development</MenuItem>
</CustomTextField>
<CustomTextField rows={2} fullWidth multiline defaultValue='Customization & Bug Fixes' />
</Grid>
<Grid size={{ xs: 12, md: 3, lg: 2 }}>
<Typography className='font-medium md:absolute md:-top-8'>Cost</Typography>
<CustomTextField
{...(isBelowMdScreen && { fullWidth: true })}
type='number'
placeholder='24'
defaultValue='24'
className='mbe-5'
slotProps={{
input: {
inputProps: { min: 0 }
}
}}
/>
<div className='flex flex-col'>
<Typography component='span' color='text.primary'>
Discount:
</Typography>
<div className='flex gap-2'>
<Typography component='span' color='text.primary'>
0%
</Typography>
<Tooltip title='Tax 1' placement='top'>
<Typography component='span' color='text.primary'>
0%
</Typography>
</Tooltip>
<Tooltip title='Tax 2' placement='top'>
<Typography component='span' color='text.primary'>
0%
</Typography>
</Tooltip>
</div>
</div>
</Grid>
<Grid size={{ xs: 12, md: 2 }}>
<Typography className='font-medium md:absolute md:-top-8'>Hours</Typography>
<CustomTextField
{...(isBelowMdScreen && { fullWidth: true })}
type='number'
placeholder='1'
defaultValue='1'
slotProps={{
input: {
inputProps: { min: 0 }
}
}}
/>
</Grid>
<Grid size={{ xs: 12, md: 2 }}>
<Typography className='font-medium md:absolute md:-top-8'>Price</Typography>
<Typography>$24.00</Typography>
</Grid>
</Grid>
<div className='flex flex-col justify-start border-is'>
<IconButton size='small' onClick={deleteForm}>
<i className='tabler-x text-2xl text-actionActive' />
</IconButton>
</div>
</div>
))}
<Grid size={{ xs: 12 }}>
<Button
size='small'
variant='contained'
onClick={() => setCount(count + 1)}
startIcon={<i className='tabler-plus' />}
>
Add Item
</Button>
</Grid>
</Grid>
<Grid size={{ xs: 12 }}>
<Divider className='border-dashed' />
</Grid>
<Grid size={{ xs: 12 }}>
<div className='flex justify-between flex-col gap-4 sm:flex-row'>
<div className='flex flex-col gap-4 order-2 sm:order-[unset]'>
<div className='flex items-center gap-2'>
<Typography className='font-medium' color='text.primary'>
Salesperson:
</Typography>
<CustomTextField defaultValue='Tommy Shelby' />
</div>
<CustomTextField placeholder='Thanks for your business' />
</div>
<div className='min-is-[200px]'>
<div className='flex items-center justify-between'>
<Typography>Subtotal:</Typography>
<Typography className='font-medium' color='text.primary'>
$1800
</Typography>
</div>
<div className='flex items-center justify-between'>
<Typography>Discount:</Typography>
<Typography className='font-medium' color='text.primary'>
$28
</Typography>
</div>
<div className='flex items-center justify-between'>
<Typography>Tax:</Typography>
<Typography className='font-medium' color='text.primary'>
21%
</Typography>
</div>
<Divider className='mlb-2' />
<div className='flex items-center justify-between'>
<Typography>Total:</Typography>
<Typography className='font-medium' color='text.primary'>
$1690
</Typography>
</div>
</div>
</div>
</Grid>
<Grid size={{ xs: 12 }}>
<Divider className='border-dashed' />
</Grid>
<Grid size={{ xs: 12 }}>
<InputLabel htmlFor='invoice-note' className='inline-flex mbe-1 text-textPrimary'>
Note:
</InputLabel>
<CustomTextField
id='invoice-note'
rows={2}
fullWidth
multiline
className='border rounded'
defaultValue='It was a pleasure working with you and your team. We hope you will keep us in mind for future freelance
projects. Thank You!'
/>
</Grid>
</Grid>
</CardContent>
</Card>
<AddCustomerDrawer open={open} setOpen={setOpen} onFormSubmit={onFormSubmit} />
</>
)
}
export default AddAction
@@ -0,0 +1,144 @@
// React Imports
import { useState } from 'react'
import type { FormEvent } from 'react'
// MUI Imports
import Drawer from '@mui/material/Drawer'
import IconButton from '@mui/material/IconButton'
import Typography from '@mui/material/Typography'
import MenuItem from '@mui/material/MenuItem'
import Button from '@mui/material/Button'
import Divider from '@mui/material/Divider'
// Component Imports
import CustomTextField from '@core/components/mui/TextField'
type Props = {
open: boolean
setOpen: (open: boolean) => void
onFormSubmit: (formData: FormDataType) => void
}
export type FormDataType = {
name: string
company: string
email: string
address: string
country: string
contactNumber: string
}
// Vars
export const initialFormData: FormDataType = {
name: '',
company: '',
email: '',
address: '',
country: 'USA',
contactNumber: ''
}
const countries = ['USA', 'UK', 'Russia', 'Australia', 'Canada']
const AddCustomerDrawer = ({ open, setOpen, onFormSubmit }: Props) => {
// States
const [data, setData] = useState<FormDataType>(initialFormData)
const handleSubmit = (e: FormEvent<HTMLFormElement>) => {
e.preventDefault()
setOpen(false)
onFormSubmit(data)
handleReset()
}
const handleReset = () => {
setOpen(false)
setData(initialFormData)
}
return (
<Drawer
open={open}
anchor='right'
variant='temporary'
onClose={handleReset}
ModalProps={{ keepMounted: true }}
sx={{ '& .MuiDrawer-paper': { width: { xs: 300, sm: 400 } } }}
>
<div className='flex items-center justify-between plb-5 pli-6'>
<Typography variant='h5'>Add New Customer</Typography>
<IconButton size='small' onClick={handleReset}>
<i className='tabler-x text-2xl text-textPrimary' />
</IconButton>
</div>
<Divider />
<div className='p-6'>
<form onSubmit={e => handleSubmit(e)} className='flex flex-col gap-5'>
<CustomTextField
fullWidth
id='name'
label='Name'
value={data.name}
onChange={e => setData({ ...data, name: e.target.value })}
/>
<CustomTextField
fullWidth
id='company'
label='Company'
value={data.company}
onChange={e => setData({ ...data, company: e.target.value })}
/>
<CustomTextField
fullWidth
id='email'
label='Email'
value={data.email}
onChange={e => setData({ ...data, email: e.target.value })}
/>
<CustomTextField
rows={6}
multiline
fullWidth
id='address'
label='Address'
value={data.address}
onChange={e => setData({ ...data, address: e.target.value })}
/>
<CustomTextField
select
id='country'
label='Country'
name='country'
variant='outlined'
value={data?.country?.toLowerCase().replace(/\s+/g, '-') || ''}
onChange={e => setData({ ...data, country: e.target.value })}
>
{countries.map((item, index) => (
<MenuItem key={index} value={item.toLowerCase().replace(/\s+/g, '-')}>
{item}
</MenuItem>
))}
</CustomTextField>
<CustomTextField
fullWidth
id='contact'
type='number'
label='Contact Number'
value={data.contactNumber}
onChange={e => setData({ ...data, contactNumber: e.target.value })}
/>
<div className='flex items-center gap-4'>
<Button variant='contained' type='submit'>
Add
</Button>
<Button variant='tonal' color='error' type='reset' onClick={handleReset}>
Cancel
</Button>
</div>
</form>
</div>
</Drawer>
)
}
export default AddCustomerDrawer