feat(matches): show both manual match requests and auto recording suggestions

Backend:
- Extend GET /api/matches to include RecordingSuggestions alongside Match objects
- Add 'type' field: 'manual' for user-created matches, 'auto' for algorithm suggestions
- Fetch suggestions where user is dancer (to be recorded) or recorder (recording others)
- Transform suggestions to match format with partner info
- Support status filtering for both types

Frontend:
- Display 'Auto' (purple) or 'Manual' (gray) badge on match cards
- For pending auto suggestions: show 'Go to Records' button instead of Accept/Reject
- For accepted auto suggestions without slug: show 'Chat not available yet'
- Only allow Accept/Reject actions on manual match requests
This commit is contained in:
Radosław Gierwiało
2025-11-30 15:30:49 +01:00
parent d8799d03af
commit f45cadae7d
2 changed files with 185 additions and 20 deletions

View File

@@ -47,6 +47,15 @@ const MatchCard = ({ match, onAccept, onReject, onOpenChat, processing }) => {
</div>
<div className="flex items-center gap-2">
{match.type === 'auto' ? (
<span className="text-xs px-2 py-1 bg-purple-100 text-purple-700 rounded-full font-medium">
Auto
</span>
) : (
<span className="text-xs px-2 py-1 bg-gray-100 text-gray-700 rounded-full font-medium">
Manual
</span>
)}
{isIncoming && (
<span className="text-xs px-2 py-1 bg-amber-100 text-amber-700 rounded-full font-medium">
Incoming Request
@@ -66,7 +75,7 @@ const MatchCard = ({ match, onAccept, onReject, onOpenChat, processing }) => {
</div>
<div className="flex items-center gap-2 ml-4">
{isIncoming && (
{isIncoming && match.type === 'manual' && (
<>
<button
onClick={() => onAccept(match.slug)}
@@ -91,7 +100,16 @@ const MatchCard = ({ match, onAccept, onReject, onOpenChat, processing }) => {
</>
)}
{isOutgoing && (
{isIncoming && match.type === 'auto' && (
<Link
to={`/events/${match.event.slug}/chat?tab=records`}
className="px-3 py-1.5 text-sm bg-purple-600 text-white rounded-md hover:bg-purple-700 transition-colors"
>
Go to Records
</Link>
)}
{isOutgoing && match.type === 'manual' && (
<button
onClick={() => onReject(match.slug)}
disabled={processing}
@@ -101,7 +119,16 @@ const MatchCard = ({ match, onAccept, onReject, onOpenChat, processing }) => {
</button>
)}
{isAccepted && (
{isOutgoing && match.type === 'auto' && (
<Link
to={`/events/${match.event.slug}/chat?tab=records`}
className="px-3 py-1.5 text-sm bg-purple-600 text-white rounded-md hover:bg-purple-700 transition-colors"
>
Go to Records
</Link>
)}
{isAccepted && match.slug && (
<button
onClick={() => onOpenChat(match)}
className="flex items-center gap-2 px-4 py-2 bg-primary-600 text-white rounded-md hover:bg-primary-700 transition-colors"
@@ -110,6 +137,12 @@ const MatchCard = ({ match, onAccept, onReject, onOpenChat, processing }) => {
Open Chat
</button>
)}
{isAccepted && !match.slug && (
<span className="text-sm text-gray-500 italic">
Chat not available yet
</span>
)}
</div>
</div>
</div>