Delete and Edit Vendor
This commit is contained in:
parent
c91be1812b
commit
40c417ec72
@ -1,6 +1,6 @@
|
|||||||
import { useQuery } from '@tanstack/react-query'
|
import { useQuery } from '@tanstack/react-query'
|
||||||
import { api } from '../api'
|
import { api } from '../api'
|
||||||
import { Vendors } from '@/types/services/vendor'
|
import { Vendor, Vendors } from '@/types/services/vendor'
|
||||||
|
|
||||||
interface VendorQueryParams {
|
interface VendorQueryParams {
|
||||||
page?: number
|
page?: number
|
||||||
@ -34,3 +34,13 @@ export function useVendors(params: VendorQueryParams = {}) {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function useVendorById(id: string) {
|
||||||
|
return useQuery<Vendor>({
|
||||||
|
queryKey: ['vendors', id],
|
||||||
|
queryFn: async () => {
|
||||||
|
const res = await api.get(`/vendors/${id}`)
|
||||||
|
return res.data.data
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|||||||
@ -1,20 +1,28 @@
|
|||||||
|
'use client'
|
||||||
|
|
||||||
// MUI Imports
|
// MUI Imports
|
||||||
import Card from '@mui/material/Card'
|
import Card from '@mui/material/Card'
|
||||||
import CardContent from '@mui/material/CardContent'
|
import CardContent from '@mui/material/CardContent'
|
||||||
import Typography from '@mui/material/Typography'
|
import Typography from '@mui/material/Typography'
|
||||||
import Chip from '@mui/material/Chip'
|
import Chip from '@mui/material/Chip'
|
||||||
import Divider from '@mui/material/Divider'
|
import Divider from '@mui/material/Divider'
|
||||||
import Button from '@mui/material/Button'
|
|
||||||
import type { ButtonProps } from '@mui/material/Button'
|
|
||||||
|
|
||||||
// Type Imports
|
|
||||||
import type { ThemeColor } from '@core/types'
|
|
||||||
|
|
||||||
// Component Imports
|
// Component Imports
|
||||||
import EditUserInfo from '@components/dialogs/edit-user-info'
|
|
||||||
import ConfirmationDialog from '@components/dialogs/confirmation-dialog'
|
|
||||||
import OpenDialogOnElementClick from '@components/dialogs/OpenDialogOnElementClick'
|
|
||||||
import CustomAvatar from '@core/components/mui/Avatar'
|
import CustomAvatar from '@core/components/mui/Avatar'
|
||||||
|
import { useParams } from 'next/navigation'
|
||||||
|
import { useVendorById } from '@/services/queries/vendor'
|
||||||
|
import Loading from '@/components/layout/shared/Loading'
|
||||||
|
import { getInitials } from '@/utils/getInitials'
|
||||||
|
import OpenDialogOnElementClick from '@/components/dialogs/OpenDialogOnElementClick'
|
||||||
|
import { Box, Button, ButtonProps, CircularProgress } from '@mui/material'
|
||||||
|
import ConfirmationDialog from '@/components/dialogs/confirmation-dialog'
|
||||||
|
import EditUserInfo from '@/components/dialogs/edit-user-info'
|
||||||
|
import { ThemeColor } from '@/@core/types'
|
||||||
|
import { useState } from 'react'
|
||||||
|
import AddVendorDrawer from '../../list/AddVendorDrawer'
|
||||||
|
import ConfirmDeleteDialog from '@/components/dialogs/confirm-delete'
|
||||||
|
import { useRouter } from 'next/router'
|
||||||
|
import { useVendorsMutation } from '@/services/mutations/vendor'
|
||||||
|
|
||||||
// Vars
|
// Vars
|
||||||
const userData = {
|
const userData = {
|
||||||
@ -33,7 +41,25 @@ const userData = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const VendorDetails = () => {
|
const VendorDetails = () => {
|
||||||
// Vars
|
const [editVendorOpen, setEditVendorOpen] = useState(false)
|
||||||
|
const [openConfirm, setOpenConfirm] = useState(false)
|
||||||
|
|
||||||
|
const params = useParams()
|
||||||
|
const id = params?.id ?? ''
|
||||||
|
|
||||||
|
const { data: vendor, isLoading, error } = useVendorById(id as string)
|
||||||
|
|
||||||
|
const { deleteVendor } = useVendorsMutation()
|
||||||
|
|
||||||
|
const handleDelete = () => {
|
||||||
|
deleteVendor.mutate(id as string, {
|
||||||
|
onSuccess: () => {
|
||||||
|
setOpenConfirm(false)
|
||||||
|
window.history.back()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
const buttonProps = (children: string, color: ThemeColor, variant: ButtonProps['variant']): ButtonProps => ({
|
const buttonProps = (children: string, color: ThemeColor, variant: ButtonProps['variant']): ButtonProps => ({
|
||||||
children,
|
children,
|
||||||
color,
|
color,
|
||||||
@ -42,91 +68,132 @@ const VendorDetails = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Card>
|
{isLoading ? (
|
||||||
<CardContent className='flex flex-col pbs-12 gap-6'>
|
<Box
|
||||||
<div className='flex flex-col gap-6'>
|
position='absolute'
|
||||||
<div className='flex items-center justify-center flex-col gap-4'>
|
top={0}
|
||||||
<div className='flex flex-col items-center gap-4'>
|
left={0}
|
||||||
<CustomAvatar alt='user-profile' src='/images/avatars/1.png' variant='rounded' size={120} />
|
right={0}
|
||||||
<Typography variant='h5'>{`${userData.firstName} ${userData.lastName}`}</Typography>
|
bottom={0}
|
||||||
|
display='flex'
|
||||||
|
alignItems='center'
|
||||||
|
justifyContent='center'
|
||||||
|
bgcolor='rgba(255,255,255,0.7)'
|
||||||
|
zIndex={1}
|
||||||
|
>
|
||||||
|
<CircularProgress size={24} />
|
||||||
|
</Box>
|
||||||
|
) : (
|
||||||
|
<Card>
|
||||||
|
<CardContent className='flex flex-col pbs-12 gap-6'>
|
||||||
|
<div className='flex flex-col gap-6'>
|
||||||
|
<div className='flex items-center justify-center flex-col gap-4'>
|
||||||
|
<div className='flex flex-col items-center gap-4'>
|
||||||
|
{/* <CustomAvatar alt='vendor-profile' variant='rounded' size={120}>
|
||||||
|
{getInitials(vendor?.name as string)}
|
||||||
|
</CustomAvatar> */}
|
||||||
|
<Typography variant='h5'>{vendor?.name}</Typography>
|
||||||
|
</div>
|
||||||
|
<Chip label='Vendor' color='primary' size='small' variant='tonal' />
|
||||||
</div>
|
</div>
|
||||||
<Chip label='Vendor' color='primary' size='small' variant='tonal' />
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Detail Kontak Section */}
|
{/* Detail Kontak Section */}
|
||||||
<div>
|
<div>
|
||||||
<Typography variant='h5'>Detail Kontak</Typography>
|
<Typography variant='h5'>Detail Kontak</Typography>
|
||||||
<Divider className='mlb-4' />
|
<Divider className='mlb-4' />
|
||||||
<div className='flex flex-col gap-2'>
|
<div className='flex flex-col gap-2'>
|
||||||
<div className='flex items-center flex-wrap gap-x-1.5'>
|
<div className='flex items-center flex-wrap gap-x-1.5'>
|
||||||
<Typography className='font-medium' color='text.primary'>
|
<Typography className='font-medium' color='text.primary'>
|
||||||
Nama:
|
Contact Person:
|
||||||
</Typography>
|
</Typography>
|
||||||
<Typography>{`${userData.firstName} ${userData.lastName}`}</Typography>
|
<Typography>{vendor?.contact_person}</Typography>
|
||||||
</div>
|
</div>
|
||||||
<div className='flex items-center flex-wrap gap-x-1.5'>
|
<div className='flex items-center flex-wrap gap-x-1.5'>
|
||||||
<Typography className='font-medium' color='text.primary'>
|
<Typography className='font-medium' color='text.primary'>
|
||||||
Perusahaan:
|
Perusahaan:
|
||||||
</Typography>
|
</Typography>
|
||||||
<Typography>{userData.perusahaan}</Typography>
|
<Typography>{vendor?.name}</Typography>
|
||||||
</div>
|
</div>
|
||||||
<div className='flex items-center flex-wrap gap-x-1.5'>
|
<div className='flex items-center flex-wrap gap-x-1.5'>
|
||||||
<Typography className='font-medium' color='text.primary'>
|
<Typography className='font-medium' color='text.primary'>
|
||||||
Email:
|
Email:
|
||||||
</Typography>
|
</Typography>
|
||||||
<Typography color='primary' sx={{ textDecoration: 'none', cursor: 'pointer' }}>
|
<Typography color='primary' sx={{ textDecoration: 'none', cursor: 'pointer' }}>
|
||||||
{userData.email}
|
{vendor?.email}
|
||||||
</Typography>
|
</Typography>
|
||||||
</div>
|
</div>
|
||||||
<div className='flex items-center flex-wrap gap-x-1.5'>
|
<div className='flex items-center flex-wrap gap-x-1.5'>
|
||||||
<Typography className='font-medium' color='text.primary'>
|
<Typography className='font-medium' color='text.primary'>
|
||||||
Telepon:
|
Telepon:
|
||||||
</Typography>
|
</Typography>
|
||||||
<Typography color='primary' sx={{ textDecoration: 'none', cursor: 'pointer' }}>
|
<Typography color='primary' sx={{ textDecoration: 'none', cursor: 'pointer' }}>
|
||||||
{userData.telepon}
|
{vendor?.phone_number}
|
||||||
</Typography>
|
</Typography>
|
||||||
</div>
|
</div>
|
||||||
<div className='flex items-center flex-wrap gap-x-1.5'>
|
<div className='flex items-center flex-wrap gap-x-1.5'>
|
||||||
<Typography className='font-medium' color='text.primary'>
|
<Typography className='font-medium' color='text.primary'>
|
||||||
Alamat Penagihan:
|
Alamat Penagihan:
|
||||||
</Typography>
|
</Typography>
|
||||||
<Typography color='primary' sx={{ textDecoration: 'none', cursor: 'pointer' }}>
|
<Typography color='primary' sx={{ textDecoration: 'none', cursor: 'pointer' }}>
|
||||||
{userData.alamatPenagihan}
|
{vendor?.address ?? '-'}
|
||||||
</Typography>
|
</Typography>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Pemetaan Akun Section */}
|
{/* Pemetaan Akun Section */}
|
||||||
<div>
|
<div>
|
||||||
<Typography variant='h5'>Pemetaan Akun</Typography>
|
<Typography variant='h5'>Pemetaan Akun</Typography>
|
||||||
<Divider className='mlb-4' />
|
<Divider className='mlb-4' />
|
||||||
<div className='flex flex-col gap-2'>
|
<div className='flex flex-col gap-2'>
|
||||||
<div className='flex items-center flex-wrap gap-x-1.5'>
|
<div className='flex items-center flex-wrap gap-x-1.5'>
|
||||||
<Typography className='font-medium' color='text.primary'>
|
<Typography className='font-medium' color='text.primary'>
|
||||||
Akun Hutang:
|
Akun Hutang:
|
||||||
</Typography>
|
</Typography>
|
||||||
<Typography color='primary' sx={{ textDecoration: 'none', cursor: 'pointer' }}>
|
<Typography color='primary' sx={{ textDecoration: 'none', cursor: 'pointer' }}>
|
||||||
{userData.akunHutang}
|
{userData.akunHutang}
|
||||||
</Typography>
|
</Typography>
|
||||||
</div>
|
</div>
|
||||||
<div className='flex items-center flex-wrap gap-x-1.5'>
|
<div className='flex items-center flex-wrap gap-x-1.5'>
|
||||||
<Typography className='font-medium' color='text.primary'>
|
<Typography className='font-medium' color='text.primary'>
|
||||||
Akun Piutang:
|
Akun Piutang:
|
||||||
</Typography>
|
</Typography>
|
||||||
<Typography color='text.secondary'>{userData.akunPiutang || '-'}</Typography>
|
<Typography color='text.secondary'>{userData.akunPiutang || '-'}</Typography>
|
||||||
</div>
|
</div>
|
||||||
<div className='flex items-center flex-wrap gap-x-1.5'>
|
<div className='flex items-center flex-wrap gap-x-1.5'>
|
||||||
<Typography className='font-medium' color='text.primary'>
|
<Typography className='font-medium' color='text.primary'>
|
||||||
Kena Pajak:
|
Kena Pajak:
|
||||||
</Typography>
|
</Typography>
|
||||||
<Typography color='text.primary'>{userData.kenaPajak}</Typography>
|
<Typography color='text.primary'>{userData.kenaPajak}</Typography>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div className='flex gap-4 justify-center'>
|
||||||
</CardContent>
|
<Button variant='contained' onClick={() => setEditVendorOpen(!editVendorOpen)} className='max-sm:is-full'>
|
||||||
</Card>
|
Edit
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
variant='contained'
|
||||||
|
color='error'
|
||||||
|
onClick={() => setOpenConfirm(!openConfirm)}
|
||||||
|
className='max-sm:is-full'
|
||||||
|
>
|
||||||
|
Hapus
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
)}
|
||||||
|
<AddVendorDrawer open={editVendorOpen} handleClose={() => setEditVendorOpen(!editVendorOpen)} data={vendor} />
|
||||||
|
<ConfirmDeleteDialog
|
||||||
|
open={openConfirm}
|
||||||
|
onClose={() => setOpenConfirm(false)}
|
||||||
|
onConfirm={handleDelete}
|
||||||
|
isLoading={deleteVendor.isPending}
|
||||||
|
title='Delete Vendor'
|
||||||
|
message='Are you sure you want to delete this Vendor? This action cannot be undone.'
|
||||||
|
/>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
94
src/views/apps/vendor/list/AddVendorDrawer.tsx
vendored
94
src/views/apps/vendor/list/AddVendorDrawer.tsx
vendored
@ -1,5 +1,5 @@
|
|||||||
// React Imports
|
// React Imports
|
||||||
import { useState } from 'react'
|
import { useState, useEffect } from 'react'
|
||||||
|
|
||||||
// MUI Imports
|
// MUI Imports
|
||||||
import Button from '@mui/material/Button'
|
import Button from '@mui/material/Button'
|
||||||
@ -18,12 +18,13 @@ import { useForm, Controller } from 'react-hook-form'
|
|||||||
|
|
||||||
// Component Imports
|
// Component Imports
|
||||||
import CustomTextField from '@core/components/mui/TextField'
|
import CustomTextField from '@core/components/mui/TextField'
|
||||||
import { VendorRequest } from '@/types/services/vendor'
|
import { Vendor, VendorRequest } from '@/types/services/vendor'
|
||||||
import { useVendorsMutation } from '@/services/mutations/vendor'
|
import { useVendorsMutation } from '@/services/mutations/vendor'
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
open: boolean
|
open: boolean
|
||||||
handleClose: () => void
|
handleClose: () => void
|
||||||
|
data?: Vendor // Data vendor untuk edit (jika ada)
|
||||||
}
|
}
|
||||||
|
|
||||||
type FormValidateType = {
|
type FormValidateType = {
|
||||||
@ -51,9 +52,9 @@ const initialData: FormValidateType = {
|
|||||||
is_active: true
|
is_active: true
|
||||||
}
|
}
|
||||||
|
|
||||||
const AddVendorDrawer = (props: Props) => {
|
const AddEditVendorDrawer = (props: Props) => {
|
||||||
// Props
|
// Props
|
||||||
const { open, handleClose } = props
|
const { open, handleClose, data } = props
|
||||||
|
|
||||||
// States
|
// States
|
||||||
const [showMore, setShowMore] = useState(false)
|
const [showMore, setShowMore] = useState(false)
|
||||||
@ -61,6 +62,9 @@ const AddVendorDrawer = (props: Props) => {
|
|||||||
|
|
||||||
const { createVendor, updateVendor } = useVendorsMutation()
|
const { createVendor, updateVendor } = useVendorsMutation()
|
||||||
|
|
||||||
|
// Determine if this is edit mode
|
||||||
|
const isEditMode = Boolean(data?.id)
|
||||||
|
|
||||||
// Hooks
|
// Hooks
|
||||||
const {
|
const {
|
||||||
control,
|
control,
|
||||||
@ -71,29 +75,73 @@ const AddVendorDrawer = (props: Props) => {
|
|||||||
defaultValues: initialData
|
defaultValues: initialData
|
||||||
})
|
})
|
||||||
|
|
||||||
const handleFormSubmit = async (data: FormValidateType) => {
|
// Effect to populate form when editing
|
||||||
|
useEffect(() => {
|
||||||
|
if (isEditMode && data) {
|
||||||
|
// Populate form with existing data
|
||||||
|
const formData: FormValidateType = {
|
||||||
|
name: data.name || '',
|
||||||
|
email: data.email || '',
|
||||||
|
phone_number: data.phone_number || '',
|
||||||
|
address: data.address || '',
|
||||||
|
contact_person: data.contact_person || '',
|
||||||
|
tax_number: data.tax_number || '',
|
||||||
|
payment_terms: data.payment_terms || '',
|
||||||
|
notes: data.notes || '',
|
||||||
|
is_active: data.is_active ?? true
|
||||||
|
}
|
||||||
|
|
||||||
|
resetForm(formData)
|
||||||
|
|
||||||
|
// Show more fields if any optional field has data
|
||||||
|
const hasOptionalData = data.address || data.tax_number || data.payment_terms || data.notes
|
||||||
|
if (hasOptionalData) {
|
||||||
|
setShowMore(true)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Reset to initial data for add mode
|
||||||
|
resetForm(initialData)
|
||||||
|
setShowMore(false)
|
||||||
|
}
|
||||||
|
}, [data, isEditMode, resetForm])
|
||||||
|
|
||||||
|
const handleFormSubmit = async (formData: FormValidateType) => {
|
||||||
try {
|
try {
|
||||||
setIsSubmitting(true)
|
setIsSubmitting(true)
|
||||||
|
|
||||||
// Create VendorRequest object
|
// Create VendorRequest object
|
||||||
const vendorRequest: VendorRequest = {
|
const vendorRequest: VendorRequest = {
|
||||||
name: data.name,
|
name: formData.name,
|
||||||
email: data.email || undefined,
|
email: formData.email || undefined,
|
||||||
phone_number: data.phone_number || undefined,
|
phone_number: formData.phone_number || undefined,
|
||||||
address: data.address || undefined,
|
address: formData.address || undefined,
|
||||||
contact_person: data.contact_person || undefined,
|
contact_person: formData.contact_person || undefined,
|
||||||
tax_number: data.tax_number || undefined,
|
tax_number: formData.tax_number || undefined,
|
||||||
payment_terms: data.payment_terms || undefined,
|
payment_terms: formData.payment_terms || undefined,
|
||||||
notes: data.notes || undefined,
|
notes: formData.notes || undefined,
|
||||||
is_active: data.is_active
|
is_active: formData.is_active
|
||||||
}
|
}
|
||||||
|
|
||||||
createVendor.mutate(vendorRequest, {
|
if (isEditMode && data?.id) {
|
||||||
onSuccess: () => {
|
// Update existing vendor
|
||||||
handleReset()
|
updateVendor.mutate(
|
||||||
handleClose()
|
{ id: data.id, payload: vendorRequest },
|
||||||
}
|
{
|
||||||
})
|
onSuccess: () => {
|
||||||
|
handleReset()
|
||||||
|
handleClose()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
// Create new vendor
|
||||||
|
createVendor.mutate(vendorRequest, {
|
||||||
|
onSuccess: () => {
|
||||||
|
handleReset()
|
||||||
|
handleClose()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error submitting vendor:', error)
|
console.error('Error submitting vendor:', error)
|
||||||
// Handle error (show toast, etc.)
|
// Handle error (show toast, etc.)
|
||||||
@ -136,7 +184,7 @@ const AddVendorDrawer = (props: Props) => {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div className='flex items-center justify-between plb-5 pli-6'>
|
<div className='flex items-center justify-between plb-5 pli-6'>
|
||||||
<Typography variant='h5'>Tambah Vendor Baru</Typography>
|
<Typography variant='h5'>{isEditMode ? 'Edit Vendor' : 'Tambah Vendor Baru'}</Typography>
|
||||||
<IconButton size='small' onClick={handleReset}>
|
<IconButton size='small' onClick={handleReset}>
|
||||||
<i className='tabler-x text-2xl text-textPrimary' />
|
<i className='tabler-x text-2xl text-textPrimary' />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
@ -359,7 +407,7 @@ const AddVendorDrawer = (props: Props) => {
|
|||||||
>
|
>
|
||||||
<div className='flex items-center gap-4'>
|
<div className='flex items-center gap-4'>
|
||||||
<Button variant='contained' type='submit' form='vendor-form' disabled={isSubmitting}>
|
<Button variant='contained' type='submit' form='vendor-form' disabled={isSubmitting}>
|
||||||
{isSubmitting ? 'Menyimpan...' : 'Simpan'}
|
{isSubmitting ? (isEditMode ? 'Mengupdate...' : 'Menyimpan...') : isEditMode ? 'Update' : 'Simpan'}
|
||||||
</Button>
|
</Button>
|
||||||
<Button variant='outlined' color='error' onClick={handleReset} disabled={isSubmitting}>
|
<Button variant='outlined' color='error' onClick={handleReset} disabled={isSubmitting}>
|
||||||
Batal
|
Batal
|
||||||
@ -370,4 +418,4 @@ const AddVendorDrawer = (props: Props) => {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export default AddVendorDrawer
|
export default AddEditVendorDrawer
|
||||||
|
|||||||
@ -183,12 +183,12 @@ const VendorListTable = () => {
|
|||||||
cell: ({ row }) => (
|
cell: ({ row }) => (
|
||||||
<div className='flex items-center gap-4'>
|
<div className='flex items-center gap-4'>
|
||||||
<div className='flex flex-col'>
|
<div className='flex flex-col'>
|
||||||
<Link href={getLocalizedUrl(`/apps/vendor/detail`, locale as Locale)}>
|
<Link href={getLocalizedUrl(`/apps/vendor/${row.original.id}/detail`, locale as Locale)}>
|
||||||
<Typography className='font-medium cursor-pointer hover:underline text-primary'>
|
<Typography className='font-medium cursor-pointer hover:underline text-primary'>
|
||||||
{row.original.contact_person}
|
{row.original.contact_person}
|
||||||
</Typography>
|
</Typography>
|
||||||
|
<Typography variant='body2'>{row.original.email}</Typography>
|
||||||
</Link>
|
</Link>
|
||||||
<Typography variant='body2'>{row.original.email}</Typography>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user