From 024c3b9b1b06c7f9b528ec55475e7712f2610699 Mon Sep 17 00:00:00 2001 From: mijinummi Date: Sun, 22 Feb 2026 23:12:03 +0100 Subject: [PATCH 1/2] feat(frontend): add condition fulfillment component with evidence submission (#70) --- .../component/escrow/ConditionItem.tsx | 44 +++++++++++++++++++ .../component/escrow/ConditionsList.tsx | 26 +++++++++++ .../escrow/FulfillConditionModal.tsx | 40 +++++++++++++++++ 3 files changed, 110 insertions(+) create mode 100644 apps/frontend/component/escrow/ConditionItem.tsx create mode 100644 apps/frontend/component/escrow/ConditionsList.tsx create mode 100644 apps/frontend/component/escrow/FulfillConditionModal.tsx diff --git a/apps/frontend/component/escrow/ConditionItem.tsx b/apps/frontend/component/escrow/ConditionItem.tsx new file mode 100644 index 0000000..b87e5f6 --- /dev/null +++ b/apps/frontend/component/escrow/ConditionItem.tsx @@ -0,0 +1,44 @@ +import React, { useState } from 'react'; +import FulfillConditionModal from './FulfillConditionModal'; + +interface Condition { + id: string; + description: string; + fulfilled: boolean; + confirmed: boolean; +} + +interface Props { + condition: Condition; + role: 'seller' | 'buyer'; +} + +const ConditionItem: React.FC = ({ condition, role }) => { + const [showModal, setShowModal] = useState(false); + + const handleFulfill = () => setShowModal(true); + const handleConfirm = async () => { + // API call to confirm condition + await fetch(`/api/escrow/conditions/${condition.id}/confirm`, { method: 'POST' }); + }; + + return ( +
+

{condition.description}

+ {role === 'seller' && !condition.fulfilled && ( + + )} + {role === 'buyer' && condition.fulfilled && !condition.confirmed && ( + + )} + {showModal && ( + setShowModal(false)} + /> + )} +
+ ); +}; + +export default ConditionItem; diff --git a/apps/frontend/component/escrow/ConditionsList.tsx b/apps/frontend/component/escrow/ConditionsList.tsx new file mode 100644 index 0000000..8f1086c --- /dev/null +++ b/apps/frontend/component/escrow/ConditionsList.tsx @@ -0,0 +1,26 @@ +import React from 'react'; +import ConditionItem from './ConditionItem'; + +interface Condition { + id: string; + description: string; + fulfilled: boolean; + confirmed: boolean; +} + +interface Props { + conditions: Condition[]; + role: 'seller' | 'buyer'; +} + +const ConditionsList: React.FC = ({ conditions, role }) => { + return ( +
+ {conditions.map((condition) => ( + + ))} +
+ ); +}; + +export default ConditionsList; diff --git a/apps/frontend/component/escrow/FulfillConditionModal.tsx b/apps/frontend/component/escrow/FulfillConditionModal.tsx new file mode 100644 index 0000000..412e3ae --- /dev/null +++ b/apps/frontend/component/escrow/FulfillConditionModal.tsx @@ -0,0 +1,40 @@ +import React, { useState } from 'react'; + +interface Props { + conditionId: string; + onClose: () => void; +} + +const FulfillConditionModal: React.FC = ({ conditionId, onClose }) => { + const [notes, setNotes] = useState(''); + const [file, setFile] = useState(null); + + const handleSubmit = async () => { + const formData = new FormData(); + formData.append('notes', notes); + if (file) formData.append('evidence', file); + + await fetch(`/api/escrow/conditions/${conditionId}/fulfill`, { + method: 'POST', + body: formData, + }); + + onClose(); + }; + + return ( +
+

Fulfill Condition

+