initial commit

This commit is contained in:
ferdiansyah783
2025-08-05 12:35:40 +07:00
commit fffa2ead5c
1069 changed files with 118056 additions and 0 deletions
@@ -0,0 +1,79 @@
'use client'
// React Imports
import { useState } from 'react'
// MUI Imports
import Card from '@mui/material/Card'
import Grid from '@mui/material/Grid2'
import Button from '@mui/material/Button'
import Typography from '@mui/material/Typography'
import Checkbox from '@mui/material/Checkbox'
import CardHeader from '@mui/material/CardHeader'
import CardContent from '@mui/material/CardContent'
import FormControlLabel from '@mui/material/FormControlLabel'
import InputAdornment from '@mui/material/InputAdornment'
import IconButton from '@mui/material/IconButton'
// Components Imports
import CustomTextField from '@core/components/mui/TextField'
const FormLayoutsAlignment = () => {
// States
const [isPasswordShown, setIsPasswordShown] = useState(false)
const handleClickShowPassword = () => setIsPasswordShown(show => !show)
return (
<Card>
<CardHeader title='Form Alignment' />
<CardContent className='flex flex-col items-center justify-center bs-[500px]'>
<form onSubmit={e => e.preventDefault()} className='p-12 max-is-[400px] border rounded'>
<Grid container spacing={6}>
<Grid size={{ xs: 12 }}>
<Typography variant='h5'>Sign In</Typography>
</Grid>
<Grid size={{ xs: 12 }}>
<CustomTextField fullWidth label='Username' placeholder='johnDoe ' />
</Grid>
<Grid size={{ xs: 12 }}>
<CustomTextField
fullWidth
label='Password'
placeholder='············'
id='form-layout-alignment-password'
type={isPasswordShown ? 'text' : 'password'}
slotProps={{
input: {
endAdornment: (
<InputAdornment position='end'>
<IconButton
edge='end'
onClick={handleClickShowPassword}
onMouseDown={e => e.preventDefault()}
aria-label='toggle password visibility'
>
<i className={isPasswordShown ? 'tabler-eye-off' : 'tabler-eye'} />
</IconButton>
</InputAdornment>
)
}
}}
/>
</Grid>
<Grid size={{ xs: 12 }} className='pbs-2'>
<FormControlLabel control={<Checkbox />} label='Remember me' />
</Grid>
<Grid size={{ xs: 12 }} className='pbs-2'>
<Button variant='contained' type='submit' fullWidth>
Log In
</Button>
</Grid>
</Grid>
</form>
</CardContent>
</Card>
)
}
export default FormLayoutsAlignment
@@ -0,0 +1,121 @@
'use client'
// React Imports
import { useState } from 'react'
// Next Imports
import Link from 'next/link'
// MUI Imports
import Card from '@mui/material/Card'
import Grid from '@mui/material/Grid2'
import Button from '@mui/material/Button'
import Typography from '@mui/material/Typography'
import CardHeader from '@mui/material/CardHeader'
import CardContent from '@mui/material/CardContent'
import IconButton from '@mui/material/IconButton'
import InputAdornment from '@mui/material/InputAdornment'
// Components Imports
import CustomTextField from '@core/components/mui/TextField'
const FormLayoutsBasic = () => {
// States
const [isPasswordShown, setIsPasswordShown] = useState(false)
const [isConfirmPasswordShown, setIsConfirmPasswordShown] = useState(false)
const handleClickShowPassword = () => setIsPasswordShown(show => !show)
const handleClickShowConfirmPassword = () => setIsConfirmPasswordShown(show => !show)
return (
<Card>
<CardHeader title='Basic' />
<CardContent>
<form onSubmit={e => e.preventDefault()}>
<Grid container spacing={6}>
<Grid size={{ xs: 12 }}>
<CustomTextField fullWidth label='Name' placeholder='John Doe' />
</Grid>
<Grid size={{ xs: 12 }}>
<CustomTextField
fullWidth
type='email'
label='Email'
placeholder='johndoe@gmail.com'
helperText='You can use letters, numbers & periods'
/>
</Grid>
<Grid size={{ xs: 12 }}>
<CustomTextField
fullWidth
label='Password'
placeholder='············'
id='form-layout-basic-password'
type={isPasswordShown ? 'text' : 'password'}
helperText='Use 8 or more characters with a mix of letters, numbers & symbols'
slotProps={{
input: {
endAdornment: (
<InputAdornment position='end'>
<IconButton
edge='end'
onClick={handleClickShowPassword}
onMouseDown={e => e.preventDefault()}
aria-label='toggle password visibility'
>
<i className={isPasswordShown ? 'tabler-eye-off' : 'tabler-eye'} />
</IconButton>
</InputAdornment>
)
}
}}
/>
</Grid>
<Grid size={{ xs: 12 }}>
<CustomTextField
fullWidth
label='Confirm Password'
placeholder='············'
id='form-layout-basic-confirm-password'
type={isConfirmPasswordShown ? 'text' : 'password'}
helperText='Make sure to type the same password as above'
slotProps={{
input: {
endAdornment: (
<InputAdornment position='end'>
<IconButton
edge='end'
onClick={handleClickShowConfirmPassword}
onMouseDown={e => e.preventDefault()}
aria-label='toggle confirm password visibility'
>
<i className={isConfirmPasswordShown ? 'tabler-eye-off' : 'tabler-eye'} />
</IconButton>
</InputAdornment>
)
}
}}
/>
</Grid>
<Grid size={{ xs: 12 }}>
<div className='flex items-center justify-between flex-wrap gap-5'>
<Button variant='contained' type='submit'>
Get Started!
</Button>
<div className='flex items-center justify-center gap-2'>
<Typography>Already have an account?</Typography>
<Link href='/' onClick={e => e.preventDefault()} className='text-primary'>
Log In
</Link>
</div>
</div>
</Grid>
</Grid>
</form>
</CardContent>
</Card>
)
}
export default FormLayoutsBasic
@@ -0,0 +1,332 @@
'use client'
// React Imports
import { useState } from 'react'
import type { ChangeEvent, SyntheticEvent } from 'react'
// MUI Imports
import Grid from '@mui/material/Grid2'
import Button from '@mui/material/Button'
import Accordion from '@mui/material/Accordion'
import Radio from '@mui/material/Radio'
import MenuItem from '@mui/material/MenuItem'
import Divider from '@mui/material/Divider'
import FormLabel from '@mui/material/FormLabel'
import FormControlLabel from '@mui/material/FormControlLabel'
import RadioGroup from '@mui/material/RadioGroup'
import Typography from '@mui/material/Typography'
import AccordionSummary from '@mui/material/AccordionSummary'
import AccordionDetails from '@mui/material/AccordionDetails'
// Type Imports
import type { CustomInputHorizontalData } from '@core/components/custom-inputs/types'
// Component Imports
import CustomInputHorizontal from '@core/components/custom-inputs/Horizontal'
import CustomTextField from '@core/components/mui/TextField'
type FormData = {
fullName: string
phone: string
address: string
zipCode: string
landmark: string
city: string
country: string
addressType: string
number: string
name: string
expiry: string
cvv: string
}
// Vars
const data: CustomInputHorizontalData[] = [
{
title: 'Standard 3-5 Days',
meta: 'Free',
content: 'Friday, 15 Nov - Monday, 18 Nov',
isSelected: true,
value: 'standard'
},
{
title: 'Express',
meta: '$5.00',
content: 'Friday, 15 Nov - Sunday, 17 Nov',
value: 'express'
},
{
title: 'Overnight',
meta: '$10.00',
content: 'Friday, 15 Nov - Saturday, 16 Nov',
value: 'overnight'
}
]
const FormLayoutsCollapsible = () => {
// Vars
const initialSelectedOption: string = data.filter(item => item.isSelected)[
data.filter(item => item.isSelected).length - 1
].value
// States
const [expanded, setExpanded] = useState<string | false>('panel1')
const [paymentMethod, setPaymentMethod] = useState('credit')
const [selectedOption, setSelectedOption] = useState<string>(initialSelectedOption)
const [cardData, setCardData] = useState<FormData>({
fullName: '',
phone: '',
address: '',
zipCode: '',
landmark: '',
city: '',
country: '',
addressType: 'home',
number: '',
name: '',
expiry: '',
cvv: ''
})
const handleExpandChange = (panel: string) => (event: SyntheticEvent, isExpanded: boolean) => {
setExpanded(isExpanded ? panel : false)
}
const handleOptionChange = (prop: string | ChangeEvent<HTMLInputElement>) => {
if (typeof prop === 'string') {
setSelectedOption(prop)
} else {
setSelectedOption((prop.target as HTMLInputElement).value)
}
}
const handleReset = () => {
setCardData({
fullName: '',
phone: '',
address: '',
zipCode: '',
landmark: '',
city: '',
country: '',
addressType: '',
number: '',
name: '',
expiry: '',
cvv: ''
})
}
return (
<form onSubmit={e => e.preventDefault()}>
<Accordion expanded={expanded === 'panel1'} onChange={handleExpandChange('panel1')}>
<AccordionSummary expandIcon={<i className='tabler-chevron-right' />}>
<Typography>Delivery Address</Typography>
</AccordionSummary>
<Divider />
<AccordionDetails className='!pbs-6'>
<Grid container spacing={6}>
<Grid size={{ xs: 12, sm: 6 }}>
<CustomTextField
fullWidth
label='Full Name'
placeholder='John Doe'
value={cardData.fullName}
onChange={e => setCardData({ ...cardData, fullName: e.target.value })}
/>
</Grid>
<Grid size={{ xs: 12, sm: 6 }}>
<CustomTextField
fullWidth
label='Phone No.'
placeholder='123-456-7890'
value={cardData.phone}
onChange={e => setCardData({ ...cardData, phone: e.target.value })}
/>
</Grid>
<Grid size={{ xs: 12 }}>
<CustomTextField
fullWidth
rows={4}
multiline
label='Address'
placeholder='1456, Liberty Street'
value={cardData.address}
onChange={e => setCardData({ ...cardData, address: e.target.value })}
/>
</Grid>
<Grid size={{ xs: 12, sm: 6 }}>
<CustomTextField
fullWidth
type='number'
label='ZIP Code'
placeholder='10005'
value={cardData.zipCode}
onChange={e => setCardData({ ...cardData, zipCode: e.target.value })}
/>
</Grid>
<Grid size={{ xs: 12, sm: 6 }}>
<CustomTextField
fullWidth
label='Landmark'
placeholder='Nr Wall Street'
value={cardData.landmark}
onChange={e => setCardData({ ...cardData, landmark: e.target.value })}
/>
</Grid>
<Grid size={{ xs: 12, sm: 6 }}>
<CustomTextField
fullWidth
label='City'
placeholder='New York'
value={cardData.city}
onChange={e => setCardData({ ...cardData, city: e.target.value })}
/>
</Grid>
<Grid size={{ xs: 12, sm: 6 }}>
<CustomTextField
select
fullWidth
label='Country'
value={cardData.country}
onChange={e => setCardData({ ...cardData, country: e.target.value })}
>
<MenuItem value=''>Select Country</MenuItem>
<MenuItem value='UK'>UK</MenuItem>
<MenuItem value='USA'>USA</MenuItem>
<MenuItem value='Australia'>Australia</MenuItem>
<MenuItem value='Germany'>Germany</MenuItem>
</CustomTextField>
</Grid>
<Grid size={{ xs: 12 }}>
<FormLabel>Address Type</FormLabel>
<RadioGroup
row
name='radio-buttons-group'
value={cardData.addressType}
onChange={e => setCardData({ ...cardData, addressType: e.target.value })}
>
<FormControlLabel value='home' control={<Radio />} label='Home (All day delivery)' />
<FormControlLabel value='office' control={<Radio />} label='Office (Delivery between 10 AM - 5 PM)' />
</RadioGroup>
</Grid>
</Grid>
</AccordionDetails>
</Accordion>
<Accordion expanded={expanded === 'panel2'} onChange={handleExpandChange('panel2')}>
<AccordionSummary expandIcon={<i className='tabler-chevron-right' />}>
<Typography>Delivery Options</Typography>
</AccordionSummary>
<Divider />
<AccordionDetails className='!pbs-6'>
<Grid container>
{data.map((item, index) => (
<CustomInputHorizontal
type='radio'
key={index}
data={item}
gridProps={{
size: { xs: 12 },
className:
'[&:first-of-type>*]:rounded-be-none [&:last-of-type>*]:rounded-bs-none [&:nth-of-type(2)>*]:rounded-none'
}}
selected={selectedOption}
name='custom-radios-basic'
handleChange={handleOptionChange}
/>
))}
</Grid>
</AccordionDetails>
</Accordion>
<Accordion expanded={expanded === 'panel3'} onChange={handleExpandChange('panel3')}>
<AccordionSummary expandIcon={<i className='tabler-chevron-right' />}>
<Typography>Payment Method</Typography>
</AccordionSummary>
<Divider />
<AccordionDetails className='!pbs-6'>
<Grid container spacing={6}>
<Grid size={{ xs: 12, md: 6 }}>
<Grid container spacing={6}>
<Grid size={{ xs: 12 }}>
<RadioGroup
row
name='payment-method-radio'
value={paymentMethod}
onChange={e => setPaymentMethod(e.target.value)}
>
<FormControlLabel value='credit' control={<Radio />} label='Credit/Debit/ATM Card' />
<FormControlLabel value='cash' control={<Radio />} label='Cash on Delivery' />
</RadioGroup>
</Grid>
{paymentMethod === 'credit' ? (
<Grid size={{ xs: 12 }}>
<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 }}>
<CustomTextField
fullWidth
name='name'
label='Name'
autoComplete='off'
placeholder='John Doe'
value={cardData.name}
onChange={e => setCardData({ ...cardData, name: e.target.value })}
/>
</Grid>
<Grid size={{ xs: 6 }}>
<CustomTextField
fullWidth
name='expiry'
autoComplete='off'
label='Expiry Date'
placeholder='MM/YY'
value={cardData.expiry}
onChange={e => setCardData({ ...cardData, expiry: e.target.value })}
/>
</Grid>
<Grid size={{ xs: 6 }}>
<CustomTextField
fullWidth
name='cvv'
label='CVV Code'
autoComplete='off'
placeholder='123'
value={cardData.cvv}
onChange={e => setCardData({ ...cardData, cvv: e.target.value })}
/>
</Grid>
</Grid>
</Grid>
) : null}
</Grid>
</Grid>
</Grid>
</AccordionDetails>
<Divider />
<AccordionDetails className='flex gap-4 pbs-6'>
<Button type='submit' variant='contained'>
Place Order
</Button>
<Button type='reset' variant='tonal' color='secondary' onClick={() => handleReset()}>
Reset
</Button>
</AccordionDetails>
</Accordion>
</form>
)
}
export default FormLayoutsCollapsible
@@ -0,0 +1,100 @@
// MUI Imports
import Card from '@mui/material/Card'
import Grid from '@mui/material/Grid2'
import Button from '@mui/material/Button'
import CardHeader from '@mui/material/CardHeader'
import CardContent from '@mui/material/CardContent'
import InputAdornment from '@mui/material/InputAdornment'
// Components Imports
import CustomTextField from '@core/components/mui/TextField'
import Form from '@components/Form'
const FormLayoutsWithIcon = () => {
return (
<Card>
<CardHeader title='Basic with Icons' />
<CardContent>
<Form>
<Grid container spacing={6}>
<Grid size={{ xs: 12 }}>
<CustomTextField
fullWidth
label='Name'
placeholder='John Doe'
slotProps={{
input: {
startAdornment: (
<InputAdornment position='start'>
<i className='tabler-user' />
</InputAdornment>
)
}
}}
/>
</Grid>
<Grid size={{ xs: 12 }}>
<CustomTextField
fullWidth
type='email'
label='Email'
placeholder='johndoe@gmail.com'
slotProps={{
input: {
startAdornment: (
<InputAdornment position='start'>
<i className='tabler-mail' />
</InputAdornment>
)
}
}}
/>
</Grid>
<Grid size={{ xs: 12 }}>
<CustomTextField
fullWidth
label='Phone No.'
placeholder='123-456-7890'
slotProps={{
input: {
startAdornment: (
<InputAdornment position='start'>
<i className='tabler-phone' />
</InputAdornment>
)
}
}}
/>
</Grid>
<Grid size={{ xs: 12 }}>
<CustomTextField
fullWidth
rows={4}
multiline
label='Message'
placeholder='Bio...'
sx={{ '& .MuiInputBase-root.MuiFilledInput-root': { alignItems: 'baseline' } }}
slotProps={{
input: {
startAdornment: (
<InputAdornment position='start'>
<i className='tabler-message' />
</InputAdornment>
)
}
}}
/>
</Grid>
<Grid size={{ xs: 12 }}>
<Button variant='contained' type='submit'>
Submit
</Button>
</Grid>
</Grid>
</Form>
</CardContent>
</Card>
)
}
export default FormLayoutsWithIcon
@@ -0,0 +1,270 @@
'use client'
// React Imports
import { useState } from 'react'
// MUI Imports
import Card from '@mui/material/Card'
import Grid from '@mui/material/Grid2'
import Button from '@mui/material/Button'
import Divider from '@mui/material/Divider'
import MenuItem from '@mui/material/MenuItem'
import Typography from '@mui/material/Typography'
import CardHeader from '@mui/material/CardHeader'
import CardContent from '@mui/material/CardContent'
import CardActions from '@mui/material/CardActions'
import InputAdornment from '@mui/material/InputAdornment'
import IconButton from '@mui/material/IconButton'
// Components Imports
import CustomTextField from '@core/components/mui/TextField'
// Styled Component Imports
import AppReactDatepicker from '@/libs/styles/AppReactDatepicker'
type FormDataType = {
username: string
email: string
password: string
isPasswordShown: boolean
confirmPassword: string
isConfirmPasswordShown: boolean
firstName: string
lastName: string
country: string
language: string[]
date: Date | null
phoneNumber: string
}
const FormLayoutsSeparator = () => {
// States
const [formData, setFormData] = useState<FormDataType>({
username: '',
email: '',
password: '',
isPasswordShown: false,
confirmPassword: '',
isConfirmPasswordShown: false,
firstName: '',
lastName: '',
country: '',
language: [],
date: null,
phoneNumber: ''
})
const handleClickShowPassword = () => setFormData(show => ({ ...show, isPasswordShown: !show.isPasswordShown }))
const handleClickShowConfirmPassword = () =>
setFormData(show => ({ ...show, isConfirmPasswordShown: !show.isConfirmPasswordShown }))
const handleReset = () => {
setFormData({
username: '',
email: '',
password: '',
isPasswordShown: false,
confirmPassword: '',
isConfirmPasswordShown: false,
firstName: '',
lastName: '',
country: '',
language: [],
date: null,
phoneNumber: ''
})
}
return (
<Card>
<CardHeader title='Multi Column with Form Separator' />
<Divider />
<form onSubmit={e => e.preventDefault()}>
<CardContent>
<Grid container spacing={6}>
<Grid size={{ xs: 12 }}>
<Typography variant='body2' className='font-medium'>
1. Account Details
</Typography>
</Grid>
<Grid size={{ xs: 12, sm: 6 }}>
<CustomTextField
fullWidth
label='UserName'
placeholder='johnDoe '
value={formData.username}
onChange={e => setFormData({ ...formData, username: e.target.value })}
/>
</Grid>
<Grid size={{ xs: 12, sm: 6 }}>
<CustomTextField
fullWidth
type='email'
label='Email'
value={formData.email}
placeholder='johndoe@gmail.com'
onChange={e => setFormData({ ...formData, email: e.target.value })}
/>
</Grid>
<Grid size={{ xs: 12, sm: 6 }}>
<CustomTextField
fullWidth
label='Password'
placeholder='············'
id='form-layout-separator-password'
type={formData.isPasswordShown ? 'text' : 'password'}
value={formData.password}
onChange={e => setFormData({ ...formData, password: e.target.value })}
slotProps={{
input: {
endAdornment: (
<InputAdornment position='end'>
<IconButton
edge='end'
onClick={handleClickShowPassword}
onMouseDown={e => e.preventDefault()}
aria-label='toggle password visibility'
>
<i className={formData.isPasswordShown ? 'tabler-eye-off' : 'tabler-eye'} />
</IconButton>
</InputAdornment>
)
}
}}
/>
</Grid>
<Grid size={{ xs: 12, sm: 6 }}>
<CustomTextField
fullWidth
label='Confirm Password'
placeholder='············'
id='form-layout-separator-confirm-password'
type={formData.isConfirmPasswordShown ? 'text' : 'password'}
value={formData.confirmPassword}
onChange={e => setFormData({ ...formData, confirmPassword: e.target.value })}
slotProps={{
input: {
endAdornment: (
<InputAdornment position='end'>
<IconButton
edge='end'
onClick={handleClickShowConfirmPassword}
onMouseDown={e => e.preventDefault()}
aria-label='toggle confirm password visibility'
>
<i className={formData.isConfirmPasswordShown ? 'tabler-eye-off' : 'tabler-eye'} />
</IconButton>
</InputAdornment>
)
}
}}
/>
</Grid>
<Grid size={{ xs: 12 }}>
<Divider />
</Grid>
<Grid size={{ xs: 12 }}>
<Typography variant='body2' className='font-medium'>
2. Personal Info
</Typography>
</Grid>
<Grid size={{ xs: 12, sm: 6 }}>
<CustomTextField
fullWidth
label='First Name'
placeholder='John'
value={formData.firstName}
onChange={e => setFormData({ ...formData, firstName: e.target.value })}
/>
</Grid>
<Grid size={{ xs: 12, sm: 6 }}>
<CustomTextField
fullWidth
label='Last Name'
placeholder='Doe'
value={formData.lastName}
onChange={e => setFormData({ ...formData, lastName: e.target.value })}
/>
</Grid>
<Grid size={{ xs: 12, sm: 6 }}>
<CustomTextField
select
fullWidth
label='Country'
value={formData.country}
onChange={e => setFormData({ ...formData, country: e.target.value })}
>
<MenuItem value=''>Select Country</MenuItem>
<MenuItem value='UK'>UK</MenuItem>
<MenuItem value='USA'>USA</MenuItem>
<MenuItem value='Australia'>Australia</MenuItem>
<MenuItem value='Germany'>Germany</MenuItem>
</CustomTextField>
</Grid>
<Grid size={{ xs: 12, sm: 6 }}>
<CustomTextField
select
fullWidth
label='Language'
value={formData.language}
slotProps={{
select: {
multiple: true,
onChange: e => setFormData({ ...formData, language: e.target.value as string[] })
}
}}
>
<MenuItem value='English'>English</MenuItem>
<MenuItem value='French'>French</MenuItem>
<MenuItem value='Spanish'>Spanish</MenuItem>
<MenuItem value='Portuguese'>Portuguese</MenuItem>
<MenuItem value='Italian'>Italian</MenuItem>
<MenuItem value='German'>German</MenuItem>
<MenuItem value='Arabic'>Arabic</MenuItem>
</CustomTextField>
</Grid>
<Grid size={{ xs: 12, sm: 6 }}>
<AppReactDatepicker
selected={formData.date}
showYearDropdown
showMonthDropdown
onChange={(date: Date | null) => setFormData({ ...formData, date })}
placeholderText='MM/DD/YYYY'
customInput={<CustomTextField fullWidth label='Birth Date' placeholder='MM-DD-YYYY' />}
/>
</Grid>
<Grid size={{ xs: 12, sm: 6 }}>
<CustomTextField
fullWidth
label='Phone Number'
type='number'
placeholder='123-456-7890'
value={formData.phoneNumber}
onChange={e => setFormData({ ...formData, phoneNumber: e.target.value })}
/>
</Grid>
</Grid>
</CardContent>
<Divider />
<CardActions>
<Button type='submit' variant='contained' className='mie-2'>
Submit
</Button>
<Button
type='reset'
variant='tonal'
color='secondary'
onClick={() => {
handleReset()
}}
>
Reset
</Button>
</CardActions>
</form>
</Card>
)
}
export default FormLayoutsSeparator
@@ -0,0 +1,346 @@
'use client'
// React Imports
import { useState } from 'react'
import type { SyntheticEvent } from 'react'
// MUI Imports
import Card from '@mui/material/Card'
import Grid from '@mui/material/Grid2'
import Button from '@mui/material/Button'
import Tab from '@mui/material/Tab'
import MenuItem from '@mui/material/MenuItem'
import TabContext from '@mui/lab/TabContext'
import TabList from '@mui/lab/TabList'
import TabPanel from '@mui/lab/TabPanel'
import CardContent from '@mui/material/CardContent'
import CardActions from '@mui/material/CardActions'
import Divider from '@mui/material/Divider'
import InputAdornment from '@mui/material/InputAdornment'
import IconButton from '@mui/material/IconButton'
// Components Imports
import CustomTextField from '@core/components/mui/TextField'
// Styled Component Imports
import AppReactDatepicker from '@/libs/styles/AppReactDatepicker'
type FormDataType = {
firstName: string
lastName: string
country: string
language: string[]
date: Date | null
phoneNumber: string
username: string
email: string
password: string
isPasswordShown: boolean
confirmPassword: string
setIsConfirmPasswordShown: boolean
twitter: string
facebook: string
google: string
linkedin: string
instagram: string
quora: string
}
const FormLayoutsWithTabs = () => {
// States
const [value, setValue] = useState('personal_info')
const [formData, setFormData] = useState<FormDataType>({
firstName: '',
lastName: '',
country: '',
language: [],
date: null,
phoneNumber: '',
username: '',
email: '',
password: '',
isPasswordShown: false,
confirmPassword: '',
setIsConfirmPasswordShown: false,
twitter: '',
facebook: '',
google: '',
linkedin: '',
instagram: '',
quora: ''
})
const handleClickShowPassword = () => setFormData(show => ({ ...show, isPasswordShown: !show.isPasswordShown }))
const handleClickShowConfirmPassword = () =>
setFormData(show => ({ ...show, setIsConfirmPasswordShown: !show.setIsConfirmPasswordShown }))
const handleTabChange = (event: SyntheticEvent, newValue: string) => {
setValue(newValue)
}
const handleReset = () => {
setFormData({
firstName: '',
lastName: '',
country: '',
language: [],
date: null,
phoneNumber: '',
username: '',
email: '',
password: '',
isPasswordShown: false,
confirmPassword: '',
setIsConfirmPasswordShown: false,
twitter: '',
facebook: '',
google: '',
linkedin: '',
instagram: '',
quora: ''
})
}
return (
<Card>
<TabContext value={value}>
<TabList variant='scrollable' onChange={handleTabChange} className='border-be'>
<Tab label='Personal Info' value='personal_info' />
<Tab label='Account Details' value='account_details' />
<Tab label='Social Links' value='social_links' />
</TabList>
<form onSubmit={e => e.preventDefault()}>
<CardContent>
<TabPanel value='personal_info'>
<Grid container spacing={6}>
<Grid size={{ xs: 12, sm: 6 }}>
<CustomTextField
fullWidth
label='First Name'
placeholder='John'
value={formData.firstName}
onChange={e => setFormData({ ...formData, firstName: e.target.value })}
/>
</Grid>
<Grid size={{ xs: 12, sm: 6 }}>
<CustomTextField
fullWidth
label='Last Name'
placeholder='Doe'
value={formData.lastName}
onChange={e => setFormData({ ...formData, lastName: e.target.value })}
/>
</Grid>
<Grid size={{ xs: 12, sm: 6 }}>
<CustomTextField
select
fullWidth
label='Country'
value={formData.country}
onChange={e => setFormData({ ...formData, country: e.target.value })}
>
<MenuItem value=''>Select Country</MenuItem>
<MenuItem value='UK'>UK</MenuItem>
<MenuItem value='USA'>USA</MenuItem>
<MenuItem value='Australia'>Australia</MenuItem>
<MenuItem value='Germany'>Germany</MenuItem>
</CustomTextField>
</Grid>
<Grid size={{ xs: 12, sm: 6 }}>
<CustomTextField
select
fullWidth
label='Language'
value={formData.language}
slotProps={{
select: {
multiple: true,
onChange: e => setFormData({ ...formData, language: e.target.value as string[] })
}
}}
>
<MenuItem value='English'>English</MenuItem>
<MenuItem value='French'>French</MenuItem>
<MenuItem value='Spanish'>Spanish</MenuItem>
<MenuItem value='Portuguese'>Portuguese</MenuItem>
<MenuItem value='Italian'>Italian</MenuItem>
<MenuItem value='German'>German</MenuItem>
<MenuItem value='Arabic'>Arabic</MenuItem>
</CustomTextField>
</Grid>
<Grid size={{ xs: 12, sm: 6 }}>
<AppReactDatepicker
selected={formData.date}
showYearDropdown
showMonthDropdown
onChange={(date: Date | null) => setFormData({ ...formData, date })}
placeholderText='MM/DD/YYYY'
customInput={<CustomTextField fullWidth label='Birth Date' placeholder='MM-DD-YYYY' />}
/>
</Grid>
<Grid size={{ xs: 12, sm: 6 }}>
<CustomTextField
fullWidth
label='Phone Number'
type='number'
placeholder='123-456-7890'
value={formData.phoneNumber}
onChange={e => setFormData({ ...formData, phoneNumber: e.target.value })}
/>
</Grid>
</Grid>
</TabPanel>
<TabPanel value='account_details'>
<Grid container spacing={6}>
<Grid size={{ xs: 12, sm: 6 }}>
<CustomTextField
fullWidth
label='Username'
placeholder='johnDoe'
value={formData.username}
onChange={e => setFormData({ ...formData, username: e.target.value })}
/>
</Grid>
<Grid size={{ xs: 12, sm: 6 }}>
<CustomTextField
fullWidth
type='email'
label='Email'
placeholder='johndoe@gmail.com'
value={formData.email}
onChange={e => setFormData({ ...formData, email: e.target.value })}
/>
</Grid>
<Grid size={{ xs: 12, sm: 6 }}>
<CustomTextField
fullWidth
label='Password'
placeholder='············'
id='form-layout-tabs-password'
type={formData.isPasswordShown ? 'text' : 'password'}
value={formData.password}
onChange={e => setFormData({ ...formData, password: e.target.value })}
slotProps={{
input: {
endAdornment: (
<InputAdornment position='end'>
<IconButton
edge='end'
onClick={handleClickShowPassword}
onMouseDown={e => e.preventDefault()}
aria-label='toggle password visibility'
>
<i className={formData.isPasswordShown ? 'tabler-eye-off' : 'tabler-eye'} />
</IconButton>
</InputAdornment>
)
}
}}
/>
</Grid>
<Grid size={{ xs: 12, sm: 6 }}>
<CustomTextField
fullWidth
label='Confirm Password'
placeholder='············'
id='form-layout-tabs-confirm-password'
type={formData.setIsConfirmPasswordShown ? 'text' : 'password'}
value={formData.confirmPassword}
onChange={e => setFormData({ ...formData, confirmPassword: e.target.value })}
slotProps={{
input: {
endAdornment: (
<InputAdornment position='end'>
<IconButton
edge='end'
onClick={handleClickShowConfirmPassword}
onMouseDown={e => e.preventDefault()}
aria-label='toggle password visibility'
>
<i className={formData.setIsConfirmPasswordShown ? 'tabler-eye-off' : 'tabler-eye'} />
</IconButton>
</InputAdornment>
)
}
}}
/>
</Grid>
</Grid>
</TabPanel>
<TabPanel value='social_links'>
<Grid container spacing={6}>
<Grid size={{ xs: 12, sm: 6 }}>
<CustomTextField
fullWidth
label='Twitter'
placeholder='https://twitter.com/johndoe'
value={formData.twitter}
onChange={e => setFormData({ ...formData, twitter: e.target.value })}
/>
</Grid>
<Grid size={{ xs: 12, sm: 6 }}>
<CustomTextField
fullWidth
label='Facebook'
placeholder='https://facebook.com/johndoe'
value={formData.facebook}
onChange={e => setFormData({ ...formData, facebook: e.target.value })}
/>
</Grid>
<Grid size={{ xs: 12, sm: 6 }}>
<CustomTextField
fullWidth
label='Google+'
placeholder='https://plus.google.com/johndoe'
value={formData.google}
onChange={e => setFormData({ ...formData, google: e.target.value })}
/>
</Grid>
<Grid size={{ xs: 12, sm: 6 }}>
<CustomTextField
fullWidth
label='LinkedIn'
placeholder='https://linkedin.com/johndoe'
value={formData.linkedin}
onChange={e => setFormData({ ...formData, linkedin: e.target.value })}
/>
</Grid>
<Grid size={{ xs: 12, sm: 6 }}>
<CustomTextField
fullWidth
label='Instagram'
placeholder='https://instagram.com/johndoe'
value={formData.instagram}
onChange={e => setFormData({ ...formData, instagram: e.target.value })}
/>
</Grid>
<Grid size={{ xs: 12, sm: 6 }}>
<CustomTextField
fullWidth
label='Quora'
placeholder='https://quora.com/johndoe'
value={formData.quora}
onChange={e => setFormData({ ...formData, quora: e.target.value })}
/>
</Grid>
</Grid>
</TabPanel>
</CardContent>
<Divider />
<CardActions>
<Button type='submit' variant='contained' className='mie-2'>
Submit
</Button>
<Button type='reset' variant='tonal' color='secondary' onClick={() => handleReset()}>
Reset
</Button>
</CardActions>
</form>
</TabContext>
</Card>
)
}
export default FormLayoutsWithTabs
@@ -0,0 +1,166 @@
'use client'
// React Imports
import { useState } from 'react'
// MUI Imports
import Card from '@mui/material/Card'
import Grid from '@mui/material/Grid2'
import Button from '@mui/material/Button'
import CardHeader from '@mui/material/CardHeader'
import CardContent from '@mui/material/CardContent'
import CircularProgress from '@mui/material/CircularProgress'
import InputAdornment from '@mui/material/InputAdornment'
import IconButton from '@mui/material/IconButton'
// Third-party Imports
import { toast } from 'react-toastify'
import { useForm, Controller } from 'react-hook-form'
// Components Imports
import CustomTextField from '@core/components/mui/TextField'
type FormValues = {
firstName: string
lastName: string
email: string
password: string
}
const FormValidationAsyncSubmit = () => {
// States
const [loading, setLoading] = useState(false)
const [isPasswordShown, setIsPasswordShown] = useState(false)
// Hooks
const {
control,
reset,
handleSubmit,
formState: { errors }
} = useForm<FormValues>({
defaultValues: {
firstName: '',
lastName: '',
email: '',
password: ''
}
})
const handleClickShowPassword = () => setIsPasswordShown(show => !show)
const onSubmit = async () => {
setLoading(true)
const sleep = (ms: number) => new Promise(resolve => setTimeout(resolve, ms))
await sleep(2000)
setLoading(false)
toast.success('Form Submitted')
}
return (
<Card>
<CardHeader title='Async Submit' />
<CardContent>
<form onSubmit={handleSubmit(onSubmit)}>
<Grid container spacing={6}>
<Grid size={{ xs: 12 }}>
<Controller
name='firstName'
control={control}
rules={{ required: true }}
render={({ field }) => (
<CustomTextField
{...field}
fullWidth
label='First Name'
placeholder='John'
{...(errors.firstName && { error: true, helperText: 'This field is required.' })}
/>
)}
/>
</Grid>
<Grid size={{ xs: 12 }}>
<Controller
name='lastName'
control={control}
rules={{ required: true }}
render={({ field }) => (
<CustomTextField
{...field}
fullWidth
label='Last Name'
placeholder='Doe'
{...(errors.lastName && { error: true, helperText: 'This field is required.' })}
/>
)}
/>
</Grid>
<Grid size={{ xs: 12 }}>
<Controller
name='email'
control={control}
rules={{ required: true }}
render={({ field }) => (
<CustomTextField
{...field}
fullWidth
type='email'
label='Email'
placeholder='johndoe@gmail.com'
{...(errors.email && { error: true, helperText: 'This field is required.' })}
/>
)}
/>
</Grid>
<Grid size={{ xs: 12 }}>
<Controller
name='password'
control={control}
rules={{ required: true }}
render={({ field }) => (
<CustomTextField
{...field}
fullWidth
label='Password'
id='outlined-password'
placeholder='············'
type={isPasswordShown ? 'text' : 'password'}
slotProps={{
input: {
endAdornment: (
<InputAdornment position='end'>
<IconButton
edge='end'
onClick={handleClickShowPassword}
onMouseDown={e => e.preventDefault()}
aria-label='toggle password visibility'
>
<i className={isPasswordShown ? 'tabler-eye-off' : 'tabler-eye'} />
</IconButton>
</InputAdornment>
)
}
}}
{...(errors.password && { error: true, helperText: 'This field is required' })}
/>
)}
/>
</Grid>
<Grid size={{ xs: 12 }} className='flex gap-4'>
<Button variant='contained' type='submit' className='gap-2'>
{loading && <CircularProgress size={20} color='inherit' />}
Submit
</Button>
<Button variant='tonal' color='secondary' type='reset' onClick={() => reset()}>
Reset
</Button>
</Grid>
</Grid>
</form>
</CardContent>
</Card>
)
}
export default FormValidationAsyncSubmit
@@ -0,0 +1,267 @@
'use client'
// React Imports
import { useState } from 'react'
// MUI Imports
import Card from '@mui/material/Card'
import CardHeader from '@mui/material/CardHeader'
import CardContent from '@mui/material/CardContent'
import Grid from '@mui/material/Grid2'
import Radio from '@mui/material/Radio'
import RadioGroup from '@mui/material/RadioGroup'
import FormControlLabel from '@mui/material/FormControlLabel'
import Button from '@mui/material/Button'
import Checkbox from '@mui/material/Checkbox'
import FormLabel from '@mui/material/FormLabel'
import FormHelperText from '@mui/material/FormHelperText'
import MenuItem from '@mui/material/MenuItem'
import FormControl from '@mui/material/FormControl'
import InputAdornment from '@mui/material/InputAdornment'
import IconButton from '@mui/material/IconButton'
// Third-party Imports
import { toast } from 'react-toastify'
import { useForm, Controller } from 'react-hook-form'
// Components Imports
import CustomTextField from '@core/components/mui/TextField'
// Styled Component Imports
import AppReactDatepicker from '@/libs/styles/AppReactDatepicker'
type FormValues = {
firstName: string
lastName: string
email: string
password: string
dob: Date | null | undefined
select: string
textarea: string
radio: boolean
checkbox: boolean
}
const FormValidationBasic = () => {
// States
const [isPasswordShown, setIsPasswordShown] = useState(false)
// Hooks
const {
control,
reset,
handleSubmit,
formState: { errors }
} = useForm<FormValues>({
defaultValues: {
firstName: '',
lastName: '',
email: '',
password: '',
dob: null,
select: '',
textarea: '',
radio: false,
checkbox: false
}
})
const handleClickShowPassword = () => setIsPasswordShown(show => !show)
const onSubmit = () => toast.success('Form Submitted')
return (
<Card>
<CardHeader title='Basic' />
<CardContent>
<form onSubmit={handleSubmit(onSubmit)}>
<Grid container spacing={6}>
<Grid size={{ xs: 12, sm: 6 }}>
<Controller
name='firstName'
control={control}
rules={{ required: true }}
render={({ field }) => (
<CustomTextField
{...field}
fullWidth
label='First Name'
placeholder='John'
{...(errors.firstName && { error: true, helperText: 'This field is required.' })}
/>
)}
/>
</Grid>
<Grid size={{ xs: 12, sm: 6 }}>
<Controller
name='lastName'
control={control}
rules={{ required: true }}
render={({ field }) => (
<CustomTextField
{...field}
fullWidth
label='Last Name'
placeholder='Doe'
{...(errors.lastName && { error: true, helperText: 'This field is required.' })}
/>
)}
/>
</Grid>
<Grid size={{ xs: 12, sm: 6 }}>
<Controller
name='email'
control={control}
rules={{ required: true }}
render={({ field }) => (
<CustomTextField
{...field}
fullWidth
type='email'
label='Email'
placeholder='johndoe@gmail.com'
{...(errors.email && { error: true, helperText: 'This field is required.' })}
/>
)}
/>
</Grid>
<Grid size={{ xs: 12, sm: 6 }}>
<Controller
name='password'
control={control}
rules={{ required: true }}
render={({ field }) => (
<CustomTextField
{...field}
fullWidth
label='Password'
placeholder='············'
id='form-validation-basic-password'
type={isPasswordShown ? 'text' : 'password'}
slotProps={{
input: {
endAdornment: (
<InputAdornment position='end'>
<IconButton
edge='end'
onClick={handleClickShowPassword}
onMouseDown={e => e.preventDefault()}
aria-label='toggle password visibility'
>
<i className={isPasswordShown ? 'tabler-eye-off' : 'tabler-eye'} />
</IconButton>
</InputAdornment>
)
}
}}
{...(errors.password && { error: true, helperText: 'This field is required.' })}
/>
)}
/>
</Grid>
<Grid size={{ xs: 12, sm: 6 }}>
<Controller
name='dob'
control={control}
rules={{ required: true }}
render={({ field: { value, onChange } }) => (
<AppReactDatepicker
selected={value}
showYearDropdown
showMonthDropdown
onChange={onChange}
placeholderText='MM/DD/YYYY'
customInput={
<CustomTextField
value={value}
onChange={onChange}
fullWidth
label='Date Of Birth'
{...(errors.dob && { error: true, helperText: 'This field is required.' })}
/>
}
/>
)}
/>
</Grid>
<Grid size={{ xs: 12, sm: 6 }}>
<Controller
name='select'
control={control}
rules={{ required: true }}
render={({ field }) => (
<CustomTextField select fullWidth label='Country' {...field} error={Boolean(errors.select)}>
<MenuItem value=''>Select Country</MenuItem>
<MenuItem value='UK'>UK</MenuItem>
<MenuItem value='USA'>USA</MenuItem>
<MenuItem value='Australia'>Australia</MenuItem>
<MenuItem value='Germany'>Germany</MenuItem>
</CustomTextField>
)}
/>
{errors.select && <FormHelperText error>This field is required.</FormHelperText>}
</Grid>
<Grid size={{ xs: 12 }}>
<Controller
name='textarea'
control={control}
rules={{ required: true }}
render={({ field }) => (
<CustomTextField
{...field}
rows={4}
fullWidth
multiline
label='Bio'
{...(errors.textarea && { error: true, helperText: 'This field is required.' })}
/>
)}
/>
</Grid>
<Grid size={{ xs: 12 }}>
<FormControl error={Boolean(errors.radio)}>
<FormLabel>Gender</FormLabel>
<Controller
name='radio'
control={control}
rules={{ required: true }}
render={({ field }) => (
<RadioGroup row {...field} name='radio-buttons-group'>
<FormControlLabel value='female' control={<Radio />} label='Female' />
<FormControlLabel value='male' control={<Radio />} label='Male' />
<FormControlLabel value='other' control={<Radio />} label='Other' />
</RadioGroup>
)}
/>
{errors.radio && <FormHelperText error>This field is required.</FormHelperText>}
</FormControl>
</Grid>
<Grid size={{ xs: 12 }}>
<FormControl error={Boolean(errors.checkbox)}>
<Controller
name='checkbox'
control={control}
rules={{ required: true }}
render={({ field }) => (
<FormControlLabel control={<Checkbox {...field} />} label='Agree to our terms and conditions' />
)}
/>
{errors.checkbox && <FormHelperText error>This field is required.</FormHelperText>}
</FormControl>
</Grid>
<Grid size={{ xs: 12 }} className='flex gap-4'>
<Button variant='contained' type='submit'>
Submit
</Button>
<Button variant='tonal' color='secondary' type='reset' onClick={() => reset()}>
Reset
</Button>
</Grid>
</Grid>
</form>
</CardContent>
</Card>
)
}
export default FormValidationBasic
@@ -0,0 +1,174 @@
'use client'
// React Imports
import { useState } from 'react'
// MUI Imports
import Card from '@mui/material/Card'
import Grid from '@mui/material/Grid2'
import Button from '@mui/material/Button'
import CardHeader from '@mui/material/CardHeader'
import CardContent from '@mui/material/CardContent'
import InputAdornment from '@mui/material/InputAdornment'
import IconButton from '@mui/material/IconButton'
// Third-party Imports
import { toast } from 'react-toastify'
import { Controller, useForm } from 'react-hook-form'
import { valibotResolver } from '@hookform/resolvers/valibot'
import { email, object, minLength, string, pipe, nonEmpty } from 'valibot'
import type { InferInput } from 'valibot'
// Components Imports
import CustomTextField from '@core/components/mui/TextField'
type FormData = InferInput<typeof schema>
const schema = object({
firstName: pipe(
string(),
nonEmpty('This field is required'),
minLength(3, 'First Name must be at least 3 characters long')
),
lastName: pipe(
string(),
nonEmpty('This field is required'),
minLength(3, 'Last Name must be at least 3 characters long')
),
email: pipe(string(), minLength(1, 'This field is required'), email('Please enter a valid email address')),
password: pipe(
string(),
nonEmpty('This field is required'),
minLength(8, 'Password must be at least 8 characters long')
)
})
const FormValidationOnScheme = () => {
// States
const [isPasswordShown, setIsPasswordShown] = useState(false)
// Hooks
const {
control,
reset,
handleSubmit,
formState: { errors }
} = useForm<FormData>({
resolver: valibotResolver(schema),
defaultValues: {
firstName: '',
lastName: '',
email: '',
password: ''
}
})
const handleClickShowPassword = () => setIsPasswordShown(show => !show)
const onSubmit = () => toast.success('Form Submitted')
return (
<Card>
<CardHeader title='Validation Schema With OnChange' />
<CardContent>
<form onSubmit={handleSubmit(onSubmit)}>
<Grid container spacing={6}>
<Grid size={{ xs: 12 }}>
<Controller
name='firstName'
control={control}
rules={{ required: true }}
render={({ field }) => (
<CustomTextField
{...field}
fullWidth
label='First Name'
placeholder='John'
{...(errors.firstName && { error: true, helperText: errors.firstName.message })}
/>
)}
/>
</Grid>
<Grid size={{ xs: 12 }}>
<Controller
name='lastName'
control={control}
rules={{ required: true }}
render={({ field }) => (
<CustomTextField
{...field}
fullWidth
label='Last Name'
placeholder='Doe'
{...(errors.lastName && { error: true, helperText: errors.lastName.message })}
/>
)}
/>
</Grid>
<Grid size={{ xs: 12 }}>
<Controller
name='email'
control={control}
rules={{ required: true }}
render={({ field }) => (
<CustomTextField
{...field}
fullWidth
type='email'
label='Email'
placeholder='johndoe@gmail.com'
{...(errors.email && { error: true, helperText: errors.email.message })}
/>
)}
/>
</Grid>
<Grid size={{ xs: 12 }}>
<Controller
name='password'
control={control}
rules={{ required: true }}
render={({ field }) => (
<CustomTextField
{...field}
fullWidth
label='Password'
placeholder='············'
id='form-validation-scheme-password'
type={isPasswordShown ? 'text' : 'password'}
slotProps={{
input: {
endAdornment: (
<InputAdornment position='end'>
<IconButton
edge='end'
onClick={handleClickShowPassword}
onMouseDown={e => e.preventDefault()}
aria-label='toggle password visibility'
>
<i className={isPasswordShown ? 'tabler-eye-off' : 'tabler-eye'} />
</IconButton>
</InputAdornment>
)
}
}}
{...(errors.password && { error: true, helperText: errors.password.message })}
/>
)}
/>
</Grid>
<Grid size={{ xs: 12 }} className='flex gap-4'>
<Button variant='contained' type='submit'>
Submit
</Button>
<Button variant='tonal' color='secondary' type='reset' onClick={() => reset()}>
Reset
</Button>
</Grid>
</Grid>
</form>
</CardContent>
</Card>
)
}
export default FormValidationOnScheme
@@ -0,0 +1,387 @@
'use client'
// React Imports
import { useState } from 'react'
// MUI Imports
import Card from '@mui/material/Card'
import Grid from '@mui/material/Grid2'
import CardContent from '@mui/material/CardContent'
import Stepper from '@mui/material/Stepper'
import Step from '@mui/material/Step'
import StepLabel from '@mui/material/StepLabel'
import Typography from '@mui/material/Typography'
import Button from '@mui/material/Button'
import MenuItem from '@mui/material/MenuItem'
import InputAdornment from '@mui/material/InputAdornment'
import IconButton from '@mui/material/IconButton'
// Third-party Imports
import { toast } from 'react-toastify'
// Component Imports
import DirectionalIcon from '@components/DirectionalIcon'
import CustomTextField from '@core/components/mui/TextField'
// Styled Component Imports
import StepperWrapper from '@core/styles/stepper'
import StepperCustomDot from '@components/stepper-dot'
type FormDataType = {
username: string
email: string
password: string
isPasswordShown: boolean
confirmPassword: string
isConfirmPasswordShown: boolean
firstName: string
lastName: string
country: string
language: string[]
twitter: string
facebook: string
instagram: string
github: string
}
// Vars
const steps = [
{
title: 'Account Details',
subtitle: 'Enter your account details'
},
{
title: 'Personal Info',
subtitle: 'Setup Information'
},
{
title: 'Social Links',
subtitle: 'Add Social Links'
}
]
const StepperAlternativeLabel = () => {
// States
const [activeStep, setActiveStep] = useState(0)
const [formData, setFormData] = useState<FormDataType>({
username: '',
email: '',
password: '',
isPasswordShown: false,
confirmPassword: '',
isConfirmPasswordShown: false,
firstName: '',
lastName: '',
country: '',
language: [],
twitter: '',
facebook: '',
instagram: '',
github: ''
})
const handleClickShowPassword = () => setFormData(show => ({ ...show, isPasswordShown: !show.isPasswordShown }))
const handleClickShowConfirmPassword = () =>
setFormData(show => ({ ...show, isConfirmPasswordShown: !show.isConfirmPasswordShown }))
const handleReset = () => {
setActiveStep(0)
setFormData({
username: '',
email: '',
password: '',
isPasswordShown: false,
confirmPassword: '',
isConfirmPasswordShown: false,
firstName: '',
lastName: '',
country: '',
language: [],
twitter: '',
facebook: '',
instagram: '',
github: ''
})
}
const handleNext = () => {
setActiveStep(prevActiveStep => prevActiveStep + 1)
if (activeStep === steps.length - 1) {
toast.success('Form Submitted')
}
}
const handleBack = () => {
setActiveStep(prevActiveStep => prevActiveStep - 1)
}
const renderStepContent = (activeStep: number) => {
switch (activeStep) {
case 0:
return (
<>
<Grid size={{ xs: 12, sm: 6 }}>
<CustomTextField
fullWidth
label='Username'
placeholder='johnDoe'
value={formData.username}
onChange={e => setFormData({ ...formData, username: e.target.value })}
/>
</Grid>
<Grid size={{ xs: 12, sm: 6 }}>
<CustomTextField
fullWidth
type='email'
label='Email'
placeholder='johndoe@gmail.com'
value={formData.email}
onChange={e => setFormData({ ...formData, email: e.target.value })}
/>
</Grid>
<Grid size={{ xs: 12, sm: 6 }}>
<CustomTextField
fullWidth
label='Password'
placeholder='············'
id='stepper-alternative-password'
type={formData.isPasswordShown ? 'text' : 'password'}
value={formData.password}
onChange={e => setFormData({ ...formData, password: e.target.value })}
slotProps={{
input: {
endAdornment: (
<InputAdornment position='end'>
<IconButton
edge='end'
onClick={handleClickShowPassword}
onMouseDown={e => e.preventDefault()}
aria-label='toggle password visibility'
>
<i className={formData.isPasswordShown ? 'tabler-eye-off' : 'tabler-eye'} />
</IconButton>
</InputAdornment>
)
}
}}
/>
</Grid>
<Grid size={{ xs: 12, sm: 6 }}>
<CustomTextField
fullWidth
label='Confirm Password'
placeholder='············'
id='stepper-alternative-confirm-password'
type={formData.isConfirmPasswordShown ? 'text' : 'password'}
value={formData.confirmPassword}
onChange={e => setFormData({ ...formData, confirmPassword: e.target.value })}
slotProps={{
input: {
endAdornment: (
<InputAdornment position='end'>
<IconButton
edge='end'
onClick={handleClickShowConfirmPassword}
onMouseDown={e => e.preventDefault()}
aria-label='toggle confirm password visibility'
>
<i className={formData.isConfirmPasswordShown ? 'tabler-eye-off' : 'tabler-eye'} />
</IconButton>
</InputAdornment>
)
}
}}
/>
</Grid>
</>
)
case 1:
return (
<>
<Grid size={{ xs: 12, sm: 6 }}>
<CustomTextField
fullWidth
label='First Name'
placeholder='John'
value={formData.firstName}
onChange={e => setFormData({ ...formData, firstName: e.target.value })}
/>
</Grid>
<Grid size={{ xs: 12, sm: 6 }}>
<CustomTextField
fullWidth
label='Last Name'
placeholder='Doe'
value={formData.lastName}
onChange={e => setFormData({ ...formData, lastName: e.target.value })}
/>
</Grid>
<Grid size={{ xs: 12, sm: 6 }}>
<CustomTextField
select
fullWidth
label='Country'
value={formData.country}
onChange={e => setFormData({ ...formData, country: e.target.value as string })}
>
<MenuItem value=''>Select Country</MenuItem>
<MenuItem value='UK'>UK</MenuItem>
<MenuItem value='USA'>USA</MenuItem>
<MenuItem value='Australia'>Australia</MenuItem>
<MenuItem value='Germany'>Germany</MenuItem>
</CustomTextField>
</Grid>
<Grid size={{ xs: 12, sm: 6 }}>
<CustomTextField
select
fullWidth
label='Language'
value={formData.language}
slotProps={{
select: {
multiple: true,
onChange: e => setFormData({ ...formData, language: e.target.value as string[] })
}
}}
>
<MenuItem value='English'>English</MenuItem>
<MenuItem value='French'>French</MenuItem>
<MenuItem value='Spanish'>Spanish</MenuItem>
<MenuItem value='Portuguese'>Portuguese</MenuItem>
<MenuItem value='Italian'>Italian</MenuItem>
<MenuItem value='German'>German</MenuItem>
<MenuItem value='Arabic'>Arabic</MenuItem>
</CustomTextField>
</Grid>
</>
)
case 2:
return (
<>
<Grid size={{ xs: 12, sm: 6 }}>
<CustomTextField
fullWidth
label='Facebook'
placeholder='https://www.facebook.com/johndoe'
value={formData.facebook}
onChange={e => setFormData({ ...formData, facebook: e.target.value })}
/>
</Grid>
<Grid size={{ xs: 12, sm: 6 }}>
<CustomTextField
fullWidth
label='Twitter'
placeholder='https://www.twitter.com/johndoe'
value={formData.twitter}
onChange={e => setFormData({ ...formData, twitter: e.target.value })}
/>
</Grid>
<Grid size={{ xs: 12, sm: 6 }}>
<CustomTextField
fullWidth
label='Instagram'
placeholder='https://www.instagram.com/johndoe'
value={formData.instagram}
onChange={e => setFormData({ ...formData, instagram: e.target.value })}
/>
</Grid>
<Grid size={{ xs: 12, sm: 6 }}>
<CustomTextField
fullWidth
label='Github'
placeholder='https://www.github.com/johndoe'
value={formData.github}
onChange={e => setFormData({ ...formData, github: e.target.value })}
/>
</Grid>
</>
)
default:
return 'Unknown step'
}
}
return (
<>
<StepperWrapper>
<Stepper activeStep={activeStep} alternativeLabel>
{steps.map(label => {
return (
<Step key={label.title}>
<StepLabel
slots={{
stepIcon: StepperCustomDot
}}
>
<div className='step-label'>
<div>
<Typography className='step-title'>{label.title}</Typography>
<Typography className='step-subtitle'>{label.subtitle}</Typography>
</div>
</div>
</StepLabel>
</Step>
)
})}
</Stepper>
</StepperWrapper>
<Card className='mt-4'>
<CardContent>
{activeStep === steps.length ? (
<>
<Typography className='mlb-2 mli-1'>All steps are completed!</Typography>
<div className='flex justify-end mt-4'>
<Button variant='contained' onClick={handleReset}>
Reset
</Button>
</div>
</>
) : (
<>
<form onSubmit={e => e.preventDefault()}>
<Grid container spacing={6}>
<Grid size={{ xs: 12 }}>
<Typography className='font-medium' color='text.primary'>
{steps[activeStep].title}
</Typography>
<Typography variant='body2'>{steps[activeStep].subtitle}</Typography>
</Grid>
{renderStepContent(activeStep)}
<Grid size={{ xs: 12 }} className='flex justify-between'>
<Button
variant='tonal'
disabled={activeStep === 0}
onClick={handleBack}
color='secondary'
startIcon={<DirectionalIcon ltrIconClass='tabler-arrow-left' rtlIconClass='tabler-arrow-right' />}
>
Back
</Button>
<Button
variant='contained'
onClick={handleNext}
endIcon={
activeStep === steps.length - 1 ? (
<i className='tabler-check' />
) : (
<DirectionalIcon ltrIconClass='tabler-arrow-right' rtlIconClass='tabler-arrow-left' />
)
}
>
{activeStep === steps.length - 1 ? 'Submit' : 'Next'}
</Button>
</Grid>
</Grid>
</form>
</>
)}
</CardContent>
</Card>
</>
)
}
export default StepperAlternativeLabel
@@ -0,0 +1,440 @@
'use client'
// React Imports
import { useState } from 'react'
// MUI Imports
import { styled, useTheme } from '@mui/material/styles'
import useMediaQuery from '@mui/material/useMediaQuery'
import Card from '@mui/material/Card'
import Grid from '@mui/material/Grid2'
import CardContent from '@mui/material/CardContent'
import Stepper from '@mui/material/Stepper'
import StepLabel from '@mui/material/StepLabel'
import Typography from '@mui/material/Typography'
import Button from '@mui/material/Button'
import MenuItem from '@mui/material/MenuItem'
import InputAdornment from '@mui/material/InputAdornment'
import IconButton from '@mui/material/IconButton'
import Divider from '@mui/material/Divider'
import MuiStep from '@mui/material/Step'
import type { StepProps } from '@mui/material/Step'
// Third-party Imports
import { toast } from 'react-toastify'
import classnames from 'classnames'
// Component Imports
import CustomAvatar from '@core/components/mui/Avatar'
import DirectionalIcon from '@components/DirectionalIcon'
import CustomTextField from '@core/components/mui/TextField'
// Styles Component Imports
import StepperWrapper from '@core/styles/stepper'
type FormDataType = {
username: string
email: string
password: string
isPasswordShown: boolean
confirmPassword: string
isConfirmPasswordShown: boolean
firstName: string
lastName: string
country: string
language: string[]
twitter: string
facebook: string
instagram: string
github: string
}
// Vars
const steps = [
{
icon: 'tabler-file-analytics',
title: 'Account Details',
subtitle: 'Enter your account details'
},
{
icon: 'tabler-user',
title: 'Personal Info',
subtitle: 'Setup Information'
},
{
icon: 'tabler-brand-instagram',
title: 'Social Links',
subtitle: 'Add Social Links'
}
]
const Step = styled(MuiStep)<StepProps>(({ theme }) => ({
paddingInline: theme.spacing(7),
'&:first-of-type': {
paddingLeft: 0
},
'&:last-of-type': {
paddingRight: 0
},
'& .MuiStepLabel-iconContainer': {
display: 'none'
},
'&.Mui-completed .step-title , &.Mui-completed .step-subtitle': {
color: 'var(--mui-palette-text-disabled)'
},
[theme.breakpoints.down('md')]: {
padding: 0,
':not(:last-of-type)': {
marginBlockEnd: theme.spacing(6)
}
}
}))
const StepperCustomHorizontal = () => {
// States
const [activeStep, setActiveStep] = useState(0)
const theme = useTheme()
const isSmallScreen = useMediaQuery(theme.breakpoints.down('md'))
const [formData, setFormData] = useState<FormDataType>({
username: '',
email: '',
password: '',
isPasswordShown: false,
confirmPassword: '',
isConfirmPasswordShown: false,
firstName: '',
lastName: '',
country: '',
language: [],
twitter: '',
facebook: '',
instagram: '',
github: ''
})
const handleClickShowPassword = () => setFormData(show => ({ ...show, isPasswordShown: !show.isPasswordShown }))
const handleClickShowConfirmPassword = () =>
setFormData(show => ({ ...show, isConfirmPasswordShown: !show.isConfirmPasswordShown }))
const handleReset = () => {
setActiveStep(0)
setFormData({
username: '',
email: '',
password: '',
isPasswordShown: false,
confirmPassword: '',
isConfirmPasswordShown: false,
firstName: '',
lastName: '',
country: '',
language: [],
twitter: '',
facebook: '',
instagram: '',
github: ''
})
}
const handleNext = () => {
setActiveStep(prevActiveStep => prevActiveStep + 1)
if (activeStep === steps.length - 1) {
toast.success('Form Submitted')
}
}
const handleBack = () => {
setActiveStep(prevActiveStep => prevActiveStep - 1)
}
const renderStepContent = (activeStep: number) => {
switch (activeStep) {
case 0:
return (
<>
<Grid size={{ xs: 12, sm: 6 }}>
<CustomTextField
fullWidth
label='Username'
placeholder='johnDoe'
value={formData.username}
onChange={e => setFormData({ ...formData, username: e.target.value })}
/>
</Grid>
<Grid size={{ xs: 12, sm: 6 }}>
<CustomTextField
fullWidth
type='email'
label='Email'
placeholder='johndoe@gmail.com'
value={formData.email}
onChange={e => setFormData({ ...formData, email: e.target.value })}
/>
</Grid>
<Grid size={{ xs: 12, sm: 6 }}>
<CustomTextField
fullWidth
label='Password'
placeholder='············'
id='stepper-customHorizontal-password'
type={formData.isPasswordShown ? 'text' : 'password'}
value={formData.password}
onChange={e => setFormData({ ...formData, password: e.target.value })}
slotProps={{
input: {
endAdornment: (
<InputAdornment position='end'>
<IconButton
edge='end'
onClick={handleClickShowPassword}
onMouseDown={e => e.preventDefault()}
aria-label='toggle password visibility'
>
<i className={formData.isPasswordShown ? 'tabler-eye-off' : 'tabler-eye'} />
</IconButton>
</InputAdornment>
)
}
}}
/>
</Grid>
<Grid size={{ xs: 12, sm: 6 }}>
<CustomTextField
fullWidth
label='Confirm Password'
placeholder='············'
id='stepper-customHorizontal-confirm-password'
type={formData.isConfirmPasswordShown ? 'text' : 'password'}
value={formData.confirmPassword}
onChange={e => setFormData({ ...formData, confirmPassword: e.target.value })}
slotProps={{
input: {
endAdornment: (
<InputAdornment position='end'>
<IconButton
edge='end'
onClick={handleClickShowConfirmPassword}
onMouseDown={e => e.preventDefault()}
aria-label='toggle confirm password visibility'
>
<i className={formData.isConfirmPasswordShown ? 'tabler-eye-off' : 'tabler-eye'} />
</IconButton>
</InputAdornment>
)
}
}}
/>
</Grid>
</>
)
case 1:
return (
<>
<Grid size={{ xs: 12, sm: 6 }}>
<CustomTextField
fullWidth
label='First Name'
placeholder='John'
value={formData.firstName}
onChange={e => setFormData({ ...formData, firstName: e.target.value })}
/>
</Grid>
<Grid size={{ xs: 12, sm: 6 }}>
<CustomTextField
fullWidth
label='Last Name'
placeholder='Doe'
value={formData.lastName}
onChange={e => setFormData({ ...formData, lastName: e.target.value })}
/>
</Grid>
<Grid size={{ xs: 12, sm: 6 }}>
<CustomTextField
select
fullWidth
label='Country'
value={formData.country}
onChange={e => setFormData({ ...formData, country: e.target.value as string })}
>
<MenuItem value=''>Select Country</MenuItem>
<MenuItem value='UK'>UK</MenuItem>
<MenuItem value='USA'>USA</MenuItem>
<MenuItem value='Australia'>Australia</MenuItem>
<MenuItem value='Germany'>Germany</MenuItem>
</CustomTextField>
</Grid>
<Grid size={{ xs: 12, sm: 6 }}>
<CustomTextField
select
fullWidth
label='Language'
value={formData.language}
slotProps={{
select: {
multiple: true,
onChange: e => setFormData({ ...formData, language: e.target.value as string[] })
}
}}
>
<MenuItem value='English'>English</MenuItem>
<MenuItem value='French'>French</MenuItem>
<MenuItem value='Spanish'>Spanish</MenuItem>
<MenuItem value='Portuguese'>Portuguese</MenuItem>
<MenuItem value='Italian'>Italian</MenuItem>
<MenuItem value='German'>German</MenuItem>
<MenuItem value='Arabic'>Arabic</MenuItem>
</CustomTextField>
</Grid>
</>
)
case 2:
return (
<>
<Grid size={{ xs: 12, sm: 6 }}>
<CustomTextField
fullWidth
label='Facebook'
placeholder='https://www.facebook.com/johndoe'
value={formData.facebook}
onChange={e => setFormData({ ...formData, facebook: e.target.value })}
/>
</Grid>
<Grid size={{ xs: 12, sm: 6 }}>
<CustomTextField
fullWidth
label='Twitter'
placeholder='https://www.twitter.com/johndoe'
value={formData.twitter}
onChange={e => setFormData({ ...formData, twitter: e.target.value })}
/>
</Grid>
<Grid size={{ xs: 12, sm: 6 }}>
<CustomTextField
fullWidth
label='Instagram'
placeholder='https://www.instagram.com/johndoe'
value={formData.instagram}
onChange={e => setFormData({ ...formData, instagram: e.target.value })}
/>
</Grid>
<Grid size={{ xs: 12, sm: 6 }}>
<CustomTextField
fullWidth
label='Github'
placeholder='https://www.github.com/johndoe'
value={formData.github}
onChange={e => setFormData({ ...formData, github: e.target.value })}
/>
</Grid>
</>
)
default:
return 'Unknown step'
}
}
return (
<>
<Card>
<CardContent>
<StepperWrapper>
<Stepper
activeStep={activeStep}
connector={
!isSmallScreen ? (
<DirectionalIcon
ltrIconClass='tabler-chevron-right'
rtlIconClass='tabler-chevron-left'
className='text-xl'
/>
) : null
}
>
{steps.map((step, index) => {
return (
<Step key={index}>
<StepLabel>
<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(step.icon)} />
</CustomAvatar>
<div>
<Typography className='step-title'>{step.title}</Typography>
<Typography className='step-subtitle'>{step.subtitle}</Typography>
</div>
</div>
</StepLabel>
</Step>
)
})}
</Stepper>
</StepperWrapper>
</CardContent>
<Divider sx={{ m: '0 !important' }} />
<CardContent>
{activeStep === steps.length ? (
<>
<Typography className='mlb-2 mli-1'>All steps are completed!</Typography>
<div className='flex justify-end mt-4'>
<Button variant='contained' onClick={handleReset}>
Reset
</Button>
</div>
</>
) : (
<>
<form onSubmit={e => e.preventDefault()}>
<Grid container spacing={6}>
<Grid size={{ xs: 12 }}>
<Typography className='font-medium' color='text.primary'>
{steps[activeStep].title}
</Typography>
<Typography variant='body2'>{steps[activeStep].subtitle}</Typography>
</Grid>
{renderStepContent(activeStep)}
<Grid size={{ xs: 12 }} className='flex justify-between'>
<Button
variant='tonal'
disabled={activeStep === 0}
onClick={handleBack}
startIcon={<DirectionalIcon ltrIconClass='tabler-arrow-left' rtlIconClass='tabler-arrow-right' />}
color='secondary'
>
Back
</Button>
<Button
variant='contained'
onClick={handleNext}
endIcon={
activeStep === steps.length - 1 ? (
<i className='tabler-check' />
) : (
<DirectionalIcon ltrIconClass='tabler-arrow-right' rtlIconClass='tabler-arrow-left' />
)
}
>
{activeStep === steps.length - 1 ? 'Submit' : 'Next'}
</Button>
</Grid>
</Grid>
</form>
</>
)}
</CardContent>
</Card>
</>
)
}
export default StepperCustomHorizontal
@@ -0,0 +1,451 @@
'use client'
// React Imports
import type { ChangeEvent } from 'react'
import { Fragment, useState } from 'react'
// MUI Imports
import { styled } from '@mui/material/styles'
import Box from '@mui/material/Box'
import Card from '@mui/material/Card'
import Grid from '@mui/material/Grid2'
import Button from '@mui/material/Button'
import Divider from '@mui/material/Divider'
import Stepper from '@mui/material/Stepper'
import MenuItem from '@mui/material/MenuItem'
import StepLabel from '@mui/material/StepLabel'
import Typography from '@mui/material/Typography'
import IconButton from '@mui/material/IconButton'
import InputAdornment from '@mui/material/InputAdornment'
import CardContent from '@mui/material/CardContent'
import MuiStep from '@mui/material/Step'
import type { StepProps } from '@mui/material/Step'
import type { SelectChangeEvent } from '@mui/material/Select'
import type { CardContentProps } from '@mui/material/CardContent'
// Third Party Imports
import { toast } from 'react-toastify'
import classnames from 'classnames'
// Components Imports
import CustomAvatar from '@core/components/mui/Avatar'
import CustomTextField from '@core/components/mui/TextField'
import DirectionalIcon from '@components/DirectionalIcon'
// Styled Component Imports
import StepperWrapper from '@core/styles/stepper'
interface State {
password: string
password2: string
showPassword: boolean
showPassword2: boolean
}
const steps = [
{
icon: 'tabler-file-analytics',
title: 'Account Details',
subtitle: 'Enter your Account Details'
},
{
icon: 'tabler-user',
title: 'Personal Info',
subtitle: 'Setup Information'
},
{
icon: 'tabler-brand-instagram',
title: 'Social Links',
subtitle: 'Add Social Links'
}
]
const StepperHeaderContainer = styled(CardContent)<CardContentProps>(({ theme }) => ({
borderRight: `1px solid 'var(--mui-palette-divider)'`,
[theme.breakpoints.down('md')]: {
borderRight: 0,
borderBottom: `1px solid 'var(--mui-palette-divider)'`
}
}))
const Step = styled(MuiStep)<StepProps>(({ theme }) => ({
'& .MuiStepLabel-root': {
paddingTop: 0
},
'&:first-of-type .MuiStepLabel-root': {
paddingTop: theme.spacing(1)
},
'&:not(:last-of-type) .MuiStepLabel-root': {
paddingBottom: theme.spacing(6)
},
'&:last-of-type .MuiStepLabel-root': {
paddingBottom: theme.spacing(1)
},
'& .MuiStepLabel-iconContainer': {
display: 'none'
},
'&.Mui-completed .step-title , &.Mui-completed .step-subtitle': {
color: 'var(--mui-palette-text-disabled)'
}
}))
const StepperCustomVertical = () => {
// States
const [email, setEmail] = useState<string>('')
const [google, setGoogle] = useState<string>('')
const [country, setCountry] = useState<string>('')
const [twitter, setTwitter] = useState<string>('')
const [username, setUsername] = useState<string>('')
const [lastName, setLastName] = useState<string>('')
const [facebook, setFacebook] = useState<string>('')
const [linkedIn, setLinkedIn] = useState<string>('')
const [firstName, setFirstName] = useState<string>('')
const [activeStep, setActiveStep] = useState<number>(0)
const [language, setLanguage] = useState<string[]>([])
const [state, setState] = useState<State>({
password: '',
password2: '',
showPassword: false,
showPassword2: false
})
// Handle Stepper
const handleBack = () => {
setActiveStep(prevActiveStep => prevActiveStep - 1)
}
const handleNext = () => {
setActiveStep(prevActiveStep => prevActiveStep + 1)
if (activeStep === steps.length - 1) {
toast.success('Form Submitted')
}
}
const handleReset = () => {
setEmail('')
setGoogle('')
setCountry('')
setTwitter('')
setUsername('')
setLastName('')
setFacebook('')
setLinkedIn('')
setLanguage([])
setFirstName('')
setActiveStep(0)
setState({ ...state, password: '', password2: '' })
}
// Handle Password
const handlePasswordChange = (prop: keyof State) => (event: ChangeEvent<HTMLInputElement>) => {
setState({ ...state, [prop]: event.target.value })
}
const handleClickShowPassword = () => {
setState({ ...state, showPassword: !state.showPassword })
}
// Handle Confirm Password
const handleConfirmChange = (prop: keyof State) => (event: ChangeEvent<HTMLInputElement>) => {
setState({ ...state, [prop]: event.target.value })
}
const handleClickShowConfirmPassword = () => {
setState({ ...state, showPassword2: !state.showPassword2 })
}
// Handle Language
const handleSelectChange = (event: SelectChangeEvent<string[]>) => {
setLanguage(event.target.value as string[])
}
const getStepContent = (step: number) => {
switch (step) {
case 0:
return (
<Fragment>
<Grid size={{ xs: 12, sm: 6 }}>
<CustomTextField
fullWidth
label='Username'
value={username}
placeholder='JohnDoe'
onChange={e => setUsername(e.target.value)}
/>
</Grid>
<Grid size={{ xs: 12, sm: 6 }}>
<CustomTextField
fullWidth
type='email'
label='Email'
value={email}
placeholder='johndoe@gmail.com'
onChange={e => setEmail(e.target.value)}
/>
</Grid>
<Grid size={{ xs: 12, sm: 6 }}>
<CustomTextField
fullWidth
label='Password'
placeholder='············'
value={state.password}
id='stepper-custom-vertical-account-password'
onChange={handlePasswordChange('password')}
type={state.showPassword ? 'text' : 'password'}
slotProps={{
input: {
endAdornment: (
<InputAdornment position='end'>
<IconButton
edge='end'
onClick={handleClickShowPassword}
onMouseDown={e => e.preventDefault()}
aria-label='toggle password visibility'
>
<i className={state.showPassword ? 'tabler-eye' : 'tabler-eye-off'} />
</IconButton>
</InputAdornment>
)
}
}}
/>
</Grid>
<Grid size={{ xs: 12, sm: 6 }}>
<CustomTextField
fullWidth
value={state.password2}
label='Confirm Password'
placeholder='············'
id='stepper-custom-vertical-account-password-2'
onChange={handleConfirmChange('password2')}
type={state.showPassword2 ? 'text' : 'password'}
slotProps={{
input: {
endAdornment: (
<InputAdornment position='end'>
<IconButton
edge='end'
onMouseDown={e => e.preventDefault()}
aria-label='toggle password visibility'
onClick={handleClickShowConfirmPassword}
>
<i className={state.showPassword2 ? 'tabler-eye' : 'tabler-eye-off'} />
</IconButton>
</InputAdornment>
)
}
}}
/>
</Grid>
</Fragment>
)
case 1:
return (
<Fragment key={step}>
<Grid size={{ xs: 12, sm: 6 }}>
<CustomTextField
fullWidth
value={firstName}
label='First Name'
placeholder='John'
onChange={e => setFirstName(e.target.value)}
/>
</Grid>
<Grid size={{ xs: 12, sm: 6 }}>
<CustomTextField
fullWidth
value={lastName}
label='Last Name'
placeholder='Doe'
onChange={e => setLastName(e.target.value)}
/>
</Grid>
<Grid size={{ xs: 12, sm: 6 }}>
<CustomTextField
select
fullWidth
label='Country'
value={country}
onChange={e => setCountry(e.target.value)}
id='stepper-custom-vertical-personal-select'
>
<MenuItem value=''>Select Country</MenuItem>
<MenuItem value='UK'>UK</MenuItem>
<MenuItem value='USA'>USA</MenuItem>
<MenuItem value='Australia'>Australia</MenuItem>
<MenuItem value='Germany'>Germany</MenuItem>
</CustomTextField>
</Grid>
<Grid size={{ xs: 12, sm: 6 }}>
<CustomTextField
select
fullWidth
label='Language'
id='stepper-custom-vertical-personal-multiple-select'
slotProps={{
select: {
multiple: true,
value: language,
onChange: e => handleSelectChange(e as SelectChangeEvent<string[]>)
}
}}
>
<MenuItem value='English'>English</MenuItem>
<MenuItem value='French'>French</MenuItem>
<MenuItem value='Spanish'>Spanish</MenuItem>
<MenuItem value='Portuguese'>Portuguese</MenuItem>
<MenuItem value='Italian'>Italian</MenuItem>
<MenuItem value='German'>German</MenuItem>
<MenuItem value='Arabic'>Arabic</MenuItem>
</CustomTextField>
</Grid>
</Fragment>
)
case 2:
return (
<Fragment key={step}>
<Grid size={{ xs: 12, sm: 6 }}>
<CustomTextField
fullWidth
label='Twitter'
value={twitter}
onChange={e => setTwitter(e.target.value)}
placeholder='https://twitter.com/johndoe'
/>
</Grid>
<Grid size={{ xs: 12, sm: 6 }}>
<CustomTextField
fullWidth
label='Facebook'
value={facebook}
onChange={e => setFacebook(e.target.value)}
placeholder='https://facebook.com/johndoe'
/>
</Grid>
<Grid size={{ xs: 12, sm: 6 }}>
<CustomTextField
fullWidth
label='Google+'
value={google}
onChange={e => setGoogle(e.target.value)}
placeholder='https://plus.google.com/johndoe'
/>
</Grid>
<Grid size={{ xs: 12, sm: 6 }}>
<CustomTextField
fullWidth
label='LinkedIn'
value={linkedIn}
onChange={e => setLinkedIn(e.target.value)}
placeholder='https://linkedin.com/johndoe'
/>
</Grid>
</Fragment>
)
default:
return 'Unknown Step'
}
}
const renderContent = () => {
if (activeStep === steps.length) {
return (
<>
<Typography>All steps are completed!</Typography>
<Box sx={{ mt: 4, display: 'flex', justifyContent: 'flex-end' }}>
<Button variant='contained' onClick={handleReset}>
Reset
</Button>
</Box>
</>
)
} else {
return (
<form onSubmit={e => e.preventDefault()}>
<Grid container spacing={5}>
<Grid size={{ xs: 12 }}>
<Typography variant='body2' sx={{ fontWeight: 600, color: 'text.primary' }}>
{steps[activeStep].title}
</Typography>
<Typography variant='caption' component='p'>
{steps[activeStep].subtitle}
</Typography>
</Grid>
{getStepContent(activeStep)}
<Grid size={{ xs: 12 }} sx={{ display: 'flex', justifyContent: 'space-between' }}>
<Button
variant='tonal'
color='secondary'
disabled={activeStep === 0}
onClick={handleBack}
startIcon={<DirectionalIcon ltrIconClass='tabler-arrow-left' rtlIconClass='tabler-arrow-right' />}
>
Back
</Button>
<Button
variant='contained'
onClick={handleNext}
endIcon={
activeStep === steps.length - 1 ? (
<i className='tabler-check' />
) : (
<DirectionalIcon ltrIconClass='tabler-arrow-right' rtlIconClass='tabler-arrow-left' />
)
}
>
{activeStep === steps.length - 1 ? 'Submit' : 'Next'}
</Button>
</Grid>
</Grid>
</form>
)
}
}
return (
<Card sx={{ display: 'flex', flexDirection: { xs: 'column', md: 'row' } }}>
<StepperHeaderContainer>
<StepperWrapper sx={{ height: '100%' }}>
<Stepper
activeStep={activeStep}
orientation='vertical'
connector={<></>}
sx={{ height: '100%', minWidth: '15rem' }}
>
{steps.map((step, index) => {
// const RenderAvatar = activeStep >= index ? CustomAvatar : Avatar
return (
<Step key={index}>
<StepLabel>
<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(step.icon)} />
</CustomAvatar>
<div>
<Typography className='step-title'>{step.title}</Typography>
<Typography className='step-subtitle'>{step.subtitle}</Typography>
</div>
</div>
</StepLabel>
</Step>
)
})}
</Stepper>
</StepperWrapper>
</StepperHeaderContainer>
<Divider sx={{ m: '0 !important' }} />
<CardContent sx={{ width: '100%' }}>{renderContent()}</CardContent>
</Card>
)
}
export default StepperCustomVertical
@@ -0,0 +1,612 @@
'use client'
// React Imports
import { useState } from 'react'
// MUI Imports
import { styled } from '@mui/material/styles'
import Grid from '@mui/material/Grid2'
import Card from '@mui/material/Card'
import Step from '@mui/material/Step'
import Button from '@mui/material/Button'
import Divider from '@mui/material/Divider'
import MuiStepper from '@mui/material/Stepper'
import MenuItem from '@mui/material/MenuItem'
import StepLabel from '@mui/material/StepLabel'
import Typography from '@mui/material/Typography'
import CardContent from '@mui/material/CardContent'
import FormHelperText from '@mui/material/FormHelperText'
import InputAdornment from '@mui/material/InputAdornment'
import IconButton from '@mui/material/IconButton'
import type { StepperProps } from '@mui/material/Stepper'
// Third-party Imports
import { toast } from 'react-toastify'
import { Controller, useForm } from 'react-hook-form'
import { valibotResolver } from '@hookform/resolvers/valibot'
import { email, object, minLength, string, array, forward, pipe, nonEmpty, check } from 'valibot'
// Component Imports
import CustomTextField from '@core/components/mui/TextField'
import StepperWrapper from '@core/styles/stepper'
import StepperCustomDot from '@components/stepper-dot'
import DirectionalIcon from '@components/DirectionalIcon'
// Vars
const steps = [
{
title: 'Account Details',
subtitle: 'Enter your account details'
},
{
title: 'Personal Info',
subtitle: 'Setup Information'
},
{
title: 'Social Links',
subtitle: 'Add Social Links'
}
]
// Styled Components
const Stepper = styled(MuiStepper)<StepperProps>(({ theme }) => ({
justifyContent: 'center',
'& .MuiStep-root': {
'&:first-of-type': {
paddingInlineStart: 0
},
'&:last-of-type': {
paddingInlineEnd: 0
},
[theme.breakpoints.down('md')]: {
paddingInline: 0
}
}
}))
const accountValidationSchema = object({
username: pipe(string(), nonEmpty('This field is required'), minLength(1)),
email: pipe(string(), nonEmpty('This field is required'), email('Please enter a valid email address')),
password: pipe(
string(),
nonEmpty('This field is required'),
minLength(8, 'Password must be at least 8 characters long')
),
confirmPassword: pipe(string(), nonEmpty('This field is required'), minLength(1))
})
const accountSchema = pipe(
accountValidationSchema,
forward(
check(input => input.password === input.confirmPassword, 'Passwords do not match.'),
['confirmPassword']
)
)
const personalSchema = object({
firstName: pipe(string(), nonEmpty('This field is required'), minLength(1)),
lastName: pipe(string(), nonEmpty('This field is required'), minLength(1)),
country: pipe(string(), nonEmpty('This field is required'), minLength(1)),
language: pipe(array(string()), nonEmpty('This field is required'), minLength(1))
})
const socialSchema = object({
twitter: pipe(string(), nonEmpty('This field is required'), minLength(1)),
facebook: pipe(string(), nonEmpty('This field is required'), minLength(1)),
google: pipe(string(), nonEmpty('This field is required'), minLength(1)),
linkedIn: pipe(string(), nonEmpty('This field is required'), minLength(1))
})
const StepperLinearWithValidation = () => {
// States
const [activeStep, setActiveStep] = useState(0)
const [isPasswordShown, setIsPasswordShown] = useState(false)
const [isConfirmPasswordShown, setIsConfirmPasswordShown] = useState(false)
// Vars
const Languages = ['English', 'French', 'Spanish', 'Portuguese', 'Italian', 'German', 'Arabic']
// Hooks
const {
reset: accountReset,
control: accountControl,
handleSubmit: handleAccountSubmit,
formState: { errors: accountErrors }
} = useForm({
resolver: valibotResolver(accountSchema),
defaultValues: {
username: '',
email: '',
password: '',
confirmPassword: ''
}
})
const {
reset: personalReset,
control: personalControl,
handleSubmit: handlePersonalSubmit,
formState: { errors: personalErrors }
} = useForm({
resolver: valibotResolver(personalSchema),
defaultValues: {
firstName: '',
lastName: '',
country: '',
language: []
}
})
const {
reset: socialReset,
control: socialControl,
handleSubmit: handleSocialSubmit,
formState: { errors: socialErrors }
} = useForm({
resolver: valibotResolver(socialSchema),
defaultValues: {
twitter: '',
facebook: '',
google: '',
linkedIn: ''
}
})
const handleClickShowPassword = () => setIsPasswordShown(show => !show)
const handleClickShowConfirmPassword = () => setIsConfirmPasswordShown(show => !show)
const onSubmit = () => {
setActiveStep(prevActiveStep => prevActiveStep + 1)
if (activeStep === steps.length - 1) {
toast.success('Form Submitted')
}
}
const handleBack = () => {
setActiveStep(prevActiveStep => prevActiveStep - 1)
}
const handleReset = () => {
setActiveStep(0)
accountReset({ email: '', username: '', password: '', confirmPassword: '' })
personalReset({ firstName: '', lastName: '', country: '', language: [] })
socialReset({ twitter: '', facebook: '', google: '', linkedIn: '' })
setIsPasswordShown(false)
setIsConfirmPasswordShown(false)
}
const renderStepContent = (activeStep: number) => {
switch (activeStep) {
case 0:
return (
<form key={0} onSubmit={handleAccountSubmit(onSubmit)}>
<Grid container spacing={6}>
<Grid size={{ xs: 12 }}>
<Typography className='font-medium' color='text.primary'>
{steps[0].title}
</Typography>
<Typography variant='body2'>{steps[0].subtitle}</Typography>
</Grid>
<Grid size={{ xs: 12, sm: 6 }}>
<Controller
name='username'
control={accountControl}
rules={{ required: true }}
render={({ field }) => (
<CustomTextField
{...field}
fullWidth
label='Username'
placeholder='johnDoe'
{...(accountErrors.username && { error: true, helperText: accountErrors.username.message })}
/>
)}
/>
</Grid>
<Grid size={{ xs: 12, sm: 6 }}>
<Controller
name='email'
control={accountControl}
rules={{ required: true }}
render={({ field }) => (
<CustomTextField
{...field}
fullWidth
type='email'
label='Email'
placeholder='johndoe@gmail.com'
{...(accountErrors.email && { error: true, helperText: accountErrors.email.message })}
/>
)}
/>
</Grid>
<Grid size={{ xs: 12, sm: 6 }}>
<Controller
name='password'
control={accountControl}
rules={{ required: true }}
render={({ field }) => (
<CustomTextField
{...field}
fullWidth
label='Password'
placeholder='············'
id='stepper-linear-validation-password'
type={isPasswordShown ? 'text' : 'password'}
slotProps={{
input: {
endAdornment: (
<InputAdornment position='end'>
<IconButton
edge='end'
onClick={handleClickShowPassword}
onMouseDown={e => e.preventDefault()}
aria-label='toggle password visibility'
>
<i className={isPasswordShown ? 'tabler-eye-off' : 'tabler-eye'} />
</IconButton>
</InputAdornment>
)
}
}}
{...(accountErrors.password && { error: true, helperText: accountErrors.password.message })}
/>
)}
/>
</Grid>
<Grid size={{ xs: 12, sm: 6 }}>
<Controller
name='confirmPassword'
control={accountControl}
rules={{ required: true }}
render={({ field }) => (
<CustomTextField
{...field}
fullWidth
label='Confirm Password'
placeholder='············'
id='stepper-linear-confirmPassword'
type={isConfirmPasswordShown ? 'text' : 'password'}
{...(accountErrors['confirmPassword'] && {
error: true,
helperText: accountErrors['confirmPassword'].message
})}
slotProps={{
input: {
endAdornment: (
<InputAdornment position='end'>
<IconButton
edge='end'
onClick={handleClickShowConfirmPassword}
onMouseDown={e => e.preventDefault()}
aria-label='toggle password visibility'
>
<i className={isConfirmPasswordShown ? 'tabler-eye-off' : 'tabler-eye'} />
</IconButton>
</InputAdornment>
)
}
}}
/>
)}
/>
</Grid>
<Grid size={{ xs: 12 }} className='flex justify-between'>
<Button
variant='tonal'
disabled
color='secondary'
startIcon={<DirectionalIcon ltrIconClass='tabler-arrow-left' rtlIconClass='tabler-arrow-right' />}
>
Back
</Button>
<Button
variant='contained'
type='submit'
endIcon={<DirectionalIcon ltrIconClass='tabler-arrow-right' rtlIconClass='tabler-arrow-left' />}
>
Next
</Button>
</Grid>
</Grid>
</form>
)
case 1:
return (
<form key={1} onSubmit={handlePersonalSubmit(onSubmit)}>
<Grid container spacing={6}>
<Grid size={{ xs: 12 }}>
<Typography className='font-medium' color='text.primary'>
{steps[1].title}
</Typography>
<Typography variant='body2'>{steps[1].subtitle}</Typography>
</Grid>
<Grid size={{ xs: 12, sm: 6 }}>
<Controller
name='firstName'
control={personalControl}
rules={{ required: true }}
render={({ field }) => (
<CustomTextField
{...field}
fullWidth
label='First Name'
placeholder='John'
{...(personalErrors.firstName && {
error: true,
helperText: personalErrors.firstName.message
})}
/>
)}
/>
</Grid>
<Grid size={{ xs: 12, sm: 6 }}>
<Controller
name='lastName'
control={personalControl}
rules={{ required: true }}
render={({ field }) => (
<CustomTextField
{...field}
fullWidth
label='Last Name'
placeholder='Doe'
{...(personalErrors.lastName && {
error: true,
helperText: personalErrors.lastName.message
})}
/>
)}
/>
</Grid>
<Grid size={{ xs: 12, sm: 6 }}>
<Controller
name='country'
control={personalControl}
rules={{ required: true }}
render={({ field }) => (
<CustomTextField
select
fullWidth
label='Country'
{...field}
error={Boolean(personalErrors.country)}
>
<MenuItem value='UK'>UK</MenuItem>
<MenuItem value='USA'>USA</MenuItem>
<MenuItem value='Australia'>Australia</MenuItem>
<MenuItem value='Germany'>Germany</MenuItem>
</CustomTextField>
)}
/>
{personalErrors.country && <FormHelperText error>country is a required field</FormHelperText>}
</Grid>
<Grid size={{ xs: 12, sm: 6 }}>
<Controller
name='language'
control={personalControl}
rules={{ required: true }}
render={({ field: { value, onChange } }) => (
<CustomTextField
select
fullWidth
slotProps={{
select: { multiple: true }
}}
label='Language'
value={Array.isArray(value) ? value : []}
onChange={onChange}
error={Boolean(personalErrors.language)}
>
{Languages.map(language => (
<MenuItem key={language} value={language}>
{language}
</MenuItem>
))}
</CustomTextField>
)}
/>
{personalErrors.language && <FormHelperText error>language is a required field</FormHelperText>}
</Grid>
<Grid size={{ xs: 12 }} className='flex justify-between'>
<Button
variant='tonal'
onClick={handleBack}
color='secondary'
startIcon={<DirectionalIcon ltrIconClass='tabler-arrow-left' rtlIconClass='tabler-arrow-right' />}
>
Back
</Button>
<Button
variant='contained'
type='submit'
endIcon={<DirectionalIcon ltrIconClass='tabler-arrow-right' rtlIconClass='tabler-arrow-left' />}
>
Next
</Button>
</Grid>
</Grid>
</form>
)
case 2:
return (
<form key={2} onSubmit={handleSocialSubmit(onSubmit)}>
<Grid container spacing={6}>
<Grid size={{ xs: 12 }}>
<Typography className='font-medium' color='text.primary'>
{steps[2].title}
</Typography>
<Typography variant='body2'>{steps[2].subtitle}</Typography>
</Grid>
<Grid size={{ xs: 12, sm: 6 }}>
<Controller
name='twitter'
control={socialControl}
rules={{ required: true }}
render={({ field: { value, onChange } }) => (
<CustomTextField
value={value}
onChange={onChange}
fullWidth
label='Twitter'
placeholder='https://twitter.com/johndoe'
{...(socialErrors.twitter && { error: true, helperText: socialErrors.twitter.message })}
/>
)}
/>
</Grid>
<Grid size={{ xs: 12, sm: 6 }}>
<Controller
name='facebook'
control={socialControl}
rules={{ required: true }}
render={({ field: { value, onChange } }) => (
<CustomTextField
value={value}
onChange={onChange}
fullWidth
label='Facebook'
placeholder='https://facebook.com/johndoe'
{...(socialErrors.facebook && { error: true, helperText: socialErrors.facebook.message })}
/>
)}
/>
</Grid>
<Grid size={{ xs: 12, sm: 6 }}>
<Controller
name='google'
control={socialControl}
rules={{ required: true }}
render={({ field }) => (
<CustomTextField
{...field}
fullWidth
label='Google'
placeholder='https://google.com/johndoe'
{...(socialErrors.google && { error: true, helperText: socialErrors.google.message })}
/>
)}
/>
</Grid>
<Grid size={{ xs: 12, sm: 6 }}>
<Controller
name='linkedIn'
control={socialControl}
rules={{ required: true }}
render={({ field }) => (
<CustomTextField
{...field}
fullWidth
label='LinkedIn'
placeholder='https://linkedin.com/johndoe'
{...(socialErrors.linkedIn && { error: true, helperText: socialErrors.linkedIn.message })}
/>
)}
/>
</Grid>
<Grid size={{ xs: 12 }} className='flex justify-between'>
<Button
variant='tonal'
onClick={handleBack}
color='secondary'
startIcon={<DirectionalIcon ltrIconClass='tabler-arrow-left' rtlIconClass='tabler-arrow-right' />}
>
Back
</Button>
<Button variant='contained' type='submit' endIcon={<i className='tabler-check' />}>
Submit
</Button>
</Grid>
</Grid>
</form>
)
default:
return <Typography>Unknown stepIndex</Typography>
}
}
return (
<Card>
<CardContent>
<StepperWrapper>
<Stepper activeStep={activeStep}>
{steps.map((label, index) => {
const labelProps: {
error?: boolean
} = {}
if (index === activeStep) {
labelProps.error = false
if (
(accountErrors.email ||
accountErrors.username ||
accountErrors.password ||
accountErrors['confirmPassword']) &&
activeStep === 0
) {
labelProps.error = true
} else if (
(personalErrors.firstName ||
personalErrors.lastName ||
personalErrors.country ||
personalErrors.language) &&
activeStep === 1
) {
labelProps.error = true
} else if (
(socialErrors.google || socialErrors.twitter || socialErrors.facebook || socialErrors.linkedIn) &&
activeStep === 2
) {
labelProps.error = true
} else {
labelProps.error = false
}
}
return (
<Step key={index} className='max-md:mbe-5'>
<StepLabel
{...labelProps}
slots={{
stepIcon: StepperCustomDot
}}
>
<div className='step-label'>
<Typography className='step-number'>{`0${index + 1}`}</Typography>
<div>
<Typography className='step-title' color='text.primary'>
{label.title}
</Typography>
<Typography className='step-subtitle'>{label.subtitle}</Typography>
</div>
</div>
</StepLabel>
</Step>
)
})}
</Stepper>
</StepperWrapper>
</CardContent>
<Divider />
<CardContent>
{activeStep === steps.length ? (
<>
<Typography className='mlb-2 mli-1'>All steps are completed!</Typography>
<div className='flex justify-end mt-4'>
<Button variant='contained' onClick={handleReset}>
Reset
</Button>
</div>
</>
) : (
renderStepContent(activeStep)
)}
</CardContent>
</Card>
)
}
export default StepperLinearWithValidation
@@ -0,0 +1,116 @@
'use client'
// React Imports
import { useState } from 'react'
// MUI Imports
import Step from '@mui/material/Step'
import Card from '@mui/material/Card'
import Button from '@mui/material/Button'
import Stepper from '@mui/material/Stepper'
import StepLabel from '@mui/material/StepLabel'
import CardHeader from '@mui/material/CardHeader'
import Typography from '@mui/material/Typography'
import CardContent from '@mui/material/CardContent'
import StepContent from '@mui/material/StepContent'
// Third-party Imports
import { toast } from 'react-toastify'
import classNames from 'classnames'
// Component Imports
import StepperWrapper from '@core/styles/stepper'
import StepperCustomDot from '@components/stepper-dot'
// Vars
const steps = [
{
title: 'Account Details',
subtitle: 'Enter your Account Details',
description:
'Chocolate cookie lollipop toffee candy canes marzipan liquorice chocolate. Cake gummi bears dessert lollipop apple pie candy. Candy pie sesame snaps lollipop biscuit chocolate cake fruitcake apple pie. Toffee carrot cake biscuit oat cake jujubes fruitcake biscuit gummi bears. Cake carrot cake jujubes sugar plum pastry gummi bears gingerbread icing. Lemon drops pie cake. Halvah marzipan bonbon gingerbread cupcake pastry gummi bears cake jujubes.'
},
{
title: 'Personal Info',
subtitle: 'Setup Information',
description:
'Lemon drops ice cream danish macaroon bear claw cookie. Liquorice ice cream chocolate bar pastry chocolate bar candy. Caramels candy canes marshmallow soufflé biscuit tart fruitcake tiramisu. Gummi bears icing gingerbread pastry bonbon gummies candy canes pastry. Candy canes chocolate chupa chups cake cheesecake apple pie halvah dessert. Chupa chups wafer tootsie roll fruitcake lemon drops cookie donut topping powder.'
},
{
title: 'Social Links',
subtitle: 'Add Social Links',
description:
'Jelly lollipop halvah bear claw jujubes macaroon candy canes. Soufflé halvah lollipop liquorice macaroon powder. Cookie topping pastry oat cake caramels bonbon. Sesame snaps sweet cookie macaroon soufflé pudding. Chocolate donut macaroon muffin donut biscuit marzipan halvah. Bear claw biscuit chocolate cake chupa chups oat cake bear claw cupcake tiramisu apple pie. Carrot cake bear claw marshmallow sweet pudding toffee.'
}
]
const StepperVerticalWithNumbers = () => {
// States
const [activeStep, setActiveStep] = useState(0)
const handleNext = () => {
setActiveStep(prevActiveStep => prevActiveStep + 1)
if (activeStep === steps.length - 1) {
toast.success('Completed All Steps!!')
}
}
const handleBack = () => {
setActiveStep(prevActiveStep => prevActiveStep - 1)
}
const handleReset = () => {
setActiveStep(0)
}
return (
<Card>
<CardHeader title='Vertical Stepper with Numbers' />
<CardContent>
<StepperWrapper>
<Stepper activeStep={activeStep} orientation='vertical'>
{steps.map((step, index) => (
<Step key={index} className={classNames({ active: activeStep === index })}>
<StepLabel
slots={{
stepIcon: StepperCustomDot
}}
>
<div className='step-label'>
<Typography className='step-number'>{`0${index + 1}`}</Typography>
<div>
<Typography className='step-title'>{step.title}</Typography>
<Typography className='step-subtitle'>{step.subtitle}</Typography>
</div>
</div>
</StepLabel>
<StepContent>
<Typography>{step.description}</Typography>
<div className='flex gap-4 mt-4'>
<Button variant='contained' onClick={handleNext} size='small'>
{index === steps.length - 1 ? 'Finish' : 'Next'}
</Button>
<Button size='small' color='secondary' variant='tonal' onClick={handleBack} disabled={index === 0}>
Back
</Button>
</div>
</StepContent>
</Step>
))}
</Stepper>
</StepperWrapper>
{activeStep === steps.length && (
<div className='mt-2'>
<Typography>All steps are completed!</Typography>
<Button variant='contained' onClick={handleReset} size='small' className='mt-2'>
Reset
</Button>
</div>
)}
</CardContent>
</Card>
)
}
export default StepperVerticalWithNumbers
@@ -0,0 +1,115 @@
'use client'
// React Imports
import { useState } from 'react'
// MUI Imports
import Step from '@mui/material/Step'
import Card from '@mui/material/Card'
import Button from '@mui/material/Button'
import Stepper from '@mui/material/Stepper'
import StepLabel from '@mui/material/StepLabel'
import CardHeader from '@mui/material/CardHeader'
import Typography from '@mui/material/Typography'
import CardContent from '@mui/material/CardContent'
import StepContent from '@mui/material/StepContent'
// Third-party Imports
import { toast } from 'react-toastify'
import classNames from 'classnames'
// Component Imports
import StepperWrapper from '@core/styles/stepper'
import StepperCustomDot from '@components/stepper-dot'
// Vars
const steps = [
{
title: 'Account Details',
subtitle: 'Enter your Account Details',
description:
'Chocolate cookie lollipop toffee candy canes marzipan liquorice chocolate. Cake gummi bears dessert lollipop apple pie candy. Candy pie sesame snaps lollipop biscuit chocolate cake fruitcake apple pie. Toffee carrot cake biscuit oat cake jujubes fruitcake biscuit gummi bears. Cake carrot cake jujubes sugar plum pastry gummi bears gingerbread icing. Lemon drops pie cake. Halvah marzipan bonbon gingerbread cupcake pastry gummi bears cake jujubes.'
},
{
title: 'Personal Info',
subtitle: 'Setup Information',
description:
'Lemon drops ice cream danish macaroon bear claw cookie. Liquorice ice cream chocolate bar pastry chocolate bar candy. Caramels candy canes marshmallow soufflé biscuit tart fruitcake tiramisu. Gummi bears icing gingerbread pastry bonbon gummies candy canes pastry. Candy canes chocolate chupa chups cake cheesecake apple pie halvah dessert. Chupa chups wafer tootsie roll fruitcake lemon drops cookie donut topping powder.'
},
{
title: 'Social Links',
subtitle: 'Add Social Links',
description:
'Jelly lollipop halvah bear claw jujubes macaroon candy canes. Soufflé halvah lollipop liquorice macaroon powder. Cookie topping pastry oat cake caramels bonbon. Sesame snaps sweet cookie macaroon soufflé pudding. Chocolate donut macaroon muffin donut biscuit marzipan halvah. Bear claw biscuit chocolate cake chupa chups oat cake bear claw cupcake tiramisu apple pie. Carrot cake bear claw marshmallow sweet pudding toffee.'
}
]
const StepperVerticalWithoutNumbers = () => {
// States
const [activeStep, setActiveStep] = useState(0)
const handleNext = () => {
setActiveStep(prevActiveStep => prevActiveStep + 1)
if (activeStep === steps.length - 1) {
toast.success('Completed All Steps!!')
}
}
const handleBack = () => {
setActiveStep(prevActiveStep => prevActiveStep - 1)
}
const handleReset = () => {
setActiveStep(0)
}
return (
<Card>
<CardHeader title='Vertical Stepper without Numbers' />
<CardContent>
<StepperWrapper>
<Stepper activeStep={activeStep} orientation='vertical'>
{steps.map((step, index) => (
<Step key={index} className={classNames({ active: activeStep === index })}>
<StepLabel
slots={{
stepIcon: StepperCustomDot
}}
>
<div className='step-label'>
<div>
<Typography className='step-title'>{step.title}</Typography>
<Typography className='step-subtitle'>{step.subtitle}</Typography>
</div>
</div>
</StepLabel>
<StepContent>
<Typography>{step.description}</Typography>
<div className='flex gap-4 mt-4'>
<Button variant='contained' onClick={handleNext} size='small'>
{index === steps.length - 1 ? 'Finish' : 'Next'}
</Button>
<Button size='small' color='secondary' variant='tonal' onClick={handleBack} disabled={index === 0}>
Back
</Button>
</div>
</StepContent>
</Step>
))}
</Stepper>
</StepperWrapper>
{activeStep === steps.length && (
<div className='mt-2'>
<Typography>All steps are completed!</Typography>
<Button variant='contained' onClick={handleReset} className='mt-2' size='small'>
Reset
</Button>
</div>
)}
</CardContent>
</Card>
)
}
export default StepperVerticalWithoutNumbers