Create Vendor
This commit is contained in:
parent
8026004630
commit
3a74e32e64
52
src/services/mutations/vendor.ts
Normal file
52
src/services/mutations/vendor.ts
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
import { VendorRequest } from '@/types/services/vendor'
|
||||||
|
import { useMutation, useQueryClient } from '@tanstack/react-query'
|
||||||
|
import { toast } from 'react-toastify'
|
||||||
|
import { api } from '../api'
|
||||||
|
|
||||||
|
export const useVendorsMutation = () => {
|
||||||
|
const queryClient = useQueryClient()
|
||||||
|
|
||||||
|
const createVendor = useMutation({
|
||||||
|
mutationFn: async (newVendor: VendorRequest) => {
|
||||||
|
const response = await api.post('/vendors', newVendor)
|
||||||
|
return response.data
|
||||||
|
},
|
||||||
|
onSuccess: () => {
|
||||||
|
toast.success('Vendor created successfully!')
|
||||||
|
queryClient.invalidateQueries({ queryKey: ['vendors'] })
|
||||||
|
},
|
||||||
|
onError: (error: any) => {
|
||||||
|
toast.error(error.response?.data?.errors?.[0]?.cause || 'Create failed')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const updateVendor = useMutation({
|
||||||
|
mutationFn: async ({ id, payload }: { id: string; payload: VendorRequest }) => {
|
||||||
|
const response = await api.put(`/vendors/${id}`, payload)
|
||||||
|
return response.data
|
||||||
|
},
|
||||||
|
onSuccess: () => {
|
||||||
|
toast.success('Vendor updated successfully!')
|
||||||
|
queryClient.invalidateQueries({ queryKey: ['vendors'] })
|
||||||
|
},
|
||||||
|
onError: (error: any) => {
|
||||||
|
toast.error(error.response?.data?.errors?.[0]?.cause || 'Update failed')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const deleteVendor = useMutation({
|
||||||
|
mutationFn: async (id: string) => {
|
||||||
|
const response = await api.delete(`/vendors/${id}`)
|
||||||
|
return response.data
|
||||||
|
},
|
||||||
|
onSuccess: () => {
|
||||||
|
toast.success('Vendor deleted successfully!')
|
||||||
|
queryClient.invalidateQueries({ queryKey: ['vendors'] })
|
||||||
|
},
|
||||||
|
onError: (error: any) => {
|
||||||
|
toast.error(error.response?.data?.errors?.[0]?.cause || 'Delete failed')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return { createVendor, updateVendor, deleteVendor }
|
||||||
|
}
|
||||||
115
src/views/apps/vendor/list/AddVendorDrawer.tsx
vendored
115
src/views/apps/vendor/list/AddVendorDrawer.tsx
vendored
@ -18,40 +18,12 @@ 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'
|
||||||
// Backend Types
|
import { useVendorsMutation } from '@/services/mutations/vendor'
|
||||||
export interface VendorRequest {
|
|
||||||
name: string
|
|
||||||
email?: string
|
|
||||||
phone_number?: string
|
|
||||||
address?: string
|
|
||||||
contact_person?: string
|
|
||||||
tax_number?: string
|
|
||||||
payment_terms?: string
|
|
||||||
notes?: string
|
|
||||||
is_active: boolean
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Vendor {
|
|
||||||
id: string
|
|
||||||
organization_id: string
|
|
||||||
name: string
|
|
||||||
email?: string
|
|
||||||
phone_number?: string
|
|
||||||
address?: string
|
|
||||||
contact_person?: string
|
|
||||||
tax_number?: string
|
|
||||||
payment_terms?: string
|
|
||||||
notes?: string
|
|
||||||
is_active: boolean
|
|
||||||
created_at: string
|
|
||||||
updated_at: string
|
|
||||||
}
|
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
open: boolean
|
open: boolean
|
||||||
handleClose: () => void
|
handleClose: () => void
|
||||||
onSubmit?: (vendorRequest: VendorRequest) => Promise<void>
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type FormValidateType = {
|
type FormValidateType = {
|
||||||
@ -81,12 +53,14 @@ const initialData: FormValidateType = {
|
|||||||
|
|
||||||
const AddVendorDrawer = (props: Props) => {
|
const AddVendorDrawer = (props: Props) => {
|
||||||
// Props
|
// Props
|
||||||
const { open, handleClose, onSubmit } = props
|
const { open, handleClose } = props
|
||||||
|
|
||||||
// States
|
// States
|
||||||
const [showMore, setShowMore] = useState(false)
|
const [showMore, setShowMore] = useState(false)
|
||||||
const [isSubmitting, setIsSubmitting] = useState(false)
|
const [isSubmitting, setIsSubmitting] = useState(false)
|
||||||
|
|
||||||
|
const { createVendor, updateVendor } = useVendorsMutation()
|
||||||
|
|
||||||
// Hooks
|
// Hooks
|
||||||
const {
|
const {
|
||||||
control,
|
control,
|
||||||
@ -114,29 +88,12 @@ const AddVendorDrawer = (props: Props) => {
|
|||||||
is_active: data.is_active
|
is_active: data.is_active
|
||||||
}
|
}
|
||||||
|
|
||||||
// Call the onSubmit prop if provided (for API call)
|
createVendor.mutate(vendorRequest, {
|
||||||
if (onSubmit) {
|
onSuccess: () => {
|
||||||
await onSubmit(vendorRequest)
|
handleReset()
|
||||||
} else {
|
handleClose()
|
||||||
// Fallback: Create local vendor object for local state update
|
|
||||||
const newVendor: Vendor = {
|
|
||||||
id: `temp-${Date.now()}`, // Temporary ID
|
|
||||||
organization_id: 'current-org', // Should be provided by context
|
|
||||||
name: vendorRequest.name,
|
|
||||||
email: vendorRequest.email,
|
|
||||||
phone_number: vendorRequest.phone_number,
|
|
||||||
address: vendorRequest.address,
|
|
||||||
contact_person: vendorRequest.contact_person,
|
|
||||||
tax_number: vendorRequest.tax_number,
|
|
||||||
payment_terms: vendorRequest.payment_terms,
|
|
||||||
notes: vendorRequest.notes,
|
|
||||||
is_active: vendorRequest.is_active,
|
|
||||||
created_at: new Date().toISOString(),
|
|
||||||
updated_at: new Date().toISOString()
|
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
|
|
||||||
handleReset()
|
|
||||||
} 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.)
|
||||||
@ -214,12 +171,13 @@ const AddVendorDrawer = (props: Props) => {
|
|||||||
{/* Email */}
|
{/* Email */}
|
||||||
<div>
|
<div>
|
||||||
<Typography variant='body2' className='mb-2'>
|
<Typography variant='body2' className='mb-2'>
|
||||||
Email
|
Email <span className='text-red-500'>*</span>
|
||||||
</Typography>
|
</Typography>
|
||||||
<Controller
|
<Controller
|
||||||
name='email'
|
name='email'
|
||||||
control={control}
|
control={control}
|
||||||
rules={{
|
rules={{
|
||||||
|
required: 'Email wajib diisi',
|
||||||
pattern: {
|
pattern: {
|
||||||
value: /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i,
|
value: /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i,
|
||||||
message: 'Format email tidak valid'
|
message: 'Format email tidak valid'
|
||||||
@ -241,24 +199,35 @@ const AddVendorDrawer = (props: Props) => {
|
|||||||
{/* Nomor Telepon */}
|
{/* Nomor Telepon */}
|
||||||
<div>
|
<div>
|
||||||
<Typography variant='body2' className='mb-2'>
|
<Typography variant='body2' className='mb-2'>
|
||||||
Nomor Telepon
|
Nomor Telepon <span className='text-red-500'>*</span>
|
||||||
</Typography>
|
</Typography>
|
||||||
<Controller
|
<Controller
|
||||||
name='phone_number'
|
name='phone_number'
|
||||||
control={control}
|
control={control}
|
||||||
render={({ field }) => <CustomTextField {...field} fullWidth placeholder='Nomor telepon vendor' />}
|
rules={{ required: 'Telepon wajib diisi' }}
|
||||||
|
render={({ field }) => (
|
||||||
|
<CustomTextField {...field} fullWidth placeholder='Harus Diawali 62' error={!!errors.phone_number} />
|
||||||
|
)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Contact Person */}
|
{/* Contact Person */}
|
||||||
<div>
|
<div>
|
||||||
<Typography variant='body2' className='mb-2'>
|
<Typography variant='body2' className='mb-2'>
|
||||||
Contact Person
|
Contact Person <span className='text-red-500'>*</span>
|
||||||
</Typography>
|
</Typography>
|
||||||
<Controller
|
<Controller
|
||||||
name='contact_person'
|
name='contact_person'
|
||||||
control={control}
|
control={control}
|
||||||
render={({ field }) => <CustomTextField {...field} fullWidth placeholder='Nama contact person' />}
|
rules={{ required: 'Contact Person wajib diisi' }}
|
||||||
|
render={({ field }) => (
|
||||||
|
<CustomTextField
|
||||||
|
{...field}
|
||||||
|
fullWidth
|
||||||
|
placeholder='Nama contact person'
|
||||||
|
error={!!errors.contact_person}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -278,12 +247,15 @@ const AddVendorDrawer = (props: Props) => {
|
|||||||
|
|
||||||
{/* Tampilkan selengkapnya */}
|
{/* Tampilkan selengkapnya */}
|
||||||
{!showMore && (
|
{!showMore && (
|
||||||
<div className='flex items-center gap-3 cursor-pointer' onClick={() => setShowMore(true)}>
|
<Button
|
||||||
<i className='tabler-plus text-blue-500' />
|
variant='text'
|
||||||
<Typography variant='body1' color='primary'>
|
color='primary'
|
||||||
Tampilkan selengkapnya
|
size='small'
|
||||||
</Typography>
|
sx={{ textTransform: 'none', fontSize: '14px', p: 0, textAlign: 'left', width: '200px' }}
|
||||||
</div>
|
onClick={() => setShowMore(true)}
|
||||||
|
>
|
||||||
|
+ Tampilkan selengkapnya
|
||||||
|
</Button>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Konten tambahan */}
|
{/* Konten tambahan */}
|
||||||
@ -358,12 +330,15 @@ const AddVendorDrawer = (props: Props) => {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Sembunyikan */}
|
{/* Sembunyikan */}
|
||||||
<div className='flex items-center gap-3 cursor-pointer' onClick={() => setShowMore(false)}>
|
<Button
|
||||||
<i className='tabler-minus text-blue-500' />
|
variant='text'
|
||||||
<Typography variant='body1' color='primary'>
|
color='primary'
|
||||||
Sembunyikan
|
size='small'
|
||||||
</Typography>
|
sx={{ textTransform: 'none', fontSize: '14px', p: 0, textAlign: 'left', width: '200px' }}
|
||||||
</div>
|
onClick={() => setShowMore(false)}
|
||||||
|
>
|
||||||
|
- Sembunyikan
|
||||||
|
</Button>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -235,7 +235,6 @@ const VendorListTable = () => {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Card>
|
<Card>
|
||||||
<CardHeader title='Filter' className='pbe-4' />
|
|
||||||
{/* <TableFilters setData={setFilteredData} tableData={data} /> */}
|
{/* <TableFilters setData={setFilteredData} tableData={data} /> */}
|
||||||
<div className='flex justify-between flex-col items-start md:flex-row md:items-center p-6 border-bs gap-4'>
|
<div className='flex justify-between flex-col items-start md:flex-row md:items-center p-6 border-bs gap-4'>
|
||||||
<CustomTextField
|
<CustomTextField
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user