You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

208 lines
7.3 KiB
TypeScript

'use client';
import { useState, useEffect } from 'react';
import { Loader2 } from 'lucide-react';
import Modal from '@/src/components/modals/Modal';
import ModalHeader from '@/src/components/modals/ModalHeader';
import ModalBody from '@/src/components/modals/ModalBody';
import ModalFooter from '@/src/components/modals/ModalFooter';
import PlanEntitlementsEditor from './PlanEntitlementsEditor';
import { getEntitlements, updateEntitlements } from '@/src/lib/api/facility-admin';
import type { MembershipPlan, PlanEntitlements } from '@/src/types/facility-admin';
interface EntitlementsConfigModalProps {
isOpen: boolean;
onClose: () => void;
facilityId: number;
plan: MembershipPlan;
onSuccess: () => void;
}
export default function EntitlementsConfigModal({
isOpen,
onClose,
facilityId,
plan,
onSuccess
}: EntitlementsConfigModalProps) {
const [entitlements, setEntitlements] = useState<PlanEntitlements>({});
const [loading, setLoading] = useState(true);
const [submitting, setSubmitting] = useState(false);
const [error, setError] = useState<string | null>(null);
useEffect(() => {
if (isOpen) {
fetchEntitlements();
}
}, [isOpen, plan.facility_membership_plan_id]);
async function fetchEntitlements() {
setLoading(true);
setError(null);
const result = await getEntitlements(facilityId, plan.facility_membership_plan_id);
if (result.success) {
setEntitlements(result.data);
} else {
setError(result.error.detail || 'Failed to load entitlements');
}
setLoading(false);
}
async function handleSubmit(e: React.FormEvent) {
e.preventDefault();
setSubmitting(true);
setError(null);
const result = await updateEntitlements(
facilityId,
plan.facility_membership_plan_id,
entitlements
);
setSubmitting(false);
if (result.success) {
onSuccess();
onClose();
} else {
setError(result.error.detail || 'Failed to update entitlements');
}
}
return (
<Modal isOpen={isOpen} onClose={onClose} size="lg">
<form onSubmit={handleSubmit}>
<ModalHeader onClose={onClose}>
Configure Entitlements: {plan.name}
</ModalHeader>
<ModalBody>
{error && (
<div className="bg-red-50 border border-red-200 text-red-700 px-4 py-3 rounded-lg mb-4">
{error}
</div>
)}
{loading ? (
<div className="flex items-center justify-center py-12">
<Loader2 className="w-8 h-8 text-purple-600 animate-spin" />
<span className="ml-2 text-gray-600">Loading entitlements...</span>
</div>
) : (
<div className="space-y-6">
{/* Basic Entitlements */}
<div className="space-y-4">
<h3 className="text-sm font-semibold text-gray-700 uppercase tracking-wide">
Booking Limits
</h3>
<div className="grid grid-cols-2 gap-4">
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">
Max Active Bookings
</label>
<input
type="number"
min="0"
value={entitlements.max_active_bookings ?? ''}
onChange={e => setEntitlements({
...entitlements,
max_active_bookings: e.target.value ? parseInt(e.target.value, 10) : undefined
})}
className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-purple-500"
placeholder="Unlimited"
disabled={submitting}
/>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">
Advance Booking Window (days)
</label>
<input
type="number"
min="0"
value={entitlements.advance_window_days ?? ''}
onChange={e => setEntitlements({
...entitlements,
advance_window_days: e.target.value ? parseInt(e.target.value, 10) : undefined
})}
className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-purple-500"
placeholder="Default"
disabled={submitting}
/>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">
Daily Free Bookings
</label>
<input
type="number"
min="0"
value={entitlements.daily_free_bookings ?? ''}
onChange={e => setEntitlements({
...entitlements,
daily_free_bookings: e.target.value ? parseInt(e.target.value, 10) : undefined
})}
className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-purple-500"
placeholder="None"
disabled={submitting}
/>
</div>
<div className="flex items-center pt-6">
<label className="flex items-center space-x-2">
<input
type="checkbox"
checked={entitlements.can_book ?? true}
onChange={e => setEntitlements({
...entitlements,
can_book: e.target.checked
})}
className="w-4 h-4 text-purple-600 border-gray-300 rounded focus:ring-purple-500"
disabled={submitting}
/>
<span className="text-sm text-gray-700">Can make bookings</span>
</label>
</div>
</div>
</div>
{/* Pay-Per-Court Settings */}
<div className="pt-4">
<PlanEntitlementsEditor
entitlements={entitlements}
onChange={setEntitlements}
disabled={submitting}
/>
</div>
</div>
)}
</ModalBody>
<ModalFooter>
<button
type="button"
onClick={onClose}
className="px-4 py-2 text-gray-600 hover:text-gray-800 font-medium transition-colors"
disabled={submitting}
>
Cancel
</button>
<button
type="submit"
disabled={submitting || loading}
className="bg-gradient-to-r from-purple-600 to-indigo-600 hover:from-purple-700 hover:to-indigo-700 disabled:opacity-50 disabled:cursor-not-allowed text-white px-6 py-2 rounded-lg font-semibold shadow-md transition-all duration-200"
>
{submitting ? 'Saving...' : 'Save Entitlements'}
</button>
</ModalFooter>
</form>
</Modal>
);
}