Seth0330 commited on
Commit
135b02e
·
verified ·
1 Parent(s): 4a66e91

Create admin/MembershipInviteForm.jsx

Browse files
frontend/src/components/admin/MembershipInviteForm.jsx ADDED
@@ -0,0 +1,108 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // frontend/src/components/admin/MembershipInviteForm.jsx
2
+ import React, { useState } from "react";
3
+ import { Send, X } from "lucide-react";
4
+
5
+ export default function MembershipInviteForm({
6
+ plans,
7
+ onSend,
8
+ onCancel,
9
+ isLoading,
10
+ }) {
11
+ const [email, setEmail] = useState("parent@email.com");
12
+ const [selectedPlanId, setSelectedPlanId] = useState("");
13
+ const [classDetails, setClassDetails] = useState("");
14
+
15
+ const selectedPlan = plans.find((p) => p.id === parseInt(selectedPlanId));
16
+
17
+ const handleSubmit = (e) => {
18
+ e.preventDefault();
19
+ if (!email.trim() || !selectedPlanId) {
20
+ return;
21
+ }
22
+
23
+ onSend({
24
+ email: email.trim(),
25
+ plan_id: parseInt(selectedPlanId),
26
+ class_details: classDetails.trim(),
27
+ invited_by: "admin",
28
+ });
29
+ };
30
+
31
+ return (
32
+ <form onSubmit={handleSubmit} className="space-y-4">
33
+ <div>
34
+ <label className="block text-sm font-medium text-stone-700 mb-1.5">
35
+ Email Address
36
+ </label>
37
+ <input
38
+ type="email"
39
+ required
40
+ value={email}
41
+ onChange={(e) => setEmail(e.target.value)}
42
+ className="w-full rounded-lg border border-stone-200 px-3 py-2 text-sm focus:outline-none focus:ring-1 focus:ring-red-500 focus:border-red-500"
43
+ placeholder="parent@email.com"
44
+ />
45
+ </div>
46
+
47
+ <div>
48
+ <label className="block text-sm font-medium text-stone-700 mb-1.5">
49
+ Membership Plan
50
+ </label>
51
+ <select
52
+ required
53
+ value={selectedPlanId}
54
+ onChange={(e) => setSelectedPlanId(e.target.value)}
55
+ className="w-full rounded-lg border border-stone-200 px-3 py-2 text-sm focus:outline-none focus:ring-1 focus:ring-red-500 focus:border-red-500"
56
+ >
57
+ <option value="">Select a plan...</option>
58
+ {plans
59
+ .filter((p) => p.is_active)
60
+ .map((plan) => (
61
+ <option key={plan.id} value={plan.id}>
62
+ {plan.name} - ${plan.price}/{plan.billing_period} (Up to{" "}
63
+ {plan.max_students || 1} student{plan.max_students !== 1 ? "s" : ""})
64
+ </option>
65
+ ))}
66
+ </select>
67
+ </div>
68
+
69
+ <div>
70
+ <label className="block text-sm font-medium text-stone-700 mb-1.5">
71
+ Class Information (shown to member)
72
+ </label>
73
+ <textarea
74
+ value={classDetails}
75
+ onChange={(e) => setClassDetails(e.target.value)}
76
+ rows={4}
77
+ className="w-full rounded-lg border border-stone-200 px-3 py-2 text-sm focus:outline-none focus:ring-1 focus:ring-red-500 focus:border-red-500"
78
+ placeholder="e.g., Beginner Karate - Mon & Wed 4:00 PM, Advanced Karate - Fri 5:00 PM"
79
+ />
80
+ <p className="text-xs text-stone-500 mt-1">
81
+ Describe the classes included so the member knows what they're signing
82
+ up for
83
+ </p>
84
+ </div>
85
+
86
+ <div className="flex items-center justify-end gap-2 pt-2">
87
+ <button
88
+ type="button"
89
+ onClick={onCancel}
90
+ disabled={isLoading}
91
+ className="inline-flex items-center gap-2 rounded-lg border border-stone-200 px-4 py-2 text-sm font-medium text-stone-700 hover:bg-stone-50 disabled:opacity-50"
92
+ >
93
+ <X className="w-4 h-4" />
94
+ Cancel
95
+ </button>
96
+ <button
97
+ type="submit"
98
+ disabled={isLoading || !email.trim() || !selectedPlanId}
99
+ className="inline-flex items-center gap-2 rounded-lg bg-red-600 hover:bg-red-700 text-white text-sm font-medium px-4 py-2 disabled:opacity-50 disabled:cursor-not-allowed"
100
+ >
101
+ <Send className="w-4 h-4" />
102
+ {isLoading ? "Sending..." : "Send Invite"}
103
+ </button>
104
+ </div>
105
+ </form>
106
+ );
107
+ }
108
+