All files / src/components/admin/pros CreateProModal.tsx

96.29% Statements 26/27
75% Branches 6/8
100% Functions 4/4
100% Lines 25/25

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115                            252x 252x 252x 252x   252x 8x 8x 8x 8x 8x       5x 5x 5x 5x     3x 3x   8x       252x 5x 5x 5x     252x   252x   102x                                                                                   58x                                          
import { useState } from "react";
import { useNavigate } from "@tanstack/react-router";
import { X } from "lucide-react";
import { Button } from "../../ui/button";
import { Input } from "../../ui/input";
import { adminApi } from "../../../lib/api";
import { useDialogAccessibility } from "../../../hooks";
 
interface CreateProModalProps {
	isOpen: boolean;
	onClose: () => void;
}
 
export function CreateProModal({ isOpen, onClose }: CreateProModalProps) {
	const navigate = useNavigate();
	const [businessName, setBusinessName] = useState("");
	const [isCreating, setIsCreating] = useState(false);
	const [error, setError] = useState<string | null>(null);
 
	const handleCreatePro = async () => {
		Iif (!businessName.trim()) return;
		setIsCreating(true);
		setError(null);
		try {
			const result = await adminApi.createPro({
				businessName,
				status: "draft",
			});
			Eif (result.data) {
				onClose();
				setBusinessName("");
				navigate({ to: `/admin/pros/${result.data.id}` });
			}
		} catch (err) {
			console.error("Failed to create pro:", err);
			setError("Failed to create pro");
		} finally {
			setIsCreating(false);
		}
	};
 
	const handleClose = () => {
		onClose();
		setError(null);
		setBusinessName("");
	};
 
	const { dialogRef, handleFocusTrap } = useDialogAccessibility(handleClose);
 
	if (!isOpen) return null;
 
	return (
		<div
			className="fixed inset-0 z-50 flex items-center justify-center bg-black/50"
			tabIndex={-1}
		>
			<div
				ref={dialogRef}
				role="dialog"
				aria-modal="true"
				aria-labelledby="create-pro-dialog-title"
				onKeyDown={handleFocusTrap}
				className="bg-background-elevated rounded-lg shadow-xl w-full max-w-md mx-4"
			>
				<div className="flex items-center justify-between p-4 border-b">
					<h3 id="create-pro-dialog-title" className="text-lg font-semibold">
						Create New Pro
					</h3>
					<button
						type="button"
						onClick={handleClose}
						aria-label="Close"
						className="p-1 hover:bg-background-subtle rounded"
					>
						<X className="h-5 w-5" />
					</button>
				</div>
				<div className="p-4 space-y-4">
					{error && (
						<div className="rounded-md bg-error-light px-3 py-2 text-sm text-error">
							{error}
						</div>
					)}
					<div>
						<label
							htmlFor="new-pro-business-name"
							className="mb-1.5 block text-xs font-semibold uppercase tracking-wider text-foreground-muted"
						>
							Business Name *
						</label>
						<Input
							id="new-pro-business-name"
							value={businessName}
							onChange={(e) => setBusinessName(e.target.value)}
							placeholder="Enter business name"
						/>
					</div>
				</div>
				<div className="flex justify-end gap-2 p-4 border-t">
					<Button variant="outline" onClick={handleClose}>
						Cancel
					</Button>
					<Button
						onClick={handleCreatePro}
						isLoading={isCreating}
						disabled={!businessName.trim()}
					>
						Create Pro
					</Button>
				</div>
			</div>
		</div>
	);
}