initial commit
This commit is contained in:
@@ -0,0 +1,30 @@
|
||||
'use client'
|
||||
|
||||
//Mui Imports
|
||||
import { styled } from '@mui/material'
|
||||
import Button from '@mui/material/Button'
|
||||
import type { ButtonProps } from '@mui/material/Button'
|
||||
|
||||
const DialogCloseButton = styled(Button)<ButtonProps>({
|
||||
top: 0,
|
||||
right: 0,
|
||||
color: 'var(--mui-palette-text-disabled)',
|
||||
position: 'absolute',
|
||||
boxShadow: 'var(--mui-customShadows-xs)',
|
||||
transform: 'translate(9px, -10px)',
|
||||
borderRadius: 'var(--mui-shape-customBorderRadius-sm)',
|
||||
backgroundColor: 'var(--mui-palette-background-paper) !important',
|
||||
transition: 'transform 0.25s ease-in-out, box-shadow 0.25s ease-in-out',
|
||||
blockSize: 30,
|
||||
inlineSize: 30,
|
||||
minInlineSize: 0,
|
||||
padding: 0,
|
||||
'&:hover, &:active': {
|
||||
transform: 'translate(7px, -5px) !important'
|
||||
},
|
||||
'& i, & svg': {
|
||||
fontSize: '1.25rem'
|
||||
}
|
||||
})
|
||||
|
||||
export default DialogCloseButton
|
||||
@@ -0,0 +1,40 @@
|
||||
'use client'
|
||||
|
||||
// React Imports
|
||||
import { useState } from 'react'
|
||||
import type { ComponentType } from 'react'
|
||||
|
||||
type OpenDialogOnElementClickProps = {
|
||||
element: ComponentType<any>
|
||||
dialog: ComponentType<any>
|
||||
elementProps?: any
|
||||
dialogProps?: any
|
||||
}
|
||||
|
||||
const OpenDialogOnElementClick = (props: OpenDialogOnElementClickProps) => {
|
||||
// Props
|
||||
const { element: Element, dialog: Dialog, elementProps, dialogProps } = props
|
||||
|
||||
// States
|
||||
const [open, setOpen] = useState(false)
|
||||
|
||||
// Extract onClick from elementProps
|
||||
const { onClick: elementOnClick, ...restElementProps } = elementProps
|
||||
|
||||
// Handle onClick event
|
||||
const handleOnClick = (e: MouseEvent) => {
|
||||
elementOnClick && elementOnClick(e)
|
||||
setOpen(true)
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
{/* Receive element component as prop and we will pass onclick event which changes state to open */}
|
||||
<Element onClick={handleOnClick} {...restElementProps} />
|
||||
{/* Receive dialog component as prop and we will pass open and setOpen props to that component */}
|
||||
<Dialog open={open} setOpen={setOpen} {...dialogProps} closeAfterTransition={false} />
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default OpenDialogOnElementClick
|
||||
@@ -0,0 +1,275 @@
|
||||
'use client'
|
||||
|
||||
// React Imports
|
||||
import { useEffect, useState } from 'react'
|
||||
import type { ChangeEvent } from 'react'
|
||||
|
||||
// MUI Imports
|
||||
import Dialog from '@mui/material/Dialog'
|
||||
import DialogTitle from '@mui/material/DialogTitle'
|
||||
import DialogContent from '@mui/material/DialogContent'
|
||||
import DialogActions from '@mui/material/DialogActions'
|
||||
import Button from '@mui/material/Button'
|
||||
import Typography from '@mui/material/Typography'
|
||||
import Grid from '@mui/material/Grid2'
|
||||
import MenuItem from '@mui/material/MenuItem'
|
||||
import Switch from '@mui/material/Switch'
|
||||
import FormControlLabel from '@mui/material/FormControlLabel'
|
||||
|
||||
// Third-party Imports
|
||||
import classnames from 'classnames'
|
||||
|
||||
// Type Import
|
||||
import type { CustomInputVerticalData } from '@core/components/custom-inputs/types'
|
||||
|
||||
// Component Imports
|
||||
import CustomInputVertical from '@core/components/custom-inputs/Vertical'
|
||||
import DialogCloseButton from '../DialogCloseButton'
|
||||
import CustomTextField from '@core/components/mui/TextField'
|
||||
|
||||
type AddEditAddressData = {
|
||||
firstName?: string
|
||||
lastName?: string
|
||||
country?: string
|
||||
address1?: string
|
||||
address2?: string
|
||||
landmark?: string
|
||||
city?: string
|
||||
state?: string
|
||||
zipCode?: string
|
||||
}
|
||||
|
||||
type AddEditAddressProps = {
|
||||
open: boolean
|
||||
setOpen: (open: boolean) => void
|
||||
data?: AddEditAddressData
|
||||
}
|
||||
|
||||
const countries = ['Select Country', 'France', 'Russia', 'China', 'UK', 'US']
|
||||
|
||||
const initialAddressData: AddEditAddressProps['data'] = {
|
||||
firstName: '',
|
||||
lastName: '',
|
||||
country: '',
|
||||
address1: '',
|
||||
address2: '',
|
||||
landmark: '',
|
||||
city: '',
|
||||
state: '',
|
||||
zipCode: ''
|
||||
}
|
||||
|
||||
const customInputData: CustomInputVerticalData[] = [
|
||||
{
|
||||
title: 'Home',
|
||||
content: 'Delivery Time (7am - 9pm)',
|
||||
value: 'home',
|
||||
isSelected: true,
|
||||
asset: 'tabler-home'
|
||||
},
|
||||
{
|
||||
title: 'Office',
|
||||
content: 'Delivery Time (10am - 6pm)',
|
||||
value: 'office',
|
||||
asset: 'tabler-building-skyscraper'
|
||||
}
|
||||
]
|
||||
|
||||
const AddEditAddress = ({ open, setOpen, data }: AddEditAddressProps) => {
|
||||
// Vars
|
||||
const initialSelected: string = customInputData?.find(item => item.isSelected)?.value || ''
|
||||
|
||||
// States
|
||||
const [selected, setSelected] = useState<string>(initialSelected)
|
||||
const [addressData, setAddressData] = useState<AddEditAddressProps['data']>(initialAddressData)
|
||||
|
||||
const handleChange = (prop: string | ChangeEvent<HTMLInputElement>) => {
|
||||
if (typeof prop === 'string') {
|
||||
setSelected(prop)
|
||||
} else {
|
||||
setSelected((prop.target as HTMLInputElement).value)
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
setAddressData(data ?? initialAddressData)
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [open])
|
||||
|
||||
return (
|
||||
<Dialog
|
||||
open={open}
|
||||
maxWidth='md'
|
||||
scroll='body'
|
||||
onClose={() => {
|
||||
setOpen(false)
|
||||
setSelected(initialSelected)
|
||||
}}
|
||||
closeAfterTransition={false}
|
||||
sx={{ '& .MuiDialog-paper': { overflow: 'visible' } }}
|
||||
>
|
||||
<DialogTitle variant='h4' className='flex gap-2 flex-col text-center sm:pbs-16 sm:pbe-6 sm:pli-16'>
|
||||
{data ? 'Edit Address' : 'Add New Address'}
|
||||
<Typography component='span' className='flex flex-col text-center'>
|
||||
{data ? 'Edit Address for future billing' : 'Add address for billing address'}
|
||||
</Typography>
|
||||
</DialogTitle>
|
||||
<form onSubmit={e => e.preventDefault()}>
|
||||
<DialogContent className='pbs-0 sm:pli-16'>
|
||||
<DialogCloseButton onClick={() => setOpen(false)} disableRipple>
|
||||
<i className='tabler-x' />
|
||||
</DialogCloseButton>
|
||||
<Grid container spacing={6}>
|
||||
{customInputData.map((item, index) => {
|
||||
let asset
|
||||
|
||||
if (item.asset && typeof item.asset === 'string') {
|
||||
asset = <i className={classnames(item.asset, 'text-[28px]')} />
|
||||
}
|
||||
|
||||
return (
|
||||
<Grid size={{ xs: 12, sm: 6 }} key={index}>
|
||||
<CustomInputVertical
|
||||
type='radio'
|
||||
key={index}
|
||||
data={{ ...item, asset }}
|
||||
selected={selected}
|
||||
name='addressType'
|
||||
handleChange={handleChange}
|
||||
/>
|
||||
</Grid>
|
||||
)
|
||||
})}
|
||||
<Grid size={{ xs: 12, sm: 6 }}>
|
||||
<CustomTextField
|
||||
fullWidth
|
||||
label='First Name'
|
||||
name='firstName'
|
||||
variant='outlined'
|
||||
placeholder='John'
|
||||
value={addressData?.firstName}
|
||||
onChange={e => setAddressData({ ...addressData, firstName: e.target.value })}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid size={{ xs: 12, sm: 6 }}>
|
||||
<CustomTextField
|
||||
fullWidth
|
||||
label='Last Name'
|
||||
name='lastName'
|
||||
variant='outlined'
|
||||
placeholder='Doe'
|
||||
value={addressData?.lastName}
|
||||
onChange={e => setAddressData({ ...addressData, lastName: e.target.value })}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid size={{ xs: 12 }}>
|
||||
<CustomTextField
|
||||
select
|
||||
fullWidth
|
||||
label='Country'
|
||||
name='country'
|
||||
variant='outlined'
|
||||
value={addressData?.country?.toLowerCase().replace(/\s+/g, '-') || ''}
|
||||
onChange={e => setAddressData({ ...addressData, country: e.target.value })}
|
||||
>
|
||||
{countries.map((item, index) => (
|
||||
<MenuItem key={index} value={index === 0 ? '' : item.toLowerCase().replace(/\s+/g, '-')}>
|
||||
{item}
|
||||
</MenuItem>
|
||||
))}
|
||||
</CustomTextField>
|
||||
</Grid>
|
||||
<Grid size={{ xs: 12 }}>
|
||||
<CustomTextField
|
||||
fullWidth
|
||||
label='Address Line 1'
|
||||
name='address1'
|
||||
variant='outlined'
|
||||
placeholder='12, Business Park'
|
||||
value={addressData?.address1}
|
||||
onChange={e => setAddressData({ ...addressData, address1: e.target.value })}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid size={{ xs: 12 }}>
|
||||
<CustomTextField
|
||||
fullWidth
|
||||
label='Address Line 2'
|
||||
name='address1'
|
||||
variant='outlined'
|
||||
placeholder='Mall Road'
|
||||
value={addressData?.address2}
|
||||
onChange={e => setAddressData({ ...addressData, address2: e.target.value })}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid size={{ xs: 12, sm: 6 }}>
|
||||
<CustomTextField
|
||||
fullWidth
|
||||
label='Landmark'
|
||||
name='landmark'
|
||||
variant='outlined'
|
||||
placeholder='Nr. Hard Rock Cafe'
|
||||
value={addressData?.landmark}
|
||||
onChange={e => setAddressData({ ...addressData, landmark: e.target.value })}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid size={{ xs: 12, sm: 6 }}>
|
||||
<CustomTextField
|
||||
fullWidth
|
||||
label='City'
|
||||
name='city'
|
||||
variant='outlined'
|
||||
placeholder='Los Angeles'
|
||||
value={addressData?.city}
|
||||
onChange={e => setAddressData({ ...addressData, city: e.target.value })}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid size={{ xs: 12, sm: 6 }}>
|
||||
<CustomTextField
|
||||
fullWidth
|
||||
label='State'
|
||||
name='state'
|
||||
variant='outlined'
|
||||
placeholder='California'
|
||||
value={addressData?.state}
|
||||
onChange={e => setAddressData({ ...addressData, state: e.target.value })}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid size={{ xs: 12, sm: 6 }}>
|
||||
<CustomTextField
|
||||
fullWidth
|
||||
label='Zip Code'
|
||||
type='number'
|
||||
name='zipCode'
|
||||
variant='outlined'
|
||||
placeholder='99950'
|
||||
value={addressData?.zipCode}
|
||||
onChange={e => setAddressData({ ...addressData, zipCode: e.target.value })}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid size={{ xs: 12 }}>
|
||||
<FormControlLabel control={<Switch defaultChecked />} label='Make this default shipping address' />
|
||||
</Grid>
|
||||
</Grid>
|
||||
</DialogContent>
|
||||
<DialogActions className='justify-center pbs-0 sm:pbe-16 sm:pli-16'>
|
||||
<Button variant='contained' onClick={() => setOpen(false)} type='submit'>
|
||||
{data ? 'Update' : 'Submit'}
|
||||
</Button>
|
||||
<Button
|
||||
variant='tonal'
|
||||
color='secondary'
|
||||
onClick={() => {
|
||||
setOpen(false)
|
||||
setSelected(initialSelected)
|
||||
}}
|
||||
type='reset'
|
||||
>
|
||||
Cancel
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</form>
|
||||
</Dialog>
|
||||
)
|
||||
}
|
||||
|
||||
export default AddEditAddress
|
||||
@@ -0,0 +1,147 @@
|
||||
'use client'
|
||||
|
||||
// React Imports
|
||||
import { useEffect, useState } from 'react'
|
||||
|
||||
// MUI Imports
|
||||
import Grid from '@mui/material/Grid2'
|
||||
import Dialog from '@mui/material/Dialog'
|
||||
import Button from '@mui/material/Button'
|
||||
import Switch from '@mui/material/Switch'
|
||||
import DialogTitle from '@mui/material/DialogTitle'
|
||||
import DialogContent from '@mui/material/DialogContent'
|
||||
import DialogActions from '@mui/material/DialogActions'
|
||||
import FormControlLabel from '@mui/material/FormControlLabel'
|
||||
import Typography from '@mui/material/Typography'
|
||||
|
||||
// Type Imports
|
||||
import type { ThemeColor } from '@core/types'
|
||||
|
||||
// Component Imports
|
||||
import DialogCloseButton from '../DialogCloseButton'
|
||||
import CustomTextField from '@core/components/mui/TextField'
|
||||
|
||||
type BillingCardData = {
|
||||
cardNumber?: string
|
||||
name?: string
|
||||
expiryDate?: string
|
||||
cardCvv?: string
|
||||
imgSrc?: string
|
||||
imgAlt?: string
|
||||
cardStatus?: string
|
||||
badgeColor?: ThemeColor
|
||||
}
|
||||
|
||||
type BillingCardProps = {
|
||||
open: boolean
|
||||
setOpen: (open: boolean) => void
|
||||
data?: BillingCardData
|
||||
}
|
||||
|
||||
const initialCardData: BillingCardProps['data'] = {
|
||||
cardNumber: '',
|
||||
name: '',
|
||||
expiryDate: '',
|
||||
cardCvv: '',
|
||||
imgSrc: '',
|
||||
imgAlt: '',
|
||||
cardStatus: '',
|
||||
badgeColor: 'primary'
|
||||
}
|
||||
|
||||
const BillingCard = ({ open, setOpen, data }: BillingCardProps) => {
|
||||
// States
|
||||
const [cardData, setCardData] = useState(initialCardData)
|
||||
|
||||
const handleClose = () => {
|
||||
setOpen(false)
|
||||
setCardData(initialCardData)
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
setCardData(data ?? initialCardData)
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [open])
|
||||
|
||||
return (
|
||||
<Dialog
|
||||
open={open}
|
||||
onClose={handleClose}
|
||||
closeAfterTransition={false}
|
||||
sx={{ '& .MuiDialog-paper': { overflow: 'visible' } }}
|
||||
>
|
||||
<DialogCloseButton onClick={() => setOpen(false)} disableRipple>
|
||||
<i className='tabler-x' />
|
||||
</DialogCloseButton>
|
||||
<DialogTitle variant='h4' className='flex flex-col gap-2 text-center p-6 sm:pbs-16 sm:pbe-6 sm:pli-16'>
|
||||
{data ? 'Edit Card' : 'Add New Card'}
|
||||
<Typography component='span' className='flex flex-col text-center'>
|
||||
{data ? 'Edit your saved card details' : 'Add card for future billing'}
|
||||
</Typography>
|
||||
</DialogTitle>
|
||||
<form onSubmit={e => e.preventDefault()}>
|
||||
<DialogContent className='overflow-visible pbs-0 p-6 sm:pli-16'>
|
||||
<Grid container spacing={6}>
|
||||
<Grid size={{ xs: 12 }}>
|
||||
<CustomTextField
|
||||
fullWidth
|
||||
name='number'
|
||||
autoComplete='off'
|
||||
label='Card Number'
|
||||
placeholder='0000 0000 0000 0000'
|
||||
value={cardData.cardNumber}
|
||||
onChange={e => setCardData({ ...cardData, cardNumber: e.target.value })}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid size={{ xs: 12, sm: 6 }}>
|
||||
<CustomTextField
|
||||
fullWidth
|
||||
name='name'
|
||||
label='Name on Card'
|
||||
autoComplete='off'
|
||||
placeholder='John Doe'
|
||||
value={cardData.name}
|
||||
onChange={e => setCardData({ ...cardData, name: e.target.value })}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid size={{ xs: 6, sm: 3 }}>
|
||||
<CustomTextField
|
||||
fullWidth
|
||||
name='expiry'
|
||||
autoComplete='off'
|
||||
label='Expiry'
|
||||
placeholder='MM/YY'
|
||||
value={cardData.expiryDate}
|
||||
onChange={e => setCardData({ ...cardData, expiryDate: e.target.value })}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid size={{ xs: 6, sm: 3 }}>
|
||||
<CustomTextField
|
||||
fullWidth
|
||||
name='cvv'
|
||||
label='CVV'
|
||||
autoComplete='off'
|
||||
placeholder='123'
|
||||
value={cardData.cardCvv}
|
||||
onChange={e => setCardData({ ...cardData, cardCvv: e.target.value })}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid size={{ xs: 12 }}>
|
||||
<FormControlLabel control={<Switch defaultChecked />} label='Save Card for future billing?' />
|
||||
</Grid>
|
||||
</Grid>
|
||||
</DialogContent>
|
||||
<DialogActions className='justify-center pbs-0 p-6 sm:pbe-16 sm:pli-16'>
|
||||
<Button variant='contained' type='submit' onClick={handleClose}>
|
||||
{data ? 'Update' : 'Submit'}
|
||||
</Button>
|
||||
<Button variant='tonal' type='reset' color='secondary' onClick={handleClose}>
|
||||
Cancel
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</form>
|
||||
</Dialog>
|
||||
)
|
||||
}
|
||||
|
||||
export default BillingCard
|
||||
@@ -0,0 +1,139 @@
|
||||
'use client'
|
||||
|
||||
// React Imports
|
||||
import { Fragment, useState } from 'react'
|
||||
|
||||
// MUI Imports
|
||||
import Dialog from '@mui/material/Dialog'
|
||||
import DialogContent from '@mui/material/DialogContent'
|
||||
import DialogActions from '@mui/material/DialogActions'
|
||||
import Typography from '@mui/material/Typography'
|
||||
import Button from '@mui/material/Button'
|
||||
|
||||
// Third-party Imports
|
||||
import classnames from 'classnames'
|
||||
|
||||
type ConfirmationType = 'delete-account' | 'unsubscribe' | 'suspend-account' | 'delete-order' | 'delete-customer'
|
||||
|
||||
type ConfirmationDialogProps = {
|
||||
open: boolean
|
||||
setOpen: (open: boolean) => void
|
||||
type: ConfirmationType
|
||||
}
|
||||
|
||||
const ConfirmationDialog = ({ open, setOpen, type }: ConfirmationDialogProps) => {
|
||||
// States
|
||||
const [secondDialog, setSecondDialog] = useState(false)
|
||||
const [userInput, setUserInput] = useState(false)
|
||||
|
||||
// Vars
|
||||
const Wrapper = type === 'suspend-account' ? 'div' : Fragment
|
||||
|
||||
const handleSecondDialogClose = () => {
|
||||
setSecondDialog(false)
|
||||
setOpen(false)
|
||||
}
|
||||
|
||||
const handleConfirmation = (value: boolean) => {
|
||||
setUserInput(value)
|
||||
setSecondDialog(true)
|
||||
setOpen(false)
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<Dialog fullWidth maxWidth='xs' open={open} onClose={() => setOpen(false)} closeAfterTransition={false}>
|
||||
<DialogContent className='flex items-center flex-col text-center sm:pbs-16 sm:pbe-6 sm:pli-16'>
|
||||
<i className='tabler-alert-circle text-[88px] mbe-6 text-warning' />
|
||||
<Wrapper
|
||||
{...(type === 'suspend-account' && {
|
||||
className: 'flex flex-col items-center gap-2'
|
||||
})}
|
||||
>
|
||||
<Typography variant='h4'>
|
||||
{type === 'delete-account' && 'Are you sure you want to deactivate your account?'}
|
||||
{type === 'unsubscribe' && 'Are you sure to cancel your subscription?'}
|
||||
{type === 'suspend-account' && 'Are you sure?'}
|
||||
{type === 'delete-order' && 'Are you sure?'}
|
||||
{type === 'delete-customer' && 'Are you sure?'}
|
||||
</Typography>
|
||||
{type === 'suspend-account' && (
|
||||
<Typography color='text.primary'>You won't be able to revert user!</Typography>
|
||||
)}
|
||||
{type === 'delete-order' && (
|
||||
<Typography color='text.primary'>You won't be able to revert order!</Typography>
|
||||
)}
|
||||
{type === 'delete-customer' && (
|
||||
<Typography color='text.primary'>You won't be able to revert customer!</Typography>
|
||||
)}
|
||||
</Wrapper>
|
||||
</DialogContent>
|
||||
<DialogActions className='justify-center pbs-0 sm:pbe-16 sm:pli-16'>
|
||||
<Button variant='contained' onClick={() => handleConfirmation(true)}>
|
||||
{type === 'suspend-account'
|
||||
? 'Yes, Suspend User!'
|
||||
: type === 'delete-order'
|
||||
? 'Yes, Delete Order!'
|
||||
: type === 'delete-customer'
|
||||
? 'Yes, Delete Customer!'
|
||||
: 'Yes'}
|
||||
</Button>
|
||||
<Button
|
||||
variant='tonal'
|
||||
color='secondary'
|
||||
onClick={() => {
|
||||
handleConfirmation(false)
|
||||
}}
|
||||
>
|
||||
Cancel
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
|
||||
{/* Delete Account Dialog */}
|
||||
<Dialog open={secondDialog} onClose={handleSecondDialogClose} closeAfterTransition={false}>
|
||||
<DialogContent className='flex items-center flex-col text-center sm:pbs-16 sm:pbe-6 sm:pli-16'>
|
||||
<i
|
||||
className={classnames('text-[88px] mbe-6', {
|
||||
'tabler-circle-check': userInput,
|
||||
'text-success': userInput,
|
||||
'tabler-circle-x': !userInput,
|
||||
'text-error': !userInput
|
||||
})}
|
||||
/>
|
||||
<Typography variant='h4' className='mbe-2'>
|
||||
{userInput
|
||||
? `${type === 'delete-account' ? 'Deactivated' : type === 'unsubscribe' ? 'Unsubscribed' : type === 'delete-order' || 'delete-customer' ? 'Deleted' : 'Suspended!'}`
|
||||
: 'Cancelled'}
|
||||
</Typography>
|
||||
<Typography color='text.primary'>
|
||||
{userInput ? (
|
||||
<>
|
||||
{type === 'delete-account' && 'Your account has been deactivated successfully.'}
|
||||
{type === 'unsubscribe' && 'Your subscription cancelled successfully.'}
|
||||
{type === 'suspend-account' && 'User has been suspended.'}
|
||||
{type === 'delete-order' && 'Your order deleted successfully.'}
|
||||
{type === 'delete-customer' && 'Your customer removed successfully.'}
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
{type === 'delete-account' && 'Account Deactivation Cancelled!'}
|
||||
{type === 'unsubscribe' && 'Unsubscription Cancelled!!'}
|
||||
{type === 'suspend-account' && 'Cancelled Suspension :)'}
|
||||
{type === 'delete-order' && 'Order Deletion Cancelled'}
|
||||
{type === 'delete-customer' && 'Customer Deletion Cancelled'}
|
||||
</>
|
||||
)}
|
||||
</Typography>
|
||||
</DialogContent>
|
||||
<DialogActions className='justify-center pbs-0 sm:pbe-16 sm:pli-16'>
|
||||
<Button variant='contained' color='success' onClick={handleSecondDialogClose}>
|
||||
Ok
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default ConfirmationDialog
|
||||
@@ -0,0 +1,112 @@
|
||||
// React Imports
|
||||
import { useState } from 'react'
|
||||
|
||||
// MUI Imports
|
||||
import Grid from '@mui/material/Grid2'
|
||||
import FormControlLabel from '@mui/material/FormControlLabel'
|
||||
import Switch from '@mui/material/Switch'
|
||||
import Button from '@mui/material/Button'
|
||||
import Typography from '@mui/material/Typography'
|
||||
|
||||
// Component Imports
|
||||
import CustomTextField from '@core/components/mui/TextField'
|
||||
import DirectionalIcon from '@components/DirectionalIcon'
|
||||
|
||||
type Props = {
|
||||
activeStep: number
|
||||
isLastStep: boolean
|
||||
handleNext: () => void
|
||||
handlePrev: () => void
|
||||
}
|
||||
|
||||
const Billing = ({ activeStep, isLastStep, handleNext, handlePrev }: Props) => {
|
||||
// States
|
||||
const [cardData, setCardData] = useState({
|
||||
number: '',
|
||||
name: '',
|
||||
expiry: '',
|
||||
cvv: ''
|
||||
})
|
||||
|
||||
return (
|
||||
<div className='flex flex-col gap-6'>
|
||||
<Typography variant='h5'>Payment Details</Typography>
|
||||
<Grid container spacing={6}>
|
||||
<Grid size={{ xs: 12 }}>
|
||||
<CustomTextField
|
||||
fullWidth
|
||||
name='number'
|
||||
autoComplete='off'
|
||||
label='Card Number'
|
||||
placeholder='0000 0000 0000 0000'
|
||||
value={cardData.number}
|
||||
onChange={e => setCardData({ ...cardData, number: e.target.value })}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid size={{ xs: 12, sm: 6 }}>
|
||||
<CustomTextField
|
||||
fullWidth
|
||||
name='name'
|
||||
label='Name on Card'
|
||||
autoComplete='off'
|
||||
placeholder='John Doe'
|
||||
value={cardData.name}
|
||||
onChange={e => setCardData({ ...cardData, name: e.target.value })}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid size={{ xs: 6, sm: 3 }}>
|
||||
<CustomTextField
|
||||
fullWidth
|
||||
name='expiry'
|
||||
autoComplete='off'
|
||||
label='Expiry'
|
||||
placeholder='MM/YY'
|
||||
value={cardData.expiry}
|
||||
onChange={e => setCardData({ ...cardData, expiry: e.target.value })}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid size={{ xs: 6, sm: 3 }}>
|
||||
<CustomTextField
|
||||
fullWidth
|
||||
name='cvv'
|
||||
label='CVV'
|
||||
autoComplete='off'
|
||||
placeholder='123'
|
||||
value={cardData.cvv}
|
||||
onChange={e => setCardData({ ...cardData, cvv: e.target.value })}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid size={{ xs: 12 }}>
|
||||
<FormControlLabel control={<Switch defaultChecked />} label='Save Card for future billing?' />
|
||||
</Grid>
|
||||
<Grid size={{ xs: 12 }} className='flex items-center justify-between'>
|
||||
<Button
|
||||
variant='tonal'
|
||||
color='secondary'
|
||||
disabled={activeStep === 0}
|
||||
onClick={handlePrev}
|
||||
startIcon={<DirectionalIcon ltrIconClass='tabler-arrow-left' rtlIconClass='tabler-arrow-right' />}
|
||||
>
|
||||
Previous
|
||||
</Button>
|
||||
<Button
|
||||
variant='contained'
|
||||
color={isLastStep ? 'success' : 'primary'}
|
||||
onClick={handleNext}
|
||||
endIcon={
|
||||
isLastStep ? (
|
||||
<i className='tabler-check' />
|
||||
) : (
|
||||
<DirectionalIcon ltrIconClass='tabler-arrow-right' rtlIconClass='tabler-arrow-left' />
|
||||
)
|
||||
}
|
||||
>
|
||||
{isLastStep ? 'Submit' : 'Next'}
|
||||
</Button>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default Billing
|
||||
@@ -0,0 +1,114 @@
|
||||
// React Imports
|
||||
import { useState } from 'react'
|
||||
import type { ChangeEvent } from 'react'
|
||||
|
||||
// MUI Imports
|
||||
import Typography from '@mui/material/Typography'
|
||||
import Radio from '@mui/material/Radio'
|
||||
import Button from '@mui/material/Button'
|
||||
|
||||
// Component Imports
|
||||
import CustomAvatar from '@core/components/mui/Avatar'
|
||||
import CustomTextField from '@core/components/mui/TextField'
|
||||
import DirectionalIcon from '@components/DirectionalIcon'
|
||||
|
||||
// Config Imports
|
||||
import themeConfig from '@configs/themeConfig'
|
||||
|
||||
type Props = {
|
||||
activeStep: number
|
||||
isLastStep: boolean
|
||||
handleNext: () => void
|
||||
handlePrev: () => void
|
||||
}
|
||||
|
||||
const DataBase = ({ activeStep, isLastStep, handleNext, handlePrev }: Props) => {
|
||||
// States
|
||||
const [value, setValue] = useState<string>('firebase')
|
||||
|
||||
const handleChange = (event: ChangeEvent<HTMLInputElement>) => {
|
||||
setValue(event.target.value)
|
||||
}
|
||||
|
||||
return (
|
||||
<div className='flex flex-col gap-6'>
|
||||
<CustomTextField
|
||||
fullWidth
|
||||
label='Database Name'
|
||||
placeholder={`${themeConfig.templateName.toLowerCase().replace(/\s+/g, '_')}_database`}
|
||||
/>
|
||||
<div className='flex flex-col gap-4'>
|
||||
<Typography variant='h5'>Select Database Engine</Typography>
|
||||
<div onClick={() => setValue('firebase')} className='flex items-center justify-between cursor-pointer gap-4'>
|
||||
<div className='flex items-center gap-3'>
|
||||
<CustomAvatar skin='light' color='warning' variant='rounded' size={46}>
|
||||
<img src='/images/logos/firebase.png' alt='firebase' height={30} width={30} />
|
||||
</CustomAvatar>
|
||||
<div className='flex flex-col gap-1'>
|
||||
<Typography color='text.primary' className='font-medium'>
|
||||
Firebase
|
||||
</Typography>
|
||||
<Typography variant='body2'>Cloud Firestore</Typography>
|
||||
</div>
|
||||
</div>
|
||||
<Radio value='firebase' onChange={handleChange} checked={value === 'firebase'} />
|
||||
</div>
|
||||
<div onClick={() => setValue('aws')} className='flex items-center justify-between cursor-pointer gap-4'>
|
||||
<div className='flex items-center gap-3'>
|
||||
<CustomAvatar skin='light' color='secondary' variant='rounded' size={46}>
|
||||
<img src='/images/logos/aws.png' alt='aws' height={30} width={30} />
|
||||
</CustomAvatar>
|
||||
<div className='flex flex-col gap-1'>
|
||||
<Typography color='text.primary' className='font-medium'>
|
||||
AWS
|
||||
</Typography>
|
||||
<Typography variant='body2'>Amazon Fast NoSQL Database</Typography>
|
||||
</div>
|
||||
</div>
|
||||
<Radio value='aws' onChange={handleChange} checked={value === 'aws'} />
|
||||
</div>
|
||||
<div onClick={() => setValue('sql')} className='flex items-center justify-between cursor-pointer gap-4'>
|
||||
<div className='flex items-center gap-3'>
|
||||
<CustomAvatar skin='light' color='info' variant='rounded' size={46}>
|
||||
<i className='tabler-database text-3xl' />
|
||||
</CustomAvatar>
|
||||
<div className='flex flex-col gap-1'>
|
||||
<Typography color='text.primary' className='font-medium'>
|
||||
MySQL
|
||||
</Typography>
|
||||
<Typography variant='body2'>Basic MySQL database</Typography>
|
||||
</div>
|
||||
</div>
|
||||
<Radio value='sql' onChange={handleChange} checked={value === 'sql'} />
|
||||
</div>
|
||||
</div>
|
||||
<div className='flex items-center justify-between'>
|
||||
<Button
|
||||
variant='tonal'
|
||||
color='secondary'
|
||||
disabled={activeStep === 0}
|
||||
onClick={handlePrev}
|
||||
startIcon={<DirectionalIcon ltrIconClass='tabler-arrow-left' rtlIconClass='tabler-arrow-right' />}
|
||||
>
|
||||
Previous
|
||||
</Button>
|
||||
<Button
|
||||
variant='contained'
|
||||
color={isLastStep ? 'success' : 'primary'}
|
||||
onClick={handleNext}
|
||||
endIcon={
|
||||
isLastStep ? (
|
||||
<i className='tabler-check' />
|
||||
) : (
|
||||
<DirectionalIcon ltrIconClass='tabler-arrow-right' rtlIconClass='tabler-arrow-left' />
|
||||
)
|
||||
}
|
||||
>
|
||||
{isLastStep ? 'Submit' : 'Next'}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default DataBase
|
||||
@@ -0,0 +1,110 @@
|
||||
// React Imports
|
||||
import { useState } from 'react'
|
||||
import type { ChangeEvent } from 'react'
|
||||
|
||||
// MUI Imports
|
||||
import Radio from '@mui/material/Radio'
|
||||
import Typography from '@mui/material/Typography'
|
||||
import Button from '@mui/material/Button'
|
||||
|
||||
// Component Imports
|
||||
import CustomAvatar from '@core/components/mui/Avatar'
|
||||
import CustomTextField from '@core/components/mui/TextField'
|
||||
import DirectionalIcon from '@components/DirectionalIcon'
|
||||
|
||||
// Config Imports
|
||||
import themeConfig from '@configs/themeConfig'
|
||||
|
||||
type Props = {
|
||||
activeStep: number
|
||||
isLastStep: boolean
|
||||
handleNext: () => void
|
||||
handlePrev: () => void
|
||||
}
|
||||
|
||||
const Details = ({ activeStep, isLastStep, handleNext, handlePrev }: Props) => {
|
||||
// States
|
||||
const [value, setValue] = useState<string>('crm')
|
||||
|
||||
const handleChange = (event: ChangeEvent<HTMLInputElement>) => {
|
||||
setValue(event.target.value)
|
||||
}
|
||||
|
||||
return (
|
||||
<div className='flex flex-col gap-6'>
|
||||
<CustomTextField fullWidth label='Application Name' placeholder={`${themeConfig.templateName}`} />
|
||||
<div className='flex flex-col gap-4'>
|
||||
<Typography variant='h5'>Category</Typography>
|
||||
<div onClick={() => setValue('crm')} className='flex items-center justify-between cursor-pointer gap-4'>
|
||||
<div className='flex items-center gap-3'>
|
||||
<CustomAvatar skin='light' color='info' variant='rounded' size={46}>
|
||||
<i className='tabler-file-text text-3xl' />
|
||||
</CustomAvatar>
|
||||
<div className='flex flex-col gap-1'>
|
||||
<Typography color='text.primary' className='font-medium'>
|
||||
CRM Application
|
||||
</Typography>
|
||||
<Typography variant='body2'>Scales with any business</Typography>
|
||||
</div>
|
||||
</div>
|
||||
<Radio value='crm' onChange={handleChange} checked={value === 'crm'} />
|
||||
</div>
|
||||
<div onClick={() => setValue('eCommerce')} className='flex items-center justify-between cursor-pointer gap-4'>
|
||||
<div className='flex items-center gap-3'>
|
||||
<CustomAvatar skin='light' color='success' variant='rounded' size={46}>
|
||||
<i className='tabler-shopping-cart text-3xl' />
|
||||
</CustomAvatar>
|
||||
<div className='flex flex-col gap-1'>
|
||||
<Typography color='text.primary' className='font-medium'>
|
||||
eCommerce Platforms
|
||||
</Typography>
|
||||
<Typography variant='body2'>Grow Your Business With App</Typography>
|
||||
</div>
|
||||
</div>
|
||||
<Radio value='eCommerce' onChange={handleChange} checked={value === 'eCommerce'} />
|
||||
</div>
|
||||
<div onClick={() => setValue('learning')} className='flex items-center justify-between cursor-pointer gap-4'>
|
||||
<div className='flex items-center gap-3'>
|
||||
<CustomAvatar skin='light' color='error' variant='rounded' size={46}>
|
||||
<i className='tabler-device-laptop text-3xl' />
|
||||
</CustomAvatar>
|
||||
<div className='flex flex-col gap-1'>
|
||||
<Typography color='text.primary' className='font-medium'>
|
||||
Online Learning platform
|
||||
</Typography>
|
||||
<Typography variant='body2'>Start learning today</Typography>
|
||||
</div>
|
||||
</div>
|
||||
<Radio value='learning' onChange={handleChange} checked={value === 'learning'} />
|
||||
</div>
|
||||
</div>
|
||||
<div className='flex items-center justify-between'>
|
||||
<Button
|
||||
variant='tonal'
|
||||
color='secondary'
|
||||
disabled={activeStep === 0}
|
||||
onClick={handlePrev}
|
||||
startIcon={<DirectionalIcon ltrIconClass='tabler-arrow-left' rtlIconClass='tabler-arrow-right' />}
|
||||
>
|
||||
Previous
|
||||
</Button>
|
||||
<Button
|
||||
variant='contained'
|
||||
color={isLastStep ? 'success' : 'primary'}
|
||||
onClick={handleNext}
|
||||
endIcon={
|
||||
isLastStep ? (
|
||||
<i className='tabler-check' />
|
||||
) : (
|
||||
<DirectionalIcon ltrIconClass='tabler-arrow-right' rtlIconClass='tabler-arrow-left' />
|
||||
)
|
||||
}
|
||||
>
|
||||
{isLastStep ? 'Submit' : 'Next'}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default Details
|
||||
@@ -0,0 +1,120 @@
|
||||
// React Imports
|
||||
import { useState } from 'react'
|
||||
import type { ChangeEvent } from 'react'
|
||||
|
||||
// MUI Imports
|
||||
import Typography from '@mui/material/Typography'
|
||||
import Radio from '@mui/material/Radio'
|
||||
import Button from '@mui/material/Button'
|
||||
|
||||
// Component Imports
|
||||
import CustomAvatar from '@core/components/mui/Avatar'
|
||||
import DirectionalIcon from '@components/DirectionalIcon'
|
||||
|
||||
type Props = {
|
||||
activeStep: number
|
||||
isLastStep: boolean
|
||||
handleNext: () => void
|
||||
handlePrev: () => void
|
||||
}
|
||||
|
||||
const FrameWork = ({ activeStep, isLastStep, handleNext, handlePrev }: Props) => {
|
||||
// States
|
||||
const [value, setValue] = useState<string>('react')
|
||||
|
||||
const handleChange = (event: ChangeEvent<HTMLInputElement>) => {
|
||||
setValue(event.target.value)
|
||||
}
|
||||
|
||||
return (
|
||||
<div className='flex flex-col gap-6'>
|
||||
<div className='flex flex-col gap-4'>
|
||||
<Typography variant='h5'>Select Framework</Typography>
|
||||
<div onClick={() => setValue('react')} className='flex items-center justify-between cursor-pointer gap-4'>
|
||||
<div className='flex items-center gap-3'>
|
||||
<CustomAvatar skin='light' color='info' variant='rounded' size={46}>
|
||||
<img src='/images/logos/react.png' alt='react' height={30} width={30} />
|
||||
</CustomAvatar>
|
||||
<div className='flex flex-col gap-1'>
|
||||
<Typography color='text.primary' className='font-medium'>
|
||||
React Native
|
||||
</Typography>
|
||||
<Typography variant='body2'>Create truly native apps</Typography>
|
||||
</div>
|
||||
</div>
|
||||
<Radio value='react' onChange={handleChange} checked={value === 'react'} />
|
||||
</div>
|
||||
|
||||
<div onClick={() => setValue('angular')} className='flex items-center justify-between cursor-pointer gap-4'>
|
||||
<div className='flex items-center gap-3'>
|
||||
<CustomAvatar skin='light' color='error' variant='rounded' size={46}>
|
||||
<img src='/images/logos/angular.png' alt='angular' height={30} width={30} />
|
||||
</CustomAvatar>
|
||||
<div className='flex flex-col gap-1'>
|
||||
<Typography color='text.primary' className='font-medium'>
|
||||
Angular
|
||||
</Typography>
|
||||
<Typography variant='body2'>Most suited for your application</Typography>
|
||||
</div>
|
||||
</div>
|
||||
<Radio value='angular' onChange={handleChange} checked={value === 'angular'} />
|
||||
</div>
|
||||
<div onClick={() => setValue('vuejs')} className='flex items-center justify-between cursor-pointer gap-4'>
|
||||
<div className='flex items-center gap-3'>
|
||||
<CustomAvatar skin='light' color='success' variant='rounded' size={46}>
|
||||
<img src='/images/logos/vue.png' alt='vue' height={30} width={30} />
|
||||
</CustomAvatar>
|
||||
<div className='flex flex-col gap-1'>
|
||||
<Typography color='text.primary' className='font-medium'>
|
||||
Vue
|
||||
</Typography>
|
||||
<Typography variant='body2'>Progressive Framework</Typography>
|
||||
</div>
|
||||
</div>
|
||||
<Radio value='vuejs' onChange={handleChange} checked={value === 'vuejs'} />
|
||||
</div>
|
||||
<div onClick={() => setValue('laravel')} className='flex items-center justify-between cursor-pointer gap-4'>
|
||||
<div className='flex items-center gap-3'>
|
||||
<CustomAvatar skin='light' color='warning' variant='rounded'>
|
||||
<img src='/images/logos/laravel.png' alt='laravel' height={30} width={30} />
|
||||
</CustomAvatar>
|
||||
<div className='flex flex-col gap-1'>
|
||||
<Typography color='text.primary' className='font-medium'>
|
||||
Laravel
|
||||
</Typography>
|
||||
<Typography variant='body2'>PHP web frameworks</Typography>
|
||||
</div>
|
||||
</div>
|
||||
<Radio value='laravel' onChange={handleChange} checked={value === 'laravel'} />
|
||||
</div>
|
||||
</div>
|
||||
<div className='flex items-center justify-between'>
|
||||
<Button
|
||||
variant='tonal'
|
||||
color='secondary'
|
||||
disabled={activeStep === 0}
|
||||
onClick={handlePrev}
|
||||
startIcon={<DirectionalIcon ltrIconClass='tabler-arrow-left' rtlIconClass='tabler-arrow-right' />}
|
||||
>
|
||||
Previous
|
||||
</Button>
|
||||
<Button
|
||||
variant='contained'
|
||||
color={isLastStep ? 'success' : 'primary'}
|
||||
onClick={handleNext}
|
||||
endIcon={
|
||||
isLastStep ? (
|
||||
<i className='tabler-check' />
|
||||
) : (
|
||||
<DirectionalIcon ltrIconClass='tabler-arrow-right' rtlIconClass='tabler-arrow-left' />
|
||||
)
|
||||
}
|
||||
>
|
||||
{isLastStep ? 'Submit' : 'Next'}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default FrameWork
|
||||
@@ -0,0 +1,54 @@
|
||||
// MUI Imports
|
||||
import Typography from '@mui/material/Typography'
|
||||
import Button from '@mui/material/Button'
|
||||
|
||||
// Component Imports
|
||||
import DirectionalIcon from '@components/DirectionalIcon'
|
||||
|
||||
type Props = {
|
||||
activeStep: number
|
||||
isLastStep: boolean
|
||||
handleNext: () => void
|
||||
handlePrev: () => void
|
||||
}
|
||||
|
||||
const Submit = ({ activeStep, isLastStep, handleNext, handlePrev }: Props) => {
|
||||
return (
|
||||
<div className='flex flex-col gap-6'>
|
||||
<div className='flex flex-col items-center gap-4'>
|
||||
<div className='flex flex-col items-center gap-1'>
|
||||
<Typography variant='h5'>Submit</Typography>
|
||||
<Typography variant='body2'>Submit to kickstart your project.</Typography>
|
||||
</div>
|
||||
<img alt='submit-img' src='/images/illustrations/characters/4.png' height={200} width={176} />
|
||||
</div>
|
||||
<div className='flex items-center justify-between'>
|
||||
<Button
|
||||
variant='tonal'
|
||||
color='secondary'
|
||||
disabled={activeStep === 0}
|
||||
onClick={handlePrev}
|
||||
startIcon={<DirectionalIcon ltrIconClass='tabler-arrow-left' rtlIconClass='tabler-arrow-right' />}
|
||||
>
|
||||
Previous
|
||||
</Button>
|
||||
<Button
|
||||
variant='contained'
|
||||
color={isLastStep ? 'success' : 'primary'}
|
||||
onClick={handleNext}
|
||||
endIcon={
|
||||
isLastStep ? (
|
||||
<i className='tablerr-check' />
|
||||
) : (
|
||||
<DirectionalIcon ltrIconClass='tabler-arrow-right' rtlIconClass='tabler-arrow-left' />
|
||||
)
|
||||
}
|
||||
>
|
||||
{isLastStep ? 'Submit' : 'Next'}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default Submit
|
||||
@@ -0,0 +1,182 @@
|
||||
'use client'
|
||||
|
||||
// React Imports
|
||||
import { useState } from 'react'
|
||||
|
||||
// MUI Imports
|
||||
import { styled } from '@mui/material/styles'
|
||||
import Dialog from '@mui/material/Dialog'
|
||||
import DialogTitle from '@mui/material/DialogTitle'
|
||||
import DialogContent from '@mui/material/DialogContent'
|
||||
import Typography from '@mui/material/Typography'
|
||||
import MuiStep from '@mui/material/Step'
|
||||
import StepLabel from '@mui/material/StepLabel'
|
||||
import Stepper from '@mui/material/Stepper'
|
||||
import type { StepProps } from '@mui/material/Step'
|
||||
|
||||
// Third-party Imports
|
||||
import classnames from 'classnames'
|
||||
|
||||
// Component Imports
|
||||
import Billing from './Billing'
|
||||
import CustomAvatar from '@core/components/mui/Avatar'
|
||||
import Details from './Details'
|
||||
import DialogCloseButton from '../DialogCloseButton'
|
||||
import Database from './Database'
|
||||
import FrameWork from './FrameWork'
|
||||
import Submit from './Submit'
|
||||
|
||||
// Styled Component Imports
|
||||
import StepperWrapper from '@core/styles/stepper'
|
||||
|
||||
type CreateAppProps = {
|
||||
open: boolean
|
||||
setOpen: (open: boolean) => void
|
||||
}
|
||||
|
||||
type stepperProps = {
|
||||
icon: string
|
||||
title: string
|
||||
subtitle: string
|
||||
active?: boolean
|
||||
}
|
||||
|
||||
const steps: stepperProps[] = [
|
||||
{
|
||||
icon: 'tabler-file-text',
|
||||
title: 'Details',
|
||||
subtitle: 'Enter Details'
|
||||
},
|
||||
{
|
||||
icon: 'tabler-id',
|
||||
title: 'FrameWorks',
|
||||
subtitle: 'Select Framework',
|
||||
active: true
|
||||
},
|
||||
{
|
||||
icon: 'tabler-database',
|
||||
title: 'Database',
|
||||
subtitle: 'Select Database'
|
||||
},
|
||||
{
|
||||
icon: 'tabler-credit-card',
|
||||
title: 'Billing',
|
||||
subtitle: 'Payment Details'
|
||||
},
|
||||
{
|
||||
icon: 'tabler-check',
|
||||
title: 'Submit',
|
||||
subtitle: 'Submit'
|
||||
}
|
||||
]
|
||||
|
||||
const Step = styled(MuiStep)<StepProps>({
|
||||
'&.Mui-completed .step-title , &.Mui-completed .step-subtitle': {
|
||||
color: 'var(--mui-palette-text-disabled)'
|
||||
}
|
||||
})
|
||||
|
||||
const renderStepCount = (activeStep: number, isLastStep: boolean, handleNext: () => void, handlePrev: () => void) => {
|
||||
const Tag =
|
||||
activeStep === 0
|
||||
? Details
|
||||
: activeStep === 1
|
||||
? FrameWork
|
||||
: activeStep === 2
|
||||
? Database
|
||||
: activeStep === 3
|
||||
? Billing
|
||||
: Submit
|
||||
|
||||
return <Tag activeStep={activeStep} handleNext={handleNext} handlePrev={handlePrev} isLastStep={isLastStep} />
|
||||
}
|
||||
|
||||
const CreateApp = ({ open, setOpen }: CreateAppProps) => {
|
||||
// States
|
||||
const [activeStep, setActiveStep] = useState(0)
|
||||
|
||||
const handleClose = () => {
|
||||
setOpen(false)
|
||||
setActiveStep(0)
|
||||
}
|
||||
|
||||
const handleStep = (step: number) => () => {
|
||||
setActiveStep(step)
|
||||
}
|
||||
|
||||
// Vars
|
||||
const isLastStep = activeStep === steps.length - 1
|
||||
|
||||
const handleNext = () => {
|
||||
if (!isLastStep) {
|
||||
setActiveStep(prevActiveStep => prevActiveStep + 1)
|
||||
} else {
|
||||
handleClose()
|
||||
}
|
||||
}
|
||||
|
||||
const handlePrev = () => {
|
||||
setActiveStep(prevActiveStep => prevActiveStep - 1)
|
||||
}
|
||||
|
||||
return (
|
||||
<Dialog
|
||||
fullWidth
|
||||
maxWidth='md'
|
||||
open={open}
|
||||
onClose={handleClose}
|
||||
scroll='body'
|
||||
closeAfterTransition={false}
|
||||
sx={{ '& .MuiDialog-paper': { overflow: 'visible' } }}
|
||||
>
|
||||
<DialogCloseButton onClick={() => setOpen(false)} disableRipple>
|
||||
<i className='tabler-x' />
|
||||
</DialogCloseButton>
|
||||
<DialogTitle variant='h4' className='flex gap-2 flex-col text-center sm:pbs-16 sm:pbe-6 sm:pli-16'>
|
||||
Create App
|
||||
<Typography component='span' className='flex flex-col text-center'>
|
||||
Provide data with this form to create your app.
|
||||
</Typography>
|
||||
</DialogTitle>
|
||||
<DialogContent className='pbs-0 sm:pli-16 sm:pbe-16'>
|
||||
<div className='flex gap-y-6 flex-col md:flex-row md:gap-5'>
|
||||
<StepperWrapper>
|
||||
<Stepper
|
||||
activeStep={activeStep}
|
||||
orientation='vertical'
|
||||
connector={<></>}
|
||||
className='flex flex-col gap-4 min-is-[220px]'
|
||||
>
|
||||
{steps.map((label, index) => {
|
||||
return (
|
||||
<Step key={index} onClick={handleStep(index)}>
|
||||
<StepLabel icon={<></>} className='p-1 cursor-pointer'>
|
||||
<div className='step-label'>
|
||||
<CustomAvatar
|
||||
variant='rounded'
|
||||
skin={activeStep === index ? 'filled' : 'light'}
|
||||
{...(activeStep >= index && { color: 'primary' })}
|
||||
{...(activeStep === index && { className: 'shadow-primarySm' })}
|
||||
size={38}
|
||||
>
|
||||
<i className={classnames(label.icon as string, 'text-[22px]')} />
|
||||
</CustomAvatar>
|
||||
<div className='flex flex-col'>
|
||||
<Typography className='uppercase step-title'>{label.title}</Typography>
|
||||
<Typography className='step-subtitle'>{label.subtitle}</Typography>
|
||||
</div>
|
||||
</div>
|
||||
</StepLabel>
|
||||
</Step>
|
||||
)
|
||||
})}
|
||||
</Stepper>
|
||||
</StepperWrapper>
|
||||
<div className='flex-1'>{renderStepCount(activeStep, isLastStep, handleNext, handlePrev)}</div>
|
||||
</div>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
)
|
||||
}
|
||||
|
||||
export default CreateApp
|
||||
@@ -0,0 +1,224 @@
|
||||
'use client'
|
||||
|
||||
// React Imports
|
||||
import { useState } from 'react'
|
||||
|
||||
// MUI Imports
|
||||
import Grid from '@mui/material/Grid2'
|
||||
import Dialog from '@mui/material/Dialog'
|
||||
import Button from '@mui/material/Button'
|
||||
import DialogTitle from '@mui/material/DialogTitle'
|
||||
import DialogContent from '@mui/material/DialogContent'
|
||||
import DialogActions from '@mui/material/DialogActions'
|
||||
import Chip from '@mui/material/Chip'
|
||||
import MenuItem from '@mui/material/MenuItem'
|
||||
import Typography from '@mui/material/Typography'
|
||||
import Switch from '@mui/material/Switch'
|
||||
import { FormControlLabel } from '@mui/material'
|
||||
|
||||
// Component Imports
|
||||
import DialogCloseButton from '../DialogCloseButton'
|
||||
import CustomTextField from '@core/components/mui/TextField'
|
||||
|
||||
type EditUserInfoData = {
|
||||
firstName?: string
|
||||
lastName?: string
|
||||
userName?: string
|
||||
billingEmail?: string
|
||||
status?: string
|
||||
taxId?: string
|
||||
contact?: string
|
||||
language?: string[]
|
||||
country?: string
|
||||
useAsBillingAddress?: boolean
|
||||
}
|
||||
|
||||
type EditUserInfoProps = {
|
||||
open: boolean
|
||||
setOpen: (open: boolean) => void
|
||||
data?: EditUserInfoData
|
||||
}
|
||||
|
||||
const initialData: EditUserInfoProps['data'] = {
|
||||
firstName: 'Oliver',
|
||||
lastName: 'Queen',
|
||||
userName: 'oliverQueen',
|
||||
billingEmail: 'oliverQueen@gmail.com',
|
||||
status: 'active',
|
||||
taxId: 'Tax-8894',
|
||||
contact: '+ 1 609 933 4422',
|
||||
language: ['English'],
|
||||
country: 'US',
|
||||
useAsBillingAddress: true
|
||||
}
|
||||
|
||||
const status = ['Status', 'Active', 'Inactive', 'Suspended']
|
||||
|
||||
const languages = ['English', 'Spanish', 'French', 'German', 'Hindi']
|
||||
|
||||
const countries = ['Select Country', 'France', 'Russia', 'China', 'UK', 'US']
|
||||
|
||||
const EditUserInfo = ({ open, setOpen, data }: EditUserInfoProps) => {
|
||||
// States
|
||||
const [userData, setUserData] = useState<EditUserInfoProps['data']>(data || initialData)
|
||||
|
||||
const handleClose = () => {
|
||||
setOpen(false)
|
||||
setUserData(data || initialData)
|
||||
}
|
||||
|
||||
return (
|
||||
<Dialog
|
||||
fullWidth
|
||||
open={open}
|
||||
onClose={handleClose}
|
||||
maxWidth='md'
|
||||
scroll='body'
|
||||
closeAfterTransition={false}
|
||||
sx={{ '& .MuiDialog-paper': { overflow: 'visible' } }}
|
||||
>
|
||||
<DialogCloseButton onClick={() => setOpen(false)} disableRipple>
|
||||
<i className='tabler-x' />
|
||||
</DialogCloseButton>
|
||||
<DialogTitle variant='h4' className='flex gap-2 flex-col text-center sm:pbs-16 sm:pbe-6 sm:pli-16'>
|
||||
Edit User Information
|
||||
<Typography component='span' className='flex flex-col text-center'>
|
||||
Updating user details will receive a privacy audit.
|
||||
</Typography>
|
||||
</DialogTitle>
|
||||
<form onSubmit={e => e.preventDefault()}>
|
||||
<DialogContent className='overflow-visible pbs-0 sm:pli-16'>
|
||||
<Grid container spacing={5}>
|
||||
<Grid size={{ xs: 12, sm: 6 }}>
|
||||
<CustomTextField
|
||||
fullWidth
|
||||
label='First Name'
|
||||
placeholder='John'
|
||||
value={userData?.firstName}
|
||||
onChange={e => setUserData({ ...userData, firstName: e.target.value })}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid size={{ xs: 12, sm: 6 }}>
|
||||
<CustomTextField
|
||||
fullWidth
|
||||
label='Last Name'
|
||||
placeholder='Doe'
|
||||
value={userData?.lastName}
|
||||
onChange={e => setUserData({ ...userData, lastName: e.target.value })}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid size={{ xs: 12 }}>
|
||||
<CustomTextField
|
||||
fullWidth
|
||||
label='User Name'
|
||||
placeholder='JohnDoe'
|
||||
value={userData?.userName}
|
||||
onChange={e => setUserData({ ...userData, userName: e.target.value })}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid size={{ xs: 12, sm: 6 }}>
|
||||
<CustomTextField
|
||||
fullWidth
|
||||
label='Billing Email'
|
||||
placeholder='johnDoe@email.com'
|
||||
value={userData?.billingEmail}
|
||||
onChange={e => setUserData({ ...userData, billingEmail: e.target.value })}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid size={{ xs: 12, sm: 6 }}>
|
||||
<CustomTextField
|
||||
select
|
||||
fullWidth
|
||||
label='Status'
|
||||
value={userData?.status}
|
||||
onChange={e => setUserData({ ...userData, status: e.target.value as string })}
|
||||
>
|
||||
{status.map((status, index) => (
|
||||
<MenuItem key={index} value={index === 0 ? '' : status.toLowerCase().replace(/\s+/g, '-')}>
|
||||
{status}
|
||||
</MenuItem>
|
||||
))}
|
||||
</CustomTextField>
|
||||
</Grid>
|
||||
<Grid size={{ xs: 12, sm: 6 }}>
|
||||
<CustomTextField
|
||||
fullWidth
|
||||
label='Tax ID'
|
||||
placeholder='Tax-7490'
|
||||
value={userData?.taxId}
|
||||
onChange={e => setUserData({ ...userData, taxId: e.target.value })}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid size={{ xs: 12, sm: 6 }}>
|
||||
<CustomTextField
|
||||
fullWidth
|
||||
label='Contact'
|
||||
placeholder='+ 123 456 7890'
|
||||
value={userData?.contact}
|
||||
onChange={e => setUserData({ ...userData, contact: e.target.value })}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid size={{ xs: 12, sm: 6 }}>
|
||||
<CustomTextField
|
||||
select
|
||||
fullWidth
|
||||
label='Language'
|
||||
value={userData?.language?.map(lang => lang.toLowerCase().replace(/\s+/g, '-')) || []}
|
||||
slotProps={{
|
||||
select: {
|
||||
multiple: true,
|
||||
onChange: e => setUserData({ ...userData, language: e.target.value as string[] }),
|
||||
renderValue: selected => (
|
||||
<div className='flex items-center gap-2'>
|
||||
{(selected as string[]).map(value => (
|
||||
<Chip key={value} label={value} className='capitalize' size='small' />
|
||||
))}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}}
|
||||
>
|
||||
{languages.map((language, index) => (
|
||||
<MenuItem key={index} value={language.toLowerCase().replace(/\s+/g, '-')}>
|
||||
{language}
|
||||
</MenuItem>
|
||||
))}
|
||||
</CustomTextField>
|
||||
</Grid>
|
||||
<Grid size={{ xs: 12, sm: 6 }}>
|
||||
<CustomTextField
|
||||
select
|
||||
fullWidth
|
||||
label='Country'
|
||||
value={userData?.country?.toLowerCase().replace(/\s+/g, '-')}
|
||||
onChange={e => setUserData({ ...userData, country: e.target.value as string })}
|
||||
>
|
||||
{countries.map((country, index) => (
|
||||
<MenuItem key={index} value={index === 0 ? '' : country.toLowerCase().replace(/\s+/g, '-')}>
|
||||
{country}
|
||||
</MenuItem>
|
||||
))}
|
||||
</CustomTextField>
|
||||
</Grid>
|
||||
<Grid size={{ xs: 12 }}>
|
||||
<FormControlLabel
|
||||
control={<Switch defaultChecked={userData?.useAsBillingAddress} />}
|
||||
label='Use as a billing address?'
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</DialogContent>
|
||||
<DialogActions className='justify-center pbs-0 sm:pbe-16 sm:pli-16'>
|
||||
<Button variant='contained' onClick={handleClose} type='submit'>
|
||||
Submit
|
||||
</Button>
|
||||
<Button variant='tonal' color='secondary' type='reset' onClick={handleClose}>
|
||||
Cancel
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</form>
|
||||
</Dialog>
|
||||
)
|
||||
}
|
||||
|
||||
export default EditUserInfo
|
||||
@@ -0,0 +1,122 @@
|
||||
'use client'
|
||||
|
||||
// MUI Imports
|
||||
import Avatar from '@mui/material/Avatar'
|
||||
import Dialog from '@mui/material/Dialog'
|
||||
import DialogContent from '@mui/material/DialogContent'
|
||||
import DialogTitle from '@mui/material/DialogTitle'
|
||||
import Typography from '@mui/material/Typography'
|
||||
import { useColorScheme } from '@mui/material/styles'
|
||||
|
||||
// Third-party Imports
|
||||
import classnames from 'classnames'
|
||||
|
||||
// Component Imports
|
||||
import DialogCloseButton from '../DialogCloseButton'
|
||||
|
||||
type PaymentMethodProps = {
|
||||
open: boolean
|
||||
setOpen: (open: boolean) => void
|
||||
}
|
||||
|
||||
type CardList = {
|
||||
image: string
|
||||
imgWidth: string
|
||||
imgHeight?: string
|
||||
alt: string
|
||||
cardName: string
|
||||
cardType: string
|
||||
}
|
||||
|
||||
const cardList: CardList[] = [
|
||||
{
|
||||
image: '/images/logos/visa.png',
|
||||
imgWidth: '30px',
|
||||
alt: 'visa card',
|
||||
cardName: 'Visa',
|
||||
cardType: 'Credit Card'
|
||||
},
|
||||
{
|
||||
image: '/images/logos/american-express.png',
|
||||
imgWidth: '36px',
|
||||
alt: 'American Express',
|
||||
cardName: 'American Express',
|
||||
cardType: 'Credit Card'
|
||||
},
|
||||
{
|
||||
image: '/images/logos/mastercard.png',
|
||||
imgWidth: '30px',
|
||||
alt: 'Mastercard',
|
||||
cardName: 'Mastercard',
|
||||
cardType: 'Credit Card'
|
||||
},
|
||||
{
|
||||
image: '/images/logos/jcb.png',
|
||||
imgWidth: '21.4px',
|
||||
alt: 'JCB',
|
||||
cardName: 'JCB',
|
||||
cardType: 'Credit Card'
|
||||
},
|
||||
{
|
||||
image: '/images/logos/dinners-club.png',
|
||||
imgWidth: '20px',
|
||||
alt: 'Dinners Club',
|
||||
cardName: 'Dinners Club',
|
||||
cardType: 'Credit Card'
|
||||
}
|
||||
]
|
||||
|
||||
const PaymentMethod = ({ open, setOpen }: PaymentMethodProps) => {
|
||||
// Hooks
|
||||
const { mode } = useColorScheme()
|
||||
|
||||
return (
|
||||
<Dialog
|
||||
fullWidth
|
||||
open={open}
|
||||
onClose={() => setOpen(false)}
|
||||
maxWidth='sm'
|
||||
scroll='body'
|
||||
closeAfterTransition={false}
|
||||
sx={{ '& .MuiDialog-paper': { overflow: 'visible' } }}
|
||||
>
|
||||
<DialogCloseButton onClick={() => setOpen(false)} disableRipple>
|
||||
<i className='tabler-x' />
|
||||
</DialogCloseButton>
|
||||
<DialogTitle variant='h4' className='flex gap-2 flex-col text-center sm:pbs-16 sm:pbe-10 sm:pli-16'>
|
||||
Select Payment Methods
|
||||
<Typography component='span' className='flex flex-col items-center'>
|
||||
Supported payment methods
|
||||
</Typography>
|
||||
</DialogTitle>
|
||||
<DialogContent className='pbs-0 sm:pli-16 sm:pbe-20'>
|
||||
<div>
|
||||
{cardList?.map((card, index) => (
|
||||
<div
|
||||
key={index}
|
||||
className='flex gap-x-4 gap-y-1 flex-col sm:flex-row items-start sm:items-center justify-between first:pbe-4 last:pbs-4 [&:not(:last-child):not(:first-child)]:plb-4 [&:not(:last-child)]:border-be'
|
||||
>
|
||||
<div className='flex items-center gap-4'>
|
||||
<Avatar
|
||||
variant='rounded'
|
||||
className={classnames('is-[50px] bs-[30px]', {
|
||||
'bg-white': mode === 'dark',
|
||||
'bg-actionHover': mode === 'light'
|
||||
})}
|
||||
>
|
||||
<img src={card.image} alt={card.alt} height={card.imgHeight} width={card.imgWidth} />
|
||||
</Avatar>
|
||||
<Typography className='font-medium' color='text.primary'>
|
||||
{card.cardName}
|
||||
</Typography>
|
||||
</div>
|
||||
<Typography className='max-sm:hidden'>{card.cardType}</Typography>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
)
|
||||
}
|
||||
|
||||
export default PaymentMethod
|
||||
@@ -0,0 +1,252 @@
|
||||
'use client'
|
||||
|
||||
// MUI Imports
|
||||
import Avatar from '@mui/material/Avatar'
|
||||
import Dialog from '@mui/material/Dialog'
|
||||
import DialogContent from '@mui/material/DialogContent'
|
||||
import DialogTitle from '@mui/material/DialogTitle'
|
||||
import Typography from '@mui/material/Typography'
|
||||
import { useColorScheme } from '@mui/material/styles'
|
||||
|
||||
// Third-party Imports
|
||||
import classnames from 'classnames'
|
||||
|
||||
// Component Imports
|
||||
import DialogCloseButton from '../DialogCloseButton'
|
||||
|
||||
type PaymentProvidersProps = {
|
||||
open: boolean
|
||||
setOpen: (open: boolean) => void
|
||||
}
|
||||
|
||||
type Image = {
|
||||
src: string
|
||||
alt?: string
|
||||
height?: string
|
||||
width?: string
|
||||
}
|
||||
|
||||
type CardList = {
|
||||
images: Image[]
|
||||
providerName: string
|
||||
}
|
||||
|
||||
const cardList: CardList[] = [
|
||||
{
|
||||
images: [
|
||||
{
|
||||
src: '/images/logos/visa.png',
|
||||
width: '30px'
|
||||
},
|
||||
{
|
||||
src: '/images/logos/mastercard.png',
|
||||
width: '30px'
|
||||
},
|
||||
{
|
||||
src: '/images/logos/american-express.png',
|
||||
width: '36px'
|
||||
},
|
||||
{
|
||||
src: '/images/logos/jcb.png',
|
||||
height: '16px'
|
||||
},
|
||||
{
|
||||
src: '/images/logos/dinners-club.png',
|
||||
height: '16px'
|
||||
}
|
||||
],
|
||||
providerName: 'Adyen'
|
||||
},
|
||||
{
|
||||
images: [
|
||||
{
|
||||
src: '/images/logos/visa.png',
|
||||
width: '30px'
|
||||
},
|
||||
{
|
||||
src: '/images/logos/american-express.png',
|
||||
width: '36px'
|
||||
},
|
||||
{
|
||||
src: '/images/logos/jcb.png',
|
||||
height: '16px'
|
||||
},
|
||||
{
|
||||
src: '/images/logos/dinners-club.png',
|
||||
height: '16px'
|
||||
}
|
||||
],
|
||||
providerName: '2Checkout'
|
||||
},
|
||||
{
|
||||
images: [
|
||||
{
|
||||
src: '/images/logos/visa.png',
|
||||
width: '30px'
|
||||
},
|
||||
{
|
||||
src: '/images/logos/american-express.png',
|
||||
width: '36px'
|
||||
},
|
||||
{
|
||||
src: '/images/logos/mastercard.png',
|
||||
width: '30px'
|
||||
},
|
||||
{
|
||||
src: '/images/logos/jcb.png',
|
||||
height: '16px'
|
||||
}
|
||||
],
|
||||
providerName: 'Airpay'
|
||||
},
|
||||
{
|
||||
images: [
|
||||
{
|
||||
src: '/images/logos/american-express.png',
|
||||
width: '36px'
|
||||
},
|
||||
{
|
||||
src: '/images/logos/jcb.png',
|
||||
height: '16px'
|
||||
},
|
||||
{
|
||||
src: '/images/logos/dinners-club.png',
|
||||
height: '16px'
|
||||
}
|
||||
],
|
||||
providerName: 'Authorize.net'
|
||||
},
|
||||
{
|
||||
images: [
|
||||
{
|
||||
src: '/images/logos/mastercard.png',
|
||||
width: '30px'
|
||||
},
|
||||
{
|
||||
src: '/images/logos/american-express.png',
|
||||
width: '36px'
|
||||
},
|
||||
{
|
||||
src: '/images/logos/jcb.png',
|
||||
height: '16px'
|
||||
}
|
||||
],
|
||||
providerName: 'Bambora'
|
||||
},
|
||||
{
|
||||
images: [
|
||||
{
|
||||
src: '/images/logos/visa.png',
|
||||
width: '30px'
|
||||
},
|
||||
{
|
||||
src: '/images/logos/mastercard.png',
|
||||
width: '30px'
|
||||
},
|
||||
{
|
||||
src: '/images/logos/american-express.png',
|
||||
width: '36px'
|
||||
},
|
||||
{
|
||||
src: '/images/logos/jcb.png',
|
||||
height: '16px'
|
||||
},
|
||||
{
|
||||
src: '/images/logos/dinners-club.png',
|
||||
height: '16px'
|
||||
}
|
||||
],
|
||||
providerName: 'Cayan'
|
||||
},
|
||||
{
|
||||
images: [
|
||||
{
|
||||
src: '/images/logos/visa.png',
|
||||
width: '30px'
|
||||
},
|
||||
{
|
||||
src: '/images/logos/american-express.png',
|
||||
width: '36px'
|
||||
},
|
||||
{
|
||||
src: '/images/logos/jcb.png',
|
||||
height: '16px'
|
||||
},
|
||||
{
|
||||
src: '/images/logos/dinners-club.png',
|
||||
height: '16px'
|
||||
}
|
||||
],
|
||||
providerName: 'Chase Paymentech (Orbital)'
|
||||
},
|
||||
{
|
||||
images: [
|
||||
{
|
||||
src: '/images/logos/visa.png',
|
||||
width: '30px'
|
||||
},
|
||||
{
|
||||
src: '/images/logos/mastercard.png',
|
||||
width: '30px'
|
||||
}
|
||||
],
|
||||
providerName: 'Checkout.com'
|
||||
}
|
||||
]
|
||||
|
||||
const PaymentProviders = ({ open, setOpen }: PaymentProvidersProps) => {
|
||||
// Hooks
|
||||
const { mode } = useColorScheme()
|
||||
|
||||
return (
|
||||
<Dialog
|
||||
fullWidth
|
||||
open={open}
|
||||
onClose={() => setOpen(false)}
|
||||
maxWidth='md'
|
||||
scroll='body'
|
||||
closeAfterTransition={false}
|
||||
sx={{ '& .MuiDialog-paper': { overflow: 'visible' } }}
|
||||
>
|
||||
<DialogCloseButton onClick={() => setOpen(false)} disableRipple>
|
||||
<i className='tabler-x' />
|
||||
</DialogCloseButton>
|
||||
<DialogTitle variant='h4' className='flex gap-2 flex-col text-center sm:pbs-16 sm:pbe-10 sm:pli-16'>
|
||||
Select Payment Providers
|
||||
<Typography component='span' className='flex flex-col text-center'>
|
||||
Third-party payment providers
|
||||
</Typography>
|
||||
</DialogTitle>
|
||||
<DialogContent className='pbs-0 sm:pbe-20 sm:pli-16'>
|
||||
<div>
|
||||
{cardList?.map((card, index) => (
|
||||
<div
|
||||
key={index}
|
||||
className='flex sm:items-center flex-col sm:flex-row items-start justify-between flex-wrap gap-x-4 gap-y-1 first:pbe-4 last:pbs-4 [&:not(:last-child):not(:first-child)]:plb-4 [&:not(:last-child)]:border-be'
|
||||
>
|
||||
<Typography className='font-medium' color='text.primary'>
|
||||
{card.providerName}
|
||||
</Typography>
|
||||
<div className='flex gap-x-4 gap-y-2 flex-wrap'>
|
||||
{card.images.map((image, index) => (
|
||||
<Avatar
|
||||
key={index}
|
||||
variant='rounded'
|
||||
className={classnames('is-[50px] bs-[30px]', {
|
||||
'bg-white': mode === 'dark',
|
||||
'bg-actionHover': mode === 'light'
|
||||
})}
|
||||
>
|
||||
<img src={image.src} alt={image.alt} height={image.height} width={image.width} />
|
||||
</Avatar>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
)
|
||||
}
|
||||
|
||||
export default PaymentProviders
|
||||
@@ -0,0 +1,105 @@
|
||||
// MUI Imports
|
||||
import Dialog from '@mui/material/Dialog'
|
||||
import DialogTitle from '@mui/material/DialogTitle'
|
||||
import DialogContent from '@mui/material/DialogContent'
|
||||
import DialogActions from '@mui/material/DialogActions'
|
||||
import Typography from '@mui/material/Typography'
|
||||
import Button from '@mui/material/Button'
|
||||
import Checkbox from '@mui/material/Checkbox'
|
||||
import FormControlLabel from '@mui/material/FormControlLabel'
|
||||
import Alert from '@mui/material/Alert'
|
||||
import AlertTitle from '@mui/material/AlertTitle'
|
||||
|
||||
// Component Imports
|
||||
import CustomTextField from '@core/components/mui/TextField'
|
||||
import DialogCloseButton from '../DialogCloseButton'
|
||||
|
||||
type PermissionDialogProps = {
|
||||
open: boolean
|
||||
setOpen: (open: boolean) => void
|
||||
data?: string
|
||||
}
|
||||
|
||||
type EditProps = {
|
||||
handleClose: () => void
|
||||
data: string
|
||||
}
|
||||
|
||||
const AddContent = ({ handleClose }: { handleClose: () => void }) => {
|
||||
return (
|
||||
<>
|
||||
<DialogContent className='overflow-visible pbs-0 sm:pli-16'>
|
||||
<CustomTextField
|
||||
fullWidth
|
||||
label='Permission Name'
|
||||
variant='outlined'
|
||||
placeholder='Enter Permission Name'
|
||||
className='mbe-2'
|
||||
/>
|
||||
<FormControlLabel control={<Checkbox />} label='Set as core permission' />
|
||||
</DialogContent>
|
||||
<DialogActions className='flex max-sm:flex-col max-sm:items-center max-sm:gap-2 justify-center pbs-0 sm:pbe-16 sm:pli-16'>
|
||||
<Button type='submit' variant='contained' onClick={handleClose}>
|
||||
Create Permission
|
||||
</Button>
|
||||
<Button onClick={handleClose} variant='tonal' color='secondary' className='max-sm:mis-0'>
|
||||
Discard
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
const EditContent = ({ handleClose, data }: EditProps) => {
|
||||
return (
|
||||
<DialogContent className='overflow-visible pbs-0 sm:pli-16'>
|
||||
<Alert severity='warning' className='mbe-8'>
|
||||
<AlertTitle>Warning!</AlertTitle>
|
||||
By editing the permission name, you might break the system permissions functionality. Please ensure you're
|
||||
absolutely certain before proceeding.
|
||||
</Alert>
|
||||
<div className='flex items-end gap-4 mbe-2'>
|
||||
<CustomTextField
|
||||
fullWidth
|
||||
size='small'
|
||||
defaultValue={data}
|
||||
variant='outlined'
|
||||
label='Permission Name'
|
||||
placeholder='Enter Permission Name'
|
||||
/>
|
||||
<Button variant='contained' onClick={handleClose}>
|
||||
Update
|
||||
</Button>
|
||||
</div>
|
||||
<FormControlLabel control={<Checkbox />} label='Set as core permission' />
|
||||
</DialogContent>
|
||||
)
|
||||
}
|
||||
|
||||
const PermissionDialog = ({ open, setOpen, data }: PermissionDialogProps) => {
|
||||
const handleClose = () => {
|
||||
setOpen(false)
|
||||
}
|
||||
|
||||
return (
|
||||
<Dialog
|
||||
open={open}
|
||||
onClose={handleClose}
|
||||
closeAfterTransition={false}
|
||||
sx={{ '& .MuiDialog-paper': { overflow: 'visible' } }}
|
||||
>
|
||||
<DialogCloseButton onClick={() => setOpen(false)} disableRipple>
|
||||
<i className='tabler-x' />
|
||||
</DialogCloseButton>
|
||||
<DialogTitle variant='h4' className='flex flex-col gap-2 text-center sm:pbs-16 sm:pbe-6 sm:pli-16'>
|
||||
{data ? 'Edit Permission' : 'Add New Permission'}
|
||||
<Typography component='span' className='flex flex-col text-center'>
|
||||
{data ? 'Edit permission as per your requirements.' : 'Permissions you may use and assign to your users.'}
|
||||
</Typography>
|
||||
</DialogTitle>
|
||||
{data ? <EditContent handleClose={handleClose} data={data} /> : <AddContent handleClose={handleClose} />}
|
||||
</Dialog>
|
||||
)
|
||||
}
|
||||
|
||||
export default PermissionDialog
|
||||
@@ -0,0 +1,43 @@
|
||||
'use client'
|
||||
|
||||
// MUI Imports
|
||||
import Dialog from '@mui/material/Dialog'
|
||||
import DialogContent from '@mui/material/DialogContent'
|
||||
|
||||
// Component Imports
|
||||
import DialogCloseButton from '../DialogCloseButton'
|
||||
|
||||
// Type Imports
|
||||
import type { PricingPlanType } from '@/types/pages/pricingTypes'
|
||||
|
||||
// Component Imports
|
||||
import Pricing from '@components/pricing'
|
||||
|
||||
type PricingProps = {
|
||||
open: boolean
|
||||
setOpen: (open: boolean) => void
|
||||
data: PricingPlanType[]
|
||||
}
|
||||
|
||||
const PricingDialog = ({ open, setOpen, data }: PricingProps) => {
|
||||
return (
|
||||
<Dialog
|
||||
fullWidth
|
||||
maxWidth='lg'
|
||||
open={open}
|
||||
onClose={() => setOpen(false)}
|
||||
scroll='body'
|
||||
closeAfterTransition={false}
|
||||
sx={{ '& .MuiDialog-paper': { overflow: 'visible' } }}
|
||||
>
|
||||
<DialogCloseButton onClick={() => setOpen(false)} disableRipple>
|
||||
<i className='tabler-x' />
|
||||
</DialogCloseButton>
|
||||
<DialogContent className='sm:p-16'>
|
||||
<Pricing data={data} />
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
)
|
||||
}
|
||||
|
||||
export default PricingDialog
|
||||
@@ -0,0 +1,161 @@
|
||||
'use client'
|
||||
|
||||
// React Imports
|
||||
import type { ReactNode } from 'react'
|
||||
|
||||
// MUI Imports
|
||||
import Dialog from '@mui/material/Dialog'
|
||||
import DialogTitle from '@mui/material/DialogTitle'
|
||||
import DialogContent from '@mui/material/DialogContent'
|
||||
import Typography from '@mui/material/Typography'
|
||||
import Grid from '@mui/material/Grid2'
|
||||
import Divider from '@mui/material/Divider'
|
||||
import Button from '@mui/material/Button'
|
||||
import InputAdornment from '@mui/material/InputAdornment'
|
||||
|
||||
// Third-party Imports
|
||||
import classnames from 'classnames'
|
||||
|
||||
// Component Imports
|
||||
import CustomIconButton from '@core/components/mui/IconButton'
|
||||
import CustomTextField from '@core/components/mui/TextField'
|
||||
import CustomAvatar from '@core/components/mui/Avatar'
|
||||
import DialogCloseButton from '../DialogCloseButton'
|
||||
import Keyboard from '@/assets/svg/Keyboard'
|
||||
import Paper from '@/assets/svg/Paper'
|
||||
import Rocket from '@/assets/svg/Rocket'
|
||||
|
||||
// Config Imports
|
||||
import themeConfig from '@configs/themeConfig'
|
||||
|
||||
type ReferEarnProps = {
|
||||
open: boolean
|
||||
setOpen: (open: boolean) => void
|
||||
}
|
||||
|
||||
type Options = {
|
||||
icon?: ReactNode
|
||||
title?: string
|
||||
subtitle?: string
|
||||
}
|
||||
|
||||
const options: Options[] = [
|
||||
{
|
||||
icon: <Paper />,
|
||||
title: 'Send Invitation 👍🏻',
|
||||
subtitle: 'Send your referral link to your friend'
|
||||
},
|
||||
{
|
||||
icon: <Keyboard />,
|
||||
title: 'Registration 😎',
|
||||
subtitle: 'Let them register to our services'
|
||||
},
|
||||
{
|
||||
icon: <Rocket />,
|
||||
title: 'Free Trial 🎉',
|
||||
subtitle: 'Your friend will get 30 days free trial'
|
||||
}
|
||||
]
|
||||
|
||||
const ReferEarn = ({ open, setOpen }: ReferEarnProps) => {
|
||||
return (
|
||||
<Dialog
|
||||
fullWidth
|
||||
open={open}
|
||||
onClose={() => setOpen(false)}
|
||||
maxWidth='md'
|
||||
scroll='body'
|
||||
closeAfterTransition={false}
|
||||
sx={{ '& .MuiDialog-paper': { overflow: 'visible' } }}
|
||||
>
|
||||
<DialogCloseButton onClick={() => setOpen(false)} disableRipple>
|
||||
<i className='tabler-x' />
|
||||
</DialogCloseButton>
|
||||
<DialogTitle variant='h4' className='flex gap-2 flex-col text-center sm:pbs-16 sm:pbe-12 sm:pli-16'>
|
||||
Refer & Earn
|
||||
<Typography component='span' className='flex flex-col text-center'>
|
||||
{`Invite your friend to ${themeConfig.templateName}, if they sign up, you and your friend will get 30 days free
|
||||
trial`}
|
||||
</Typography>
|
||||
</DialogTitle>
|
||||
<DialogContent className='flex flex-col gap-6 pbs-0 sm:pli-16 sm:pbe-16'>
|
||||
<Grid container spacing={6}>
|
||||
{options?.map((option, index) => (
|
||||
<Grid size={{ xs: 12, md: 4 }} key={index}>
|
||||
<div className='flex items-center flex-col gap-4'>
|
||||
<CustomAvatar
|
||||
variant='rounded'
|
||||
skin='light'
|
||||
color='primary'
|
||||
className='bs-[66px] is-[66px] sm:bs-[88px] sm:is-[88px]'
|
||||
>
|
||||
{typeof option.icon === 'string' ? (
|
||||
<i className={classnames('text-[32px] sm:text-[40px]', option.icon)} />
|
||||
) : (
|
||||
option.icon
|
||||
)}
|
||||
</CustomAvatar>
|
||||
<div className='flex flex-col gap-2 text-center'>
|
||||
<Typography variant='h5'>{option.title}</Typography>
|
||||
<Typography>{option.subtitle}</Typography>
|
||||
</div>
|
||||
</div>
|
||||
</Grid>
|
||||
))}
|
||||
</Grid>
|
||||
<Divider className='mbs-6' />
|
||||
<div className='flex flex-col gap-6'>
|
||||
<Typography variant='h5'>Invite your friends</Typography>
|
||||
<div className='flex items-end is-full flex-wrap sm:flex-nowrap gap-4'>
|
||||
<CustomTextField
|
||||
fullWidth
|
||||
size='small'
|
||||
id='refer-email'
|
||||
placeholder='johnDoe@email.com'
|
||||
label=' Enter your friend's email address and invite them to join Vuexy 😍'
|
||||
/>
|
||||
<Button variant='contained' className='max-sm:is-full'>
|
||||
Send
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
<div className='flex flex-col gap-6'>
|
||||
<Typography variant='h5'>Share the referral link</Typography>
|
||||
<div className='flex items-end justify-center sm:justify-initial flex-wrap sm:flex-nowrap gap-4'>
|
||||
<CustomTextField
|
||||
fullWidth
|
||||
size='small'
|
||||
id='refer-social'
|
||||
placeholder='http://pixinvent.link'
|
||||
label='You can also copy and send it or share it on your social media. 🚀'
|
||||
slotProps={{
|
||||
input: {
|
||||
endAdornment: (
|
||||
<InputAdornment position='end'>
|
||||
<Button size='small' className='capitalize !text-primary'>
|
||||
Copy Link
|
||||
</Button>
|
||||
</InputAdornment>
|
||||
)
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<div className='flex items-center gap-1'>
|
||||
<CustomIconButton className='rounded text-white bg-facebook'>
|
||||
<i className='tabler-brand-facebook' />
|
||||
</CustomIconButton>
|
||||
<CustomIconButton className='rounded text-white bg-twitter'>
|
||||
<i className='tabler-brand-twitter' />
|
||||
</CustomIconButton>
|
||||
<CustomIconButton className='rounded text-white bg-linkedin'>
|
||||
<i className='tabler-brand-linkedin' />
|
||||
</CustomIconButton>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
)
|
||||
}
|
||||
|
||||
export default ReferEarn
|
||||
@@ -0,0 +1,251 @@
|
||||
'use client'
|
||||
|
||||
// React Imports
|
||||
import { useState, useEffect } from 'react'
|
||||
|
||||
// MUI Imports
|
||||
import Dialog from '@mui/material/Dialog'
|
||||
import DialogTitle from '@mui/material/DialogTitle'
|
||||
import DialogContent from '@mui/material/DialogContent'
|
||||
import Typography from '@mui/material/Typography'
|
||||
import Checkbox from '@mui/material/Checkbox'
|
||||
import FormGroup from '@mui/material/FormGroup'
|
||||
import FormControlLabel from '@mui/material/FormControlLabel'
|
||||
import DialogActions from '@mui/material/DialogActions'
|
||||
import Button from '@mui/material/Button'
|
||||
|
||||
// Component Imports
|
||||
import DialogCloseButton from '../DialogCloseButton'
|
||||
import CustomTextField from '@core/components/mui/TextField'
|
||||
|
||||
// Style Imports
|
||||
import tableStyles from '@core/styles/table.module.css'
|
||||
|
||||
type RoleDialogProps = {
|
||||
open: boolean
|
||||
setOpen: (open: boolean) => void
|
||||
title?: string
|
||||
}
|
||||
|
||||
type DataType =
|
||||
| string
|
||||
| {
|
||||
title: string
|
||||
read?: boolean
|
||||
write?: boolean
|
||||
select?: boolean
|
||||
}
|
||||
|
||||
const defaultData: DataType[] = [
|
||||
'User Management',
|
||||
'Content Management',
|
||||
'Disputes Management',
|
||||
'Database Management',
|
||||
'Financial Management',
|
||||
'Reporting',
|
||||
'API Control',
|
||||
'Repository Management',
|
||||
'Payroll'
|
||||
]
|
||||
|
||||
const RoleDialog = ({ open, setOpen, title }: RoleDialogProps) => {
|
||||
// States
|
||||
const [selectedCheckbox, setSelectedCheckbox] = useState<string[]>(
|
||||
title
|
||||
? [
|
||||
'user-management-read',
|
||||
'user-management-write',
|
||||
'user-management-create',
|
||||
'disputes-management-read',
|
||||
'disputes-management-write',
|
||||
'disputes-management-create'
|
||||
]
|
||||
: []
|
||||
)
|
||||
|
||||
const [isIndeterminateCheckbox, setIsIndeterminateCheckbox] = useState<boolean>(false)
|
||||
|
||||
const handleClose = () => {
|
||||
setOpen(false)
|
||||
}
|
||||
|
||||
const togglePermission = (id: string) => {
|
||||
const arr = selectedCheckbox
|
||||
|
||||
if (selectedCheckbox.includes(id)) {
|
||||
arr.splice(arr.indexOf(id), 1)
|
||||
setSelectedCheckbox([...arr])
|
||||
} else {
|
||||
arr.push(id)
|
||||
setSelectedCheckbox([...arr])
|
||||
}
|
||||
}
|
||||
|
||||
const handleSelectAllCheckbox = () => {
|
||||
if (isIndeterminateCheckbox) {
|
||||
setSelectedCheckbox([])
|
||||
} else {
|
||||
defaultData.forEach(row => {
|
||||
const id = (typeof row === 'string' ? row : row.title).toLowerCase().split(' ').join('-')
|
||||
|
||||
togglePermission(`${id}-read`)
|
||||
togglePermission(`${id}-write`)
|
||||
togglePermission(`${id}-create`)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (selectedCheckbox.length > 0 && selectedCheckbox.length < defaultData.length * 3) {
|
||||
setIsIndeterminateCheckbox(true)
|
||||
} else {
|
||||
setIsIndeterminateCheckbox(false)
|
||||
}
|
||||
}, [selectedCheckbox])
|
||||
|
||||
return (
|
||||
<Dialog
|
||||
fullWidth
|
||||
maxWidth='md'
|
||||
scroll='body'
|
||||
open={open}
|
||||
onClose={handleClose}
|
||||
closeAfterTransition={false}
|
||||
sx={{ '& .MuiDialog-paper': { overflow: 'visible' } }}
|
||||
>
|
||||
<DialogCloseButton onClick={() => setOpen(false)} disableRipple>
|
||||
<i className='tabler-x' />
|
||||
</DialogCloseButton>
|
||||
<DialogTitle variant='h4' className='flex flex-col gap-2 text-center sm:pbs-16 sm:pbe-6 sm:pli-16'>
|
||||
{title ? 'Edit Role' : 'Add Role'}
|
||||
<Typography component='span' className='flex flex-col text-center'>
|
||||
Set Role Permissions
|
||||
</Typography>
|
||||
</DialogTitle>
|
||||
<form onSubmit={e => e.preventDefault()}>
|
||||
<DialogContent className='overflow-visible flex flex-col gap-6 pbs-0 sm:pli-16'>
|
||||
<CustomTextField
|
||||
label='Role Name'
|
||||
variant='outlined'
|
||||
fullWidth
|
||||
placeholder='Enter Role Name'
|
||||
defaultValue={title}
|
||||
onChange={e => e.target.value}
|
||||
/>
|
||||
<Typography variant='h5' className='min-is-[225px]'>
|
||||
Role Permissions
|
||||
</Typography>
|
||||
<div className='overflow-x-auto'>
|
||||
<table className={tableStyles.table}>
|
||||
<tbody>
|
||||
<tr className='border-bs-0'>
|
||||
<th className='pis-0'>
|
||||
<Typography color='text.primary' className='font-medium whitespace-nowrap flex-grow min-is-[225px]'>
|
||||
Administrator Access
|
||||
</Typography>
|
||||
</th>
|
||||
<th className='!text-end pie-0'>
|
||||
<FormControlLabel
|
||||
className='mie-0 capitalize'
|
||||
control={
|
||||
<Checkbox
|
||||
onChange={handleSelectAllCheckbox}
|
||||
indeterminate={isIndeterminateCheckbox}
|
||||
checked={selectedCheckbox.length === defaultData.length * 3}
|
||||
/>
|
||||
}
|
||||
label='Select All'
|
||||
/>
|
||||
</th>
|
||||
</tr>
|
||||
{defaultData.map((item, index) => {
|
||||
const id = (typeof item === 'string' ? item : item.title).toLowerCase().split(' ').join('-')
|
||||
|
||||
return (
|
||||
<tr key={index} className='border-be'>
|
||||
<td className='pis-0'>
|
||||
<Typography
|
||||
className='font-medium whitespace-nowrap flex-grow min-is-[225px]'
|
||||
color='text.primary'
|
||||
>
|
||||
{typeof item === 'object' ? item.title : item}
|
||||
</Typography>
|
||||
</td>
|
||||
<td className='!text-end pie-0'>
|
||||
{typeof item === 'object' ? (
|
||||
<FormGroup className='flex-row justify-end flex-nowrap gap-6'>
|
||||
<FormControlLabel
|
||||
className='mie-0'
|
||||
control={<Checkbox checked={item.read} />}
|
||||
label='Read'
|
||||
/>
|
||||
<FormControlLabel
|
||||
className='mie-0'
|
||||
control={<Checkbox checked={item.write} />}
|
||||
label='Write'
|
||||
/>
|
||||
<FormControlLabel
|
||||
className='mie-0'
|
||||
control={<Checkbox checked={item.select} />}
|
||||
label='Select'
|
||||
/>
|
||||
</FormGroup>
|
||||
) : (
|
||||
<FormGroup className='flex-row justify-end flex-nowrap gap-6'>
|
||||
<FormControlLabel
|
||||
className='mie-0'
|
||||
control={
|
||||
<Checkbox
|
||||
id={`${id}-read`}
|
||||
onChange={() => togglePermission(`${id}-read`)}
|
||||
checked={selectedCheckbox.includes(`${id}-read`)}
|
||||
/>
|
||||
}
|
||||
label='Read'
|
||||
/>
|
||||
<FormControlLabel
|
||||
className='mie-0'
|
||||
control={
|
||||
<Checkbox
|
||||
id={`${id}-write`}
|
||||
onChange={() => togglePermission(`${id}-write`)}
|
||||
checked={selectedCheckbox.includes(`${id}-write`)}
|
||||
/>
|
||||
}
|
||||
label='Write'
|
||||
/>
|
||||
<FormControlLabel
|
||||
className='mie-0'
|
||||
control={
|
||||
<Checkbox
|
||||
id={`${id}-create`}
|
||||
onChange={() => togglePermission(`${id}-create`)}
|
||||
checked={selectedCheckbox.includes(`${id}-create`)}
|
||||
/>
|
||||
}
|
||||
label='Create'
|
||||
/>
|
||||
</FormGroup>
|
||||
)}
|
||||
</td>
|
||||
</tr>
|
||||
)
|
||||
})}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</DialogContent>
|
||||
<DialogActions className='justify-center pbs-0 sm:pbe-16 sm:pli-16'>
|
||||
<Button variant='contained' type='submit' onClick={handleClose}>
|
||||
Submit
|
||||
</Button>
|
||||
<Button variant='tonal' type='reset' color='secondary' onClick={handleClose}>
|
||||
Cancel
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</form>
|
||||
</Dialog>
|
||||
)
|
||||
}
|
||||
|
||||
export default RoleDialog
|
||||
@@ -0,0 +1,253 @@
|
||||
'use client'
|
||||
|
||||
// React Imports
|
||||
import { useState } from 'react'
|
||||
import type { MouseEvent } from 'react'
|
||||
|
||||
// MUI Imports
|
||||
import Dialog from '@mui/material/Dialog'
|
||||
import DialogTitle from '@mui/material/DialogTitle'
|
||||
import DialogContent from '@mui/material/DialogContent'
|
||||
import Button from '@mui/material/Button'
|
||||
import IconButton from '@mui/material/IconButton'
|
||||
import Typography from '@mui/material/Typography'
|
||||
import Avatar from '@mui/material/Avatar'
|
||||
import List from '@mui/material/List'
|
||||
import ListItem from '@mui/material/ListItem'
|
||||
import ListItemAvatar from '@mui/material/ListItemAvatar'
|
||||
import ListItemText from '@mui/material/ListItemText'
|
||||
import Menu from '@mui/material/Menu'
|
||||
import MenuItem from '@mui/material/MenuItem'
|
||||
|
||||
// Component Imports
|
||||
import DialogCloseButton from '../DialogCloseButton'
|
||||
import CustomAutocomplete from '@core/components/mui/Autocomplete'
|
||||
import CustomTextField from '@core/components/mui/TextField'
|
||||
import CustomAvatar from '@core/components/mui/Avatar'
|
||||
|
||||
// Config Imports
|
||||
import themeConfig from '@configs/themeConfig'
|
||||
|
||||
type ShareProjectProps = {
|
||||
open: boolean
|
||||
setOpen: (open: boolean) => void
|
||||
}
|
||||
|
||||
type OptionsType = {
|
||||
avatar: string
|
||||
name: string
|
||||
}
|
||||
|
||||
type DataType = {
|
||||
avatar: string
|
||||
value: string
|
||||
name: string
|
||||
email: string
|
||||
}
|
||||
|
||||
const data: DataType[] = [
|
||||
{
|
||||
avatar: '1.png',
|
||||
value: 'Can Edit',
|
||||
name: 'Lester Palmer',
|
||||
email: 'lester.palmer@gmail.com'
|
||||
},
|
||||
{
|
||||
avatar: '2.png',
|
||||
value: 'Owner',
|
||||
name: 'Mittie Blair',
|
||||
email: 'mittie.blair@gmail.com'
|
||||
},
|
||||
{
|
||||
avatar: '3.png',
|
||||
value: 'Can Comment',
|
||||
name: 'Marvin Wheeler',
|
||||
email: 'marvin.wheeler@gmail.com'
|
||||
},
|
||||
{
|
||||
avatar: '4.png',
|
||||
value: 'Can View',
|
||||
name: 'Nannie Ford',
|
||||
email: 'nannie.ford@gmail.com'
|
||||
},
|
||||
{
|
||||
avatar: '5.png',
|
||||
value: 'Can Edit',
|
||||
name: 'Julian Murphy',
|
||||
email: 'julian.murphy@gmail.com'
|
||||
},
|
||||
{
|
||||
avatar: '6.png',
|
||||
value: 'Can View',
|
||||
name: 'Sophie Gilbert',
|
||||
email: 'sophie.gilbert@gmail.com'
|
||||
},
|
||||
{
|
||||
avatar: '7.png',
|
||||
value: 'Can Comment',
|
||||
name: 'Chris Watkins',
|
||||
email: 'chris.watkins@gmail.com'
|
||||
},
|
||||
{
|
||||
avatar: '8.png',
|
||||
value: 'Can Edit',
|
||||
name: 'Adelaide Nichols',
|
||||
email: 'adelaide.nichols@gmail.com'
|
||||
}
|
||||
]
|
||||
|
||||
const autocompleteOptions: OptionsType[] = [
|
||||
{
|
||||
avatar: '1.png',
|
||||
name: 'Chandler Bing'
|
||||
},
|
||||
{
|
||||
avatar: '2.png',
|
||||
name: 'Rachel Green'
|
||||
},
|
||||
{
|
||||
avatar: '3.png',
|
||||
name: 'Joey Tribbiani'
|
||||
},
|
||||
{
|
||||
avatar: '4.png',
|
||||
name: 'Pheobe Buffay'
|
||||
},
|
||||
{
|
||||
avatar: '5.png',
|
||||
name: 'Ross Geller'
|
||||
},
|
||||
{
|
||||
avatar: '8.png',
|
||||
name: 'Monica Geller'
|
||||
}
|
||||
]
|
||||
|
||||
const ShareProject = ({ open, setOpen }: ShareProjectProps) => {
|
||||
// States
|
||||
const [anchorEl, setAnchorEl] = useState<null | HTMLElement>(null)
|
||||
|
||||
const handleClick = (event: MouseEvent<HTMLButtonElement>) => {
|
||||
setAnchorEl(event.currentTarget)
|
||||
}
|
||||
|
||||
const handleClose = () => {
|
||||
setAnchorEl(null)
|
||||
}
|
||||
|
||||
return (
|
||||
<Dialog
|
||||
fullWidth
|
||||
maxWidth='md'
|
||||
scroll='body'
|
||||
open={open}
|
||||
onClose={() => setOpen(false)}
|
||||
closeAfterTransition={false}
|
||||
sx={{ '& .MuiDialog-paper': { overflow: 'visible' } }}
|
||||
>
|
||||
<DialogCloseButton onClick={() => setOpen(false)} disableRipple>
|
||||
<i className='tabler-x' />
|
||||
</DialogCloseButton>
|
||||
<DialogTitle variant='h4' className='flex gap-2 flex-col text-center sm:pbs-16 sm:pbe-6 sm:pli-16'>
|
||||
Share Project
|
||||
<Typography component='span' className='flex flex-col text-center'>
|
||||
Share project with the team members
|
||||
</Typography>
|
||||
</DialogTitle>
|
||||
<DialogContent className='flex flex-col gap-6 pbs-0 sm:pli-16 sm:pbe-16'>
|
||||
<div className='flex flex-col gap-2'>
|
||||
<CustomAutocomplete
|
||||
fullWidth
|
||||
options={autocompleteOptions || []}
|
||||
slotProps={{ listbox: { component: List } }}
|
||||
id='add-member'
|
||||
getOptionLabel={option => option.name}
|
||||
renderInput={params => (
|
||||
<CustomTextField {...params} size='small' placeholder='Add project members...' label='Add Members' />
|
||||
)}
|
||||
renderOption={(props, option) => {
|
||||
const { key, ...rest } = props
|
||||
|
||||
return (
|
||||
<ListItem key={key} {...rest} sx={{ width: 'calc(100% - 1rem)' }}>
|
||||
<ListItemAvatar>
|
||||
<CustomAvatar src={`/images/avatars/${option.avatar}`} alt={option.name} size={30} />
|
||||
</ListItemAvatar>
|
||||
<ListItemText primary={option.name} />
|
||||
</ListItem>
|
||||
)
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div className='flex flex-col gap-4'>
|
||||
<Typography variant='h5'>{`${data.length} Members`}</Typography>
|
||||
<div className='flex flex-col flex-wrap gap-4'>
|
||||
{data.map((member, index) => (
|
||||
<div key={index} className='flex items-center is-full gap-4'>
|
||||
<Avatar src={`/images/avatars/${member.avatar}`} alt={member.name} />
|
||||
<div className='flex justify-between items-center is-full overflow-hidden'>
|
||||
<div className='flex flex-col items-start overflow-hidden'>
|
||||
<Typography className='truncate is-full' color='text.primary'>
|
||||
{member.name}
|
||||
</Typography>
|
||||
<Typography variant='body2' className='truncate is-full'>
|
||||
{member.email}
|
||||
</Typography>
|
||||
</div>
|
||||
|
||||
<IconButton className='sm:hidden' onClick={handleClick}>
|
||||
<i className='tabler-chevron-down text-base' />
|
||||
</IconButton>
|
||||
|
||||
<Button
|
||||
color='secondary'
|
||||
className='hidden sm:flex'
|
||||
onClick={handleClick}
|
||||
endIcon={<i className='tabler-chevron-down text-base' />}
|
||||
>
|
||||
{member.value}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
<Menu
|
||||
keepMounted
|
||||
anchorEl={anchorEl}
|
||||
onClose={handleClose}
|
||||
open={Boolean(anchorEl)}
|
||||
anchorOrigin={{ vertical: 'bottom', horizontal: 'right' }}
|
||||
transformOrigin={{ vertical: 'top', horizontal: 'right' }}
|
||||
>
|
||||
<MenuItem value='Owner' onClick={handleClose}>
|
||||
Owner
|
||||
</MenuItem>
|
||||
<MenuItem value='Can Edit' onClick={handleClose}>
|
||||
Can Edit
|
||||
</MenuItem>
|
||||
<MenuItem value='Can Comment' onClick={handleClose}>
|
||||
Can Comment
|
||||
</MenuItem>
|
||||
<MenuItem value='Can View' onClick={handleClose}>
|
||||
Can View
|
||||
</MenuItem>
|
||||
</Menu>
|
||||
</div>
|
||||
</div>
|
||||
<div className='flex items-center justify-between flex-wrap gap-4'>
|
||||
<div className='flex items-center flex-grow gap-2'>
|
||||
<i className='tabler-users text-xl' />
|
||||
<Typography
|
||||
color='text.primary'
|
||||
className='font-medium'
|
||||
>{`Public to ${themeConfig.templateName} - Pixinvent`}</Typography>
|
||||
</div>
|
||||
<Button variant='contained' className='flex' startIcon={<i className='tabler-link text-base' />}>
|
||||
Copy Project Link
|
||||
</Button>
|
||||
</div>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
)
|
||||
}
|
||||
|
||||
export default ShareProject
|
||||
@@ -0,0 +1,241 @@
|
||||
'use client'
|
||||
|
||||
// React Imports
|
||||
import { useState } from 'react'
|
||||
import type { ChangeEvent } from 'react'
|
||||
|
||||
// MUI Imports
|
||||
import Dialog from '@mui/material/Dialog'
|
||||
import DialogTitle from '@mui/material/DialogTitle'
|
||||
import DialogActions from '@mui/material/DialogActions'
|
||||
import DialogContent from '@mui/material/DialogContent'
|
||||
import Grid from '@mui/material/Grid2'
|
||||
import Button from '@mui/material/Button'
|
||||
import Typography from '@mui/material/Typography'
|
||||
import Alert from '@mui/material/Alert'
|
||||
import AlertTitle from '@mui/material/AlertTitle'
|
||||
|
||||
// Type Imports
|
||||
import type { CustomInputHorizontalData } from '@core/components/custom-inputs/types'
|
||||
|
||||
// Component Imports
|
||||
import CustomInputHorizontal from '@core/components/custom-inputs/Horizontal'
|
||||
import DialogCloseButton from '../DialogCloseButton'
|
||||
import CustomTextField from '@core/components/mui/TextField'
|
||||
|
||||
type TwoFactorAuthProps = {
|
||||
open: boolean
|
||||
setOpen: (open: boolean) => void
|
||||
}
|
||||
|
||||
const data: CustomInputHorizontalData[] = [
|
||||
{
|
||||
title: (
|
||||
<div className='flex items-top gap-1'>
|
||||
<i className='tabler-settings text-xl shrink-0' />
|
||||
<Typography className='font-medium' color='text.primary'>
|
||||
Authenticator Apps
|
||||
</Typography>
|
||||
</div>
|
||||
),
|
||||
value: 'app',
|
||||
isSelected: true,
|
||||
content: 'Get code from an app like Google Authenticator or Microsoft Authenticator.'
|
||||
},
|
||||
{
|
||||
title: (
|
||||
<div className='flex items-top gap-1'>
|
||||
<i className='tabler-message-2 text-xl' />
|
||||
<Typography className='font-medium' color='text.primary'>
|
||||
SMS
|
||||
</Typography>
|
||||
</div>
|
||||
),
|
||||
value: 'sms',
|
||||
content: 'We will send a code via SMS if you need to use your backup login method.'
|
||||
}
|
||||
]
|
||||
|
||||
const SMSDialog = (handleAuthDialogClose: () => void) => {
|
||||
return (
|
||||
<>
|
||||
<DialogTitle variant='h5' className='flex flex-col gap-2 sm:pbs-16 sm:pbe-6 sm:pli-16'>
|
||||
Verify Your Mobile Number for SMS
|
||||
<Typography component='span' className='flex flex-col'>
|
||||
Enter your mobile phone number with country code and we will send you a verification code.
|
||||
</Typography>
|
||||
</DialogTitle>
|
||||
<DialogContent className='overflow-visible pbs-0 sm:pbe-16 sm:pli-16'>
|
||||
<CustomTextField fullWidth type='number' label='Mobile Number' placeholder='123 456 7890' />
|
||||
</DialogContent>
|
||||
<DialogActions className='pbs-0 sm:pbe-16 sm:pli-16'>
|
||||
<Button variant='tonal' type='reset' color='secondary' onClick={handleAuthDialogClose}>
|
||||
Cancel
|
||||
</Button>
|
||||
<Button
|
||||
color='success'
|
||||
variant='contained'
|
||||
type='submit'
|
||||
endIcon={<i className='tabler-check' />}
|
||||
onClick={handleAuthDialogClose}
|
||||
>
|
||||
Submit
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
const AppDialog = (handleAuthDialogClose: () => void) => {
|
||||
return (
|
||||
<>
|
||||
<DialogTitle variant='h4' className='text-center sm:pbs-16 sm:pbe-6 sm:pli-16'>
|
||||
Add Authenticator App
|
||||
</DialogTitle>
|
||||
<DialogContent className='flex flex-col gap-6 pbs-0 sm:pli-16'>
|
||||
<div className='flex flex-col gap-2'>
|
||||
<Typography variant='h5'>Authenticator Apps</Typography>
|
||||
<Typography>
|
||||
Using an authenticator app like Google Authenticator, Microsoft Authenticator, Authy, or 1Password, scan the
|
||||
QR code. It will generate a 6 digit code for you to enter below.
|
||||
</Typography>
|
||||
</div>
|
||||
<div className='flex justify-center'>
|
||||
<img alt='qr-code' height={150} width={150} src='/images/misc/barcode.png' />
|
||||
</div>
|
||||
<div className='flex flex-col gap-4'>
|
||||
<Alert severity='warning' icon={false}>
|
||||
<AlertTitle>ASDLKNASDA9AHS678dGhASD78AB</AlertTitle>
|
||||
If you having trouble using the QR code, select manual entry on your app
|
||||
</Alert>
|
||||
<CustomTextField fullWidth label='Enter Authentication Code' placeholder='Enter Authentication Code' />
|
||||
</div>
|
||||
</DialogContent>
|
||||
<DialogActions className='pbs-0 sm:pbe-16 sm:pli-16'>
|
||||
<Button variant='tonal' type='reset' color='secondary' onClick={handleAuthDialogClose}>
|
||||
Cancel
|
||||
</Button>
|
||||
<Button
|
||||
color='success'
|
||||
variant='contained'
|
||||
type='submit'
|
||||
endIcon={<i className='tabler-check' />}
|
||||
onClick={handleAuthDialogClose}
|
||||
>
|
||||
Submit
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
const TwoFactorAuth = ({ open, setOpen }: TwoFactorAuthProps) => {
|
||||
// Vars
|
||||
const initialSelectedOption: string = data.filter(item => item.isSelected)[
|
||||
data.filter(item => item.isSelected).length - 1
|
||||
].value
|
||||
|
||||
// States
|
||||
const [authType, setAuthType] = useState<string>(initialSelectedOption)
|
||||
const [showAuthDialog, setShowAuthDialog] = useState<boolean>(false)
|
||||
|
||||
const handleClose = () => {
|
||||
setOpen(false)
|
||||
|
||||
if (authType !== 'app') {
|
||||
setAuthType('app')
|
||||
}
|
||||
}
|
||||
|
||||
const handleAuthDialogClose = () => {
|
||||
setShowAuthDialog(false)
|
||||
setShowAuthDialog(false)
|
||||
|
||||
if (authType !== 'app') {
|
||||
setTimeout(() => {
|
||||
setAuthType('app')
|
||||
}, 250)
|
||||
}
|
||||
}
|
||||
|
||||
const handleOptionChange = (prop: string | ChangeEvent<HTMLInputElement>) => {
|
||||
if (typeof prop === 'string') {
|
||||
setAuthType(prop)
|
||||
} else {
|
||||
setAuthType((prop.target as HTMLInputElement).value)
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<Dialog
|
||||
fullWidth
|
||||
maxWidth='md'
|
||||
scroll='body'
|
||||
open={open}
|
||||
onClose={() => setOpen(false)}
|
||||
closeAfterTransition={false}
|
||||
sx={{ '& .MuiDialog-paper': { overflow: 'visible' } }}
|
||||
>
|
||||
<DialogCloseButton onClick={handleClose} disableRipple>
|
||||
<i className='tabler-x' />
|
||||
</DialogCloseButton>
|
||||
<DialogTitle variant='h4' className='flex gap-2 flex-col text-center sm:pbs-16 sm:pbe-6 sm:pli-16'>
|
||||
Select Authentication Method
|
||||
<Typography component='span' className='flex flex-col text-center'>
|
||||
You also need to select a method by which the proxy authenticates to the directory serve.
|
||||
</Typography>
|
||||
</DialogTitle>
|
||||
<DialogContent className='pbs-0 sm:pli-16'>
|
||||
<Grid container spacing={6}>
|
||||
{data.map((item, index) => (
|
||||
<CustomInputHorizontal
|
||||
type='radio'
|
||||
key={index}
|
||||
selected={authType}
|
||||
handleChange={handleOptionChange}
|
||||
data={item}
|
||||
gridProps={{ size: { xs: 12 } }}
|
||||
name='auth-method'
|
||||
/>
|
||||
))}
|
||||
</Grid>
|
||||
</DialogContent>
|
||||
<DialogActions className='pbs-0 sm:pbe-16 sm:pli-16 flex justify-center'>
|
||||
<Button
|
||||
variant='contained'
|
||||
onClick={() => {
|
||||
setOpen(false)
|
||||
setShowAuthDialog(true)
|
||||
}}
|
||||
className='capitalize'
|
||||
>
|
||||
Continue
|
||||
</Button>
|
||||
<Button variant='tonal' color='secondary' onClick={handleClose} className='capitalize'>
|
||||
Cancel
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
|
||||
<Dialog
|
||||
fullWidth
|
||||
maxWidth='md'
|
||||
scroll='body'
|
||||
open={showAuthDialog}
|
||||
onClose={handleAuthDialogClose}
|
||||
closeAfterTransition={false}
|
||||
sx={{ '& .MuiDialog-paper': { overflow: 'visible' } }}
|
||||
>
|
||||
<DialogCloseButton onClick={handleAuthDialogClose} disableRipple>
|
||||
<i className='tabler-x' />
|
||||
</DialogCloseButton>
|
||||
<form onSubmit={e => e.preventDefault()}>
|
||||
{authType === 'sms' ? SMSDialog(handleAuthDialogClose) : AppDialog(handleAuthDialogClose)}
|
||||
</form>
|
||||
</Dialog>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default TwoFactorAuth
|
||||
@@ -0,0 +1,92 @@
|
||||
'use client'
|
||||
|
||||
// React Imports
|
||||
import { useState } from 'react'
|
||||
|
||||
// MUI Imports
|
||||
import Dialog from '@mui/material/Dialog'
|
||||
import DialogTitle from '@mui/material/DialogTitle'
|
||||
import DialogContent from '@mui/material/DialogContent'
|
||||
import Button from '@mui/material/Button'
|
||||
import Typography from '@mui/material/Typography'
|
||||
import MenuItem from '@mui/material/MenuItem'
|
||||
import Divider from '@mui/material/Divider'
|
||||
|
||||
// Style Imports
|
||||
import ConfirmationDialog from '../confirmation-dialog'
|
||||
|
||||
//Component Imports
|
||||
import CustomTextField from '@core/components/mui/TextField'
|
||||
import DialogCloseButton from '../DialogCloseButton'
|
||||
|
||||
type UpgradePlanProps = {
|
||||
open: boolean
|
||||
setOpen: (open: boolean) => void
|
||||
}
|
||||
|
||||
const UpgradePlan = ({ open, setOpen }: UpgradePlanProps) => {
|
||||
// States
|
||||
const [openConfirmation, setOpenConfirmation] = useState(false)
|
||||
|
||||
const handleClose = () => {
|
||||
setOpen(false)
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<Dialog
|
||||
fullWidth
|
||||
open={open}
|
||||
onClose={handleClose}
|
||||
closeAfterTransition={false}
|
||||
sx={{ '& .MuiDialog-paper': { overflow: 'visible' } }}
|
||||
>
|
||||
<DialogCloseButton onClick={() => setOpen(false)} disableRipple>
|
||||
<i className='tabler-x' />
|
||||
</DialogCloseButton>
|
||||
<DialogTitle variant='h4' className='flex flex-col gap-2 text-center sm:pbs-16 sm:pbe-6 sm:pli-16'>
|
||||
Upgrade Plan
|
||||
<Typography component='span' className='flex flex-col text-center'>
|
||||
Choose the best plan for user
|
||||
</Typography>
|
||||
</DialogTitle>
|
||||
<DialogContent className='overflow-visible pbs-0 sm:pli-16 sm:pbe-16'>
|
||||
<div className='flex items-end gap-4 flex-col sm:flex-row'>
|
||||
<CustomTextField select fullWidth label='Choose Plan' defaultValue='Standard' id='user-view-plans-select'>
|
||||
<MenuItem value='Basic'>Basic - $0/month</MenuItem>
|
||||
<MenuItem value='Standard'>Standard - $99/month</MenuItem>
|
||||
<MenuItem value='Enterprise'>Enterprise - $499/month</MenuItem>
|
||||
<MenuItem value='Company'>Company - $999/month</MenuItem>
|
||||
</CustomTextField>
|
||||
<Button variant='contained' className='capitalize max-sm:is-full'>
|
||||
Upgrade
|
||||
</Button>
|
||||
</div>
|
||||
<Divider className='mlb-6' />
|
||||
<div className='flex flex-col gap-1'>
|
||||
<Typography variant='body2'>User current plan is standard plan</Typography>
|
||||
<div className='flex items-center justify-between flex-wrap gap-2'>
|
||||
<div className='flex justify-center items-baseline gap-1'>
|
||||
<Typography component='sup' className='self-start mbs-3' color='primary.main'>
|
||||
$
|
||||
</Typography>
|
||||
<Typography component='span' color='primary.main' variant='h1'>
|
||||
99
|
||||
</Typography>
|
||||
<Typography variant='body2' component='sub' className='self-baseline'>
|
||||
/month
|
||||
</Typography>
|
||||
</div>
|
||||
<Button variant='tonal' className='capitalize' color='error' onClick={() => setOpenConfirmation(true)}>
|
||||
Cancel Subscription
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
<ConfirmationDialog open={openConfirmation} setOpen={setOpenConfirmation} type='unsubscribe' />
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default UpgradePlan
|
||||
Reference in New Issue
Block a user