detail fixes

This commit is contained in:
Ken Yasue
2025-03-25 07:02:21 +01:00
parent 1866d84a86
commit d713939730
3 changed files with 71 additions and 22 deletions

View File

@ -1,6 +1,6 @@
'use client';
import { useState } from 'react';
import { useState, useEffect } from 'react';
import { useRouter } from 'next/navigation';
import Link from 'next/link';
@ -14,14 +14,55 @@ interface ContactRecord {
}
interface ContactRecordListProps {
contactRecords: ContactRecord[];
customerId: string;
}
export default function ContactRecordList({ contactRecords }: ContactRecordListProps) {
export default function ContactRecordList({ customerId }: ContactRecordListProps) {
const router = useRouter();
const [contactRecords, setContactRecords] = useState<ContactRecord[]>([]);
const [isLoading, setIsLoading] = useState(true);
const [isDeleting, setIsDeleting] = useState<string | null>(null);
const [error, setError] = useState<string | null>(null);
// Function to fetch contact records
const fetchContactRecords = async () => {
setIsLoading(true);
try {
const response = await fetch(`/api/contact-records?customerId=${customerId}`);
if (!response.ok) {
throw new Error('Failed to fetch contact records');
}
const data = await response.json();
setContactRecords(data);
} catch (err) {
setError(err instanceof Error ? err.message : 'An error occurred while fetching contact records');
} finally {
setIsLoading(false);
}
};
// Fetch records on initial load and when customerId changes
useEffect(() => {
fetchContactRecords();
}, [customerId]);
// Refresh data when router.refresh() is called
useEffect(() => {
// Create a callback function that will be called when the component is re-rendered
const refreshData = () => {
fetchContactRecords();
};
// Add an event listener for a custom event that will be dispatched when router.refresh() is called
window.addEventListener('contact-records-refresh', refreshData);
return () => {
window.removeEventListener('contact-records-refresh', refreshData);
};
}, []);
const handleDelete = async (id: string) => {
if (!confirm('Are you sure you want to delete this contact record?')) {
return;
@ -40,7 +81,10 @@ export default function ContactRecordList({ contactRecords }: ContactRecordListP
throw new Error(data.error || 'Failed to delete contact record');
}
// Refresh the page to show updated contact record list
// Refresh the contact records list
fetchContactRecords();
// Refresh the page
router.refresh();
} catch (err) {
setError(err instanceof Error ? err.message : 'An error occurred');
@ -49,6 +93,14 @@ export default function ContactRecordList({ contactRecords }: ContactRecordListP
}
};
if (isLoading) {
return (
<div className="text-center py-8 text-gray-500">
Loading contact records...
</div>
);
}
if (contactRecords.length === 0) {
return (
<div className="text-center py-8 text-gray-500">

View File

@ -61,6 +61,9 @@ export default function NewContactRecordForm({ customerId }: NewContactRecordFor
});
setSuccess(true);
// Dispatch a custom event to notify the ContactRecordList component to refresh
window.dispatchEvent(new Event('contact-records-refresh'));
// Refresh the page to show the new contact record
router.refresh();
} catch (err) {
@ -73,30 +76,30 @@ export default function NewContactRecordForm({ customerId }: NewContactRecordFor
return (
<div>
{error && (
<div className="bg-red-50 border-l-4 border-red-400 p-4 mb-4">
<div className="bg-red-50 border-l-4 border-red-400 p-4 mb-4 dark:bg-red-900/20 dark:border-red-500">
<div className="flex">
<div className="flex-shrink-0">
<svg className="h-5 w-5 text-red-400" viewBox="0 0 20 20" fill="currentColor">
<svg className="h-5 w-5 text-red-400 dark:text-red-300" viewBox="0 0 20 20" fill="currentColor">
<path fillRule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zM8.707 7.293a1 1 0 00-1.414 1.414L8.586 10l-1.293 1.293a1 1 0 101.414 1.414L10 11.414l1.293 1.293a1 1 0 001.414-1.414L11.414 10l1.293-1.293a1 1 0 00-1.414-1.414L10 8.586 8.707 7.293z" clipRule="evenodd" />
</svg>
</div>
<div className="ml-3">
<p className="text-sm text-red-700">{error}</p>
<p className="text-sm text-red-700 dark:text-red-300">{error}</p>
</div>
</div>
</div>
)}
{success && (
<div className="bg-green-50 border-l-4 border-green-400 p-4 mb-4">
<div className="bg-green-50 border-l-4 border-green-400 p-4 mb-4 dark:bg-green-900/20 dark:border-green-500">
<div className="flex">
<div className="flex-shrink-0">
<svg className="h-5 w-5 text-green-400" viewBox="0 0 20 20" fill="currentColor">
<svg className="h-5 w-5 text-green-400 dark:text-green-300" viewBox="0 0 20 20" fill="currentColor">
<path fillRule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clipRule="evenodd" />
</svg>
</div>
<div className="ml-3">
<p className="text-sm text-green-700">Contact record created successfully!</p>
<p className="text-sm text-green-700 dark:text-green-300">Contact record created successfully!</p>
</div>
</div>
</div>
@ -104,7 +107,7 @@ export default function NewContactRecordForm({ customerId }: NewContactRecordFor
<form onSubmit={handleSubmit} className="space-y-4">
<div>
<label htmlFor="contactType" className="block text-sm font-medium text-gray-700">
<label htmlFor="contactType" className="block text-sm font-medium text-gray-700 dark:text-gray-300">
Contact Type
</label>
<select
@ -112,7 +115,7 @@ export default function NewContactRecordForm({ customerId }: NewContactRecordFor
name="contactType"
value={formData.contactType}
onChange={handleChange}
className="mt-1 block w-full pl-3 pr-10 py-2 text-base border-gray-300 focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm rounded-md"
className="mt-1 block w-full pl-3 pr-10 py-2 text-base border-gray-300 focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm rounded-md dark:bg-gray-800 dark:border-gray-700 dark:text-gray-200"
required
>
<option value="">Select a contact type</option>
@ -124,7 +127,7 @@ export default function NewContactRecordForm({ customerId }: NewContactRecordFor
</div>
<div>
<label htmlFor="notes" className="block text-sm font-medium text-gray-700">
<label htmlFor="notes" className="block text-sm font-medium text-gray-700 dark:text-gray-300">
Notes
</label>
<textarea
@ -133,7 +136,7 @@ export default function NewContactRecordForm({ customerId }: NewContactRecordFor
rows={4}
value={formData.notes}
onChange={handleChange}
className="mt-1 block w-full shadow-sm sm:text-sm border-gray-300 rounded-md"
className="mt-1 block w-full shadow-sm sm:text-sm border-gray-300 rounded-md dark:bg-gray-800 dark:border-gray-700 dark:text-gray-200"
placeholder="Enter notes about the contact"
></textarea>
</div>

View File

@ -1,5 +1,5 @@
import Link from 'next/link';
import { getDataSource, Customer, ContactRecord } from '@/lib/database';
import { getDataSource, Customer } from '@/lib/database';
import ContactRecordList from '../../components/ContactRecordList';
import NewContactRecordForm from '../../components/NewContactRecordForm';
@ -9,7 +9,6 @@ export default async function CustomerDetail({ params }: { params: { id: string
// Fetch customer data
const dataSource = await getDataSource();
const customerRepository = dataSource.getRepository(Customer);
const contactRecordRepository = dataSource.getRepository(ContactRecord);
const customer = await customerRepository.findOne({
where: { id }
@ -30,11 +29,6 @@ export default async function CustomerDetail({ params }: { params: { id: string
);
}
// Fetch contact records for this customer
const contactRecords = await contactRecordRepository.find({
where: { customerId: id },
order: { createdAt: 'DESC' }
});
return (
<div>
@ -130,7 +124,7 @@ export default async function CustomerDetail({ params }: { params: { id: string
{/* Contact Records List */}
<div className="border-t border-gray-200">
<ContactRecordList contactRecords={contactRecords} />
<ContactRecordList customerId={id} />
</div>
</div>
</div>