|
2 | 2 |
|
3 | 3 | import { useState } from "react";
|
4 | 4 | import { UserType } from "@prisma/client";
|
| 5 | +import { Open_Sans } from "next/font/google"; |
| 6 | +import { useRouter } from "next/navigation"; |
| 7 | + |
| 8 | +const openSans = Open_Sans({ subsets: ["latin"], weight: ["400", "600", "700"] }); |
5 | 9 |
|
6 | 10 | interface InviteUserFormProps {
|
7 | 11 | closeModal: () => void;
|
8 | 12 | onSubmit: (role: UserType) => void;
|
9 | 13 | }
|
10 | 14 |
|
11 | 15 | export default function InviteUserForm({ closeModal, onSubmit }: InviteUserFormProps) {
|
| 16 | + const router = useRouter(); |
12 | 17 | const [name, setName] = useState("");
|
13 | 18 | const [email, setEmail] = useState("");
|
14 | 19 | const [role, setRole] = useState<UserType | "">("");
|
15 |
| - const [step, setStep] = useState(1); |
| 20 | + const [dropdownOpen, setDropdownOpen] = useState(false); |
| 21 | + const [errorMessage, setErrorMessage] = useState(""); |
| 22 | + const [success, setSuccess] = useState(false); |
16 | 23 |
|
17 |
| - const handleSubmit = (event: React.FormEvent) => { |
| 24 | + const handleSubmit = async (event: React.FormEvent) => { |
18 | 25 | event.preventDefault();
|
19 | 26 |
|
20 |
| - if (!role) { |
21 |
| - console.error("Role is not selected"); |
| 27 | + if (!name.trim() || !email.trim() || !role) { |
| 28 | + setErrorMessage("All fields are required."); |
22 | 29 | return;
|
23 | 30 | }
|
24 | 31 |
|
25 |
| - if (role === "SUPER_ADMIN" || role === "ADMIN" || role === "STAFF") { |
26 |
| - onSubmit(role as UserType); |
27 |
| - setStep(2); |
28 |
| - } else { |
| 32 | + //if the role is PARTNER, go to account creation without sending an invite |
| 33 | + if (role === "PARTNER") { |
| 34 | + closeModal(); |
| 35 | + router.push(`/create-partner-account?name=${encodeURIComponent(name)}&email=${encodeURIComponent(email)}`); |
| 36 | + return; |
| 37 | + } |
| 38 | + |
| 39 | + //otherwise, send invite immediately |
| 40 | + try { |
| 41 | + const response = await fetch("/api/invites", { |
| 42 | + method: "POST", |
| 43 | + headers: { "Content-Type": "application/x-www-form-urlencoded" }, |
| 44 | + body: new URLSearchParams({ |
| 45 | + email, |
| 46 | + name, |
| 47 | + userType: role.toUpperCase(), |
| 48 | + }).toString(), |
| 49 | + }); |
| 50 | + |
| 51 | + if (!response.ok) throw new Error("Couldn't send invite."); |
| 52 | + |
| 53 | + setSuccess(true); |
29 | 54 | onSubmit(role as UserType);
|
| 55 | + } catch (error) { |
| 56 | + setErrorMessage("Couldn't send invite. Please try again."); |
30 | 57 | }
|
31 | 58 | };
|
32 | 59 |
|
33 | 60 | return (
|
34 |
| - <div className="fixed inset-0 flex items-center justify-center bg-black bg-opacity-50"> |
35 |
| - <div className="bg-white p-6 rounded-lg shadow-lg w-96"> |
36 |
| - {step === 1 ? ( |
| 61 | + <div className={`fixed inset-0 flex items-center justify-center bg-black bg-opacity-50 ${openSans.className}`}> |
| 62 | + <div className="bg-white p-6 rounded-[16px] w-[450px] relative"> |
| 63 | + {success ? ( |
| 64 | + <> |
| 65 | + <h2 className="text-[24px] font-bold text-[#22070B] mb-4">Add new account</h2> |
| 66 | + <button className="text-[24px] absolute top-4 right-4 mr-3 text-[#22070B]" onClick={closeModal}>✕</button> |
| 67 | + <p className="text-[16px] text-[#22070B]/70 mb-4"> |
| 68 | + An email has been sent to finalize account creation. This account is currently pending. |
| 69 | + </p> |
| 70 | + <p className="text-[16px] text-[#22070B]/70 mb-8"> |
| 71 | + You can view the current status from the account management page. |
| 72 | + </p> |
| 73 | + <div className="flex justify-center mb-8"> |
| 74 | + <img src="/assets/blue_arrow.svg" alt="Success" className="w-30 h-30" /> |
| 75 | + </div> |
| 76 | + |
| 77 | + <button |
| 78 | + className="bg-mediumRed text-white px-6 py-3 rounded-[4px] font-semibold w-full" |
| 79 | + onClick={closeModal} |
| 80 | + > |
| 81 | + Back to account management |
| 82 | + </button> |
| 83 | + </> |
| 84 | + ) : ( |
37 | 85 | <>
|
38 |
| - <h2 className="text-xl font-bold mb-4">Add new account</h2> |
39 |
| - <button className="absolute top-4 right-4" onClick={closeModal}>✕</button> |
| 86 | + <h2 className="text-[24px] font-bold text-[#22070B] mb-4">Add new account</h2> |
| 87 | + <button className="absolute top-4 right-4 text-[#22070B]" onClick={closeModal}>✕</button> |
40 | 88 | <form onSubmit={handleSubmit}>
|
41 |
| - <label className="block mb-2">Name</label> |
| 89 | + <label className="block text-[16px] text-[#22070B] mb-2">Name</label> |
42 | 90 | <input
|
43 | 91 | type="text"
|
44 |
| - className="w-full p-2 border rounded mb-2" |
| 92 | + className="w-full p-3 border bg-[#F9F9F9] text-[16px] text-[#22070B] rounded-[4px] mb-5" |
| 93 | + placeholder="Name" |
45 | 94 | value={name}
|
46 | 95 | onChange={(e) => setName(e.target.value)}
|
47 | 96 | required
|
48 | 97 | />
|
49 | 98 |
|
50 |
| - <label className="block mb-2">Email</label> |
| 99 | + <label className="block text-[16px] text-[#22070B] mb-2">Email</label> |
51 | 100 | <input
|
52 | 101 | type="email"
|
53 |
| - className="w-full p-2 border rounded mb-2" |
| 102 | + className="w-full p-3 border bg-[#F9F9F9] text-[16px] text-[#22070B] rounded-[4px] mb-5" |
| 103 | + placeholder="Email" |
54 | 104 | value={email}
|
55 | 105 | onChange={(e) => setEmail(e.target.value)}
|
56 | 106 | required
|
57 | 107 | />
|
58 | 108 |
|
59 |
| - <label className="block mb-2">Role</label> |
60 |
| - <select |
61 |
| - className="w-full p-2 border rounded mb-4" |
62 |
| - value={role} |
63 |
| - onChange={(e) => setRole(e.target.value as UserType)} |
64 |
| - required |
65 |
| - > |
66 |
| - <option value="" disabled>Select a role</option> |
67 |
| - {Object.values(UserType).map((roleOption) => ( |
68 |
| - <option key={roleOption} value={roleOption}>{roleOption}</option> |
69 |
| - ))} |
70 |
| - </select> |
71 |
| - |
72 |
| - <div className="flex justify-between"> |
73 |
| - <button |
74 |
| - type="button" |
75 |
| - className="border border-mainRed text-mainRed px-4 py-2 rounded" |
76 |
| - onClick={closeModal} |
77 |
| - > |
| 109 | + <label className="block text-[16px] text-[#22070B] mb-2">Role</label> |
| 110 | + <div className="relative w-full"> |
| 111 | + <button type="button" className="w-full p-3 border bg-[#F9F9F9] text-[16px] text-[#22070B] rounded-[4px] flex justify-between items-center" onClick={() => setDropdownOpen(!dropdownOpen)}> |
| 112 | + {role ? role : "Select a role"} |
| 113 | + <svg className="w-4 h-4 text-[#6B7280]" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"> |
| 114 | + <path strokeLinecap="round" strokeLinejoin="round" d="M19 9l-7 7-7-7" /> |
| 115 | + </svg> |
| 116 | + </button> |
| 117 | + {dropdownOpen && ( |
| 118 | + <div className="w-full bg-white border rounded-[4px] mt-1"> |
| 119 | + {(["SUPER_ADMIN", "ADMIN", "STAFF", "PARTNER"]).map((option) => ( |
| 120 | + <div key={option} className="p-3 text-[16px] text-[#22070B] bg-[#F9F9F9] hover:bg-[#22070B]/10 cursor-pointer" onClick={() => { setRole(option as UserType); setDropdownOpen(false); }}> |
| 121 | + {option} |
| 122 | + </div> |
| 123 | + ))} |
| 124 | + </div> |
| 125 | + )} |
| 126 | + </div> |
| 127 | + |
| 128 | + {errorMessage && <p className="text-red-500 text-sm mt-2">{errorMessage}</p>} |
| 129 | + |
| 130 | + <div className="flex justify-between mt-6"> |
| 131 | + <button type="button" className="border text-mainRed px-6 py-3 rounded-[4px] font-semibold" onClick={closeModal}> |
78 | 132 | Cancel
|
79 | 133 | </button>
|
80 |
| - <button |
81 |
| - type="submit" |
82 |
| - className="bg-mainRed text-white px-4 py-2 rounded" |
83 |
| - > |
| 134 | + <button type="submit" className="bg-mainRed text-white px-6 py-3 rounded-[4px] font-semibold"> |
84 | 135 | {role === "PARTNER" ? "Next" : "Send invite link"}
|
85 | 136 | </button>
|
86 | 137 | </div>
|
87 | 138 | </form>
|
88 | 139 | </>
|
89 |
| - ) : ( |
90 |
| - <> |
91 |
| - <h2 className="text-xl font-bold mb-4">Add new account</h2> |
92 |
| - <button className="absolute top-4 right-4" onClick={closeModal}>✕</button> |
93 |
| - <p className="mb-4">An email has been sent to finalize account creation. This account is currently pending.</p> |
94 |
| - <p className="mb-4">You can view the current status from the account management page.</p> |
95 |
| - <div className="flex justify-center mb-4"> |
96 |
| - <img src="/assets/blue_arrow.svg" alt="Blue Arrow" className="w-12 h-12" /> |
97 |
| - </div> |
98 |
| - <button |
99 |
| - className="bg-mainRed text-white px-4 py-2 rounded w-full" |
100 |
| - onClick={closeModal} |
101 |
| - > |
102 |
| - Back to account management |
103 |
| - </button> |
104 |
| - </> |
105 | 140 | )}
|
106 | 141 | </div>
|
107 | 142 | </div>
|
|
0 commit comments