/** * Payment note history. * * The payments table has always had one editable Notes field, so recording why * a refund was issued overwrote whatever was there before, and nothing recorded * when a note was written or by whom. This shows the history instead: existing * entries stay visible as new ones are added, each with its time and author. * * The note stored in the old single field still appears, first and marked as * earlier, because that column carries no author or timestamp of its own. */ import React, { useState } from "react"; import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query"; import { StickyNote, User, Clock } from "lucide-react"; import { Modal } from "../ui/modal"; import { Button } from "../ui/button"; import { __ } from "../../lib/i18n"; import { apiService } from "../../lib/api-client"; import { useToast } from "../ui/toast"; import { formatDateTime } from "../../lib/dateFormat"; export interface PaymentNote { id: number; note: string; author_id: number | null; author_name: string; created_at: string; legacy: boolean; } interface PaymentNotesModalProps { isOpen: boolean; onClose: () => void; paymentId: number | null; paymentReference?: string; /** Hide the composer for roles that may read but not record. */ canAdd?: boolean; } export const PaymentNotesModal: React.FC = ({ isOpen, onClose, paymentId, paymentReference, canAdd = true, }) => { const [draft, setDraft] = useState(""); const { showToast } = useToast(); const queryClient = useQueryClient(); const { data, isLoading } = useQuery({ queryKey: ["payment-notes", paymentId], enabled: isOpen && !!paymentId, queryFn: async () => { const response = await apiService.getPaymentNotes(paymentId as number); const rows = response?.data ?? response; return Array.isArray(rows) ? (rows as PaymentNote[]) : []; }, }); const notes = data ?? []; const addNote = useMutation({ mutationFn: async (note: string) => apiService.addPaymentNote(paymentId as number, note), onSuccess: (response: any) => { if (response && response.success === false) { showToast( response.message || __("Failed to save the note.", "yatra"), "error", ); return; } setDraft(""); queryClient.invalidateQueries({ queryKey: ["payment-notes", paymentId] }); queryClient.invalidateQueries({ queryKey: ["payments"] }); showToast(__("Note added.", "yatra"), "success"); }, onError: (error: any) => { showToast( error?.message || __("Failed to save the note.", "yatra"), "error", ); }, }); const handleSubmit = () => { const note = draft.trim(); if (!note) { showToast(__("Please write a note before saving.", "yatra"), "error"); return; } addNote.mutate(note); }; return ( {__("Payment Notes", "yatra")} {paymentReference ? ( {paymentReference} ) : null} } description={__( "Everything recorded against this payment, oldest first. Adding a note never changes the ones already here.", "yatra", )} >
{isLoading ? (

{__("Loading notes…", "yatra")}

) : notes.length === 0 ? (

{__("No notes recorded against this payment yet.", "yatra")}

) : (
    {notes.map((note, index) => (
  1. {note.note}

    {note.author_name || __("Unknown", "yatra")} {formatDateTime(note.created_at)} {note.legacy ? ( {__( "Recorded before notes were kept as a history", "yatra", )} ) : null}
  2. ))}
)} {canAdd ? (