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
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>
|
|
);
|
|
}
|