374 lines
11 KiB
JavaScript

import React, { useState, useEffect } from 'react'
import { useLocation } from 'react-router-dom'
import axios from 'axios'
import {
Descriptions,
Spin,
Space,
Button,
message,
Typography,
Flex,
Form,
Input,
Collapse
} from 'antd'
import {
LoadingOutlined,
ExportOutlined,
CaretRightOutlined
} from '@ant-design/icons'
import IdText from '../../common/IdText'
import CountrySelect from '../../common/CountrySelect'
import CountryDisplay from '../../common/CountryDisplay'
import TimeDisplay from '../../common/TimeDisplay'
import ReloadIcon from '../../../Icons/ReloadIcon'
import EditIcon from '../../../Icons/EditIcon.jsx'
import XMarkIcon from '../../../Icons/XMarkIcon.jsx'
import CheckIcon from '../../../Icons/CheckIcon.jsx'
import useCollapseState from '../../hooks/useCollapseState'
import config from '../../../../config.js'
const { Title, Link } = Typography
const VendorInfo = () => {
const [vendorData, setVendorData] = useState(null)
const [loading, setLoading] = useState(false)
const [error, setError] = useState(null)
const location = useLocation()
const [messageApi, contextHolder] = message.useMessage()
const vendorId = new URLSearchParams(location.search).get('vendorId')
const [isEditing, setIsEditing] = useState(false)
const [form] = Form.useForm()
const [fetchLoading, setFetchLoading] = useState(true)
const [collapseState, updateCollapseState] = useCollapseState('VendorInfo', {
info: true
})
useEffect(() => {
if (vendorId) {
fetchVendorDetails()
}
}, [vendorId])
useEffect(() => {
if (vendorData) {
form.setFieldsValue({
name: vendorData.name || '',
website: vendorData.website || '',
contact: vendorData.contact || '',
country: vendorData.country || '',
phone: vendorData.phone || '',
email: vendorData.email || ''
})
}
}, [vendorData, form])
const fetchVendorDetails = async () => {
try {
setFetchLoading(true)
const response = await axios.get(
`${config.backendUrl}/vendors/${vendorId}`,
{
headers: {
Accept: 'application/json'
},
withCredentials: true
}
)
setVendorData(response.data)
setError(null)
} catch (err) {
setError('Failed to fetch vendor details')
messageApi.error('Failed to fetch vendor details')
} finally {
setFetchLoading(false)
}
}
const startEditing = () => {
updateCollapseState('info', true)
setIsEditing(true)
}
const cancelEditing = () => {
form.setFieldsValue({
name: vendorData?.name || '',
website: vendorData?.website || '',
contact: vendorData?.contact || '',
country: vendorData?.country || '',
phone: vendorData?.phone || '',
email: vendorData?.email || ''
})
setIsEditing(false)
}
const updateInfo = async () => {
try {
const values = await form.validateFields()
setLoading(true)
await axios.put(`${config.backendUrl}/vendors/${vendorId}`, values, {
headers: {
'Content-Type': 'application/json'
},
withCredentials: true
})
setVendorData({ ...vendorData, ...values })
setIsEditing(false)
messageApi.success('Vendor information updated successfully')
} catch (err) {
if (err.errorFields) {
return
}
console.error('Failed to update vendor information:', err)
messageApi.error('Failed to update vendor information')
} finally {
fetchVendorDetails()
setLoading(false)
}
}
if (fetchLoading) {
return (
<div style={{ textAlign: 'center', padding: '20px' }}>
<Spin indicator={<LoadingOutlined style={{ fontSize: 24 }} spin />} />
</div>
)
}
if (error || !vendorData) {
return (
<Space
direction='vertical'
style={{ width: '100%', textAlign: 'center' }}
>
<p>{error || 'Vendor not found'}</p>
<Button icon={<ReloadIcon />} onClick={fetchVendorDetails}>
Retry
</Button>
</Space>
)
}
return (
<div style={{ height: '100%', minHeight: 0, overflowY: 'auto' }}>
{contextHolder}
<Flex vertical gap={'large'}>
<Collapse
ghost
collapsible='icon'
activeKey={collapseState.info ? ['1'] : []}
onChange={(keys) => updateCollapseState('info', keys.length > 0)}
expandIcon={({ isActive }) => (
<CaretRightOutlined
rotate={isActive ? 90 : 0}
style={{ paddingTop: '9px' }}
/>
)}
className='no-h-padding-collapse no-t-padding-collapse'
>
<Collapse.Panel
header={
<Flex
align='center'
justify='space-between'
style={{ width: '100%' }}
>
<Title level={5} style={{ margin: 0 }}>
Vendor Information
</Title>
<Space>
{isEditing ? (
<>
<Button
icon={<CheckIcon />}
type='primary'
onClick={updateInfo}
loading={loading}
/>
<Button
icon={<XMarkIcon />}
onClick={cancelEditing}
disabled={loading}
/>
</>
) : (
<Button icon={<EditIcon />} onClick={startEditing} />
)}
</Space>
</Flex>
}
key='1'
>
<Form form={form} layout='vertical'>
<Descriptions
bordered
column={{
xs: 1,
sm: 1,
md: 1,
lg: 2,
xl: 2,
xxl: 2
}}
>
<Descriptions.Item label='ID'>
<IdText id={vendorData._id} type='vendor' />
</Descriptions.Item>
<Descriptions.Item label='Created At'>
<TimeDisplay
dateTime={vendorData.createdAt}
showSince={true}
/>
</Descriptions.Item>
<Descriptions.Item label='Name'>
{isEditing ? (
<Form.Item
name='name'
rules={[
{
required: true,
message: 'Please enter a vendor name'
},
{
max: 100,
message: 'Name cannot exceed 100 characters'
}
]}
style={{ margin: 0 }}
>
<Input />
</Form.Item>
) : (
vendorData.name
)}
</Descriptions.Item>
<Descriptions.Item label='Updated At'>
<TimeDisplay
dateTime={vendorData.updatedAt}
showSince={true}
/>
</Descriptions.Item>
<Descriptions.Item label='Website'>
{isEditing ? (
<Form.Item
name='website'
rules={[
{ type: 'url', message: 'Please enter a valid URL' },
{
max: 200,
message: 'Website URL cannot exceed 200 characters'
}
]}
style={{ margin: 0 }}
>
<Input />
</Form.Item>
) : vendorData.website ? (
<Link
href={vendorData.website}
target='_blank'
rel='noopener noreferrer'
>
{new URL(vendorData.website).hostname + ' '}
<ExportOutlined />
</Link>
) : (
'n/a'
)}
</Descriptions.Item>
<Descriptions.Item label='Country'>
{isEditing ? (
<Form.Item name='country' style={{ margin: 0 }}>
<CountrySelect countryCode={vendorData.country} />
</Form.Item>
) : vendorData.country ? (
<CountryDisplay countryCode={vendorData.country} />
) : (
'n/a'
)}
</Descriptions.Item>
<Descriptions.Item label='Contact'>
{isEditing ? (
<Form.Item
name='contact'
rules={[
{
max: 200,
message: 'Contact info cannot exceed 200 characters'
}
]}
style={{ margin: 0 }}
>
<Input />
</Form.Item>
) : vendorData.contact ? (
vendorData.contact
) : (
'n/a'
)}
</Descriptions.Item>
<Descriptions.Item label='Phone'>
{isEditing ? (
<Form.Item
name='phone'
rules={[
{
type: 'phone',
message: 'Please enter a valid phone number'
}
]}
style={{ margin: 0 }}
>
<Input />
</Form.Item>
) : vendorData.phone ? (
vendorData.phone
) : (
'n/a'
)}
</Descriptions.Item>
<Descriptions.Item label='Email'>
{isEditing ? (
<Form.Item
name='email'
rules={[
{
type: 'email',
message: 'Please enter a valid email'
}
]}
style={{ margin: 0 }}
>
<Input />
</Form.Item>
) : vendorData.email ? (
<Link href={`mailto:${vendorData.email}`}>
{vendorData.email + ' '}
<ExportOutlined />
</Link>
) : (
'n/a'
)}
</Descriptions.Item>
</Descriptions>
</Form>
</Collapse.Panel>
</Collapse>
</Flex>
</div>
)
}
export default VendorInfo