discount, referrals and customers page
This commit is contained in:
parent
4ed7161a33
commit
0f9d0b7e6f
|
|
@ -10,17 +10,19 @@ import {
|
||||||
TableRow,
|
TableRow,
|
||||||
} from "@/components/ui/table";
|
} from "@/components/ui/table";
|
||||||
import { apiGet } from "@/lib/api";
|
import { apiGet } from "@/lib/api";
|
||||||
|
import { useAuthStore } from "@/store/authStore";
|
||||||
import type { CustomerRow } from "@/lib/types";
|
import type { CustomerRow } from "@/lib/types";
|
||||||
import { formatDate } from "@/lib/format";
|
import { formatDate } from "@/lib/format";
|
||||||
|
|
||||||
export function CustomersPage() {
|
export function CustomersPage() {
|
||||||
|
const selectedPropertyId = useAuthStore((s) => s.selectedPropertyId);
|
||||||
const [rows, setRows] = useState<CustomerRow[]>([]);
|
const [rows, setRows] = useState<CustomerRow[]>([]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
apiGet<{ data: CustomerRow[] }>("/customers").then((r) =>
|
apiGet<{ data: CustomerRow[] }>("/customers").then((r) =>
|
||||||
setRows(r.data)
|
setRows(r.data)
|
||||||
);
|
);
|
||||||
}, []);
|
}, [selectedPropertyId]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="space-y-6">
|
<div className="space-y-6">
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,9 @@ import {
|
||||||
TableRow,
|
TableRow,
|
||||||
} from "@/components/ui/table";
|
} from "@/components/ui/table";
|
||||||
import { useAuth } from "@/context/AuthContext";
|
import { useAuth } from "@/context/AuthContext";
|
||||||
|
import { useAuthStore } from "@/store/authStore";
|
||||||
import { apiGet, apiPatch, apiPost } from "@/lib/api";
|
import { apiGet, apiPatch, apiPost } from "@/lib/api";
|
||||||
|
import { Spinner } from "@/components/ui/spinner";
|
||||||
import type { DiscountCode } from "@/lib/types";
|
import type { DiscountCode } from "@/lib/types";
|
||||||
|
|
||||||
function copy(s: string) {
|
function copy(s: string) {
|
||||||
|
|
@ -38,18 +40,21 @@ function copy(s: string) {
|
||||||
|
|
||||||
export function DiscountCodesPage() {
|
export function DiscountCodesPage() {
|
||||||
const { canManageCodes } = useAuth();
|
const { canManageCodes } = useAuth();
|
||||||
|
const selectedPropertyId = useAuthStore((s) => s.selectedPropertyId);
|
||||||
const [rows, setRows] = useState<DiscountCode[]>([]);
|
const [rows, setRows] = useState<DiscountCode[]>([]);
|
||||||
|
const [loading, setLoading] = useState(true);
|
||||||
|
const [submitting, setSubmitting] = useState(false);
|
||||||
const [open, setOpen] = useState(false);
|
const [open, setOpen] = useState(false);
|
||||||
const [custom, setCustom] = useState("");
|
const [custom, setCustom] = useState("");
|
||||||
const [generate, setGenerate] = useState(true);
|
|
||||||
const [value, setValue] = useState("10");
|
const [value, setValue] = useState("10");
|
||||||
const [dtype, setDtype] = useState<"percent" | "fixed_amount">("percent");
|
const [dtype, setDtype] = useState<"percent" | "fixed_amount">("percent");
|
||||||
|
|
||||||
const load = useCallback(() => {
|
const load = useCallback(() => {
|
||||||
|
setLoading(true);
|
||||||
apiGet<{ data: DiscountCode[] }>("/discount-codes").then((r) =>
|
apiGet<{ data: DiscountCode[] }>("/discount-codes").then((r) =>
|
||||||
setRows(r.data)
|
setRows(r.data)
|
||||||
);
|
).finally(() => setLoading(false));
|
||||||
}, []);
|
}, [selectedPropertyId]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
load();
|
load();
|
||||||
|
|
@ -57,14 +62,18 @@ export function DiscountCodesPage() {
|
||||||
|
|
||||||
async function create(e: React.FormEvent) {
|
async function create(e: React.FormEvent) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
await apiPost("/discount-codes", {
|
setSubmitting(true);
|
||||||
generate,
|
try {
|
||||||
code: generate ? undefined : custom,
|
await apiPost("/discount-codes", {
|
||||||
discountType: dtype,
|
code: custom,
|
||||||
value: Number(value),
|
discountType: dtype,
|
||||||
});
|
value: Number(value),
|
||||||
setOpen(false);
|
});
|
||||||
load();
|
setOpen(false);
|
||||||
|
load();
|
||||||
|
} finally {
|
||||||
|
setSubmitting(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function toggle(dc: DiscountCode) {
|
async function toggle(dc: DiscountCode) {
|
||||||
|
|
@ -87,24 +96,13 @@ export function DiscountCodesPage() {
|
||||||
<DialogTitle>New discount code</DialogTitle>
|
<DialogTitle>New discount code</DialogTitle>
|
||||||
</DialogHeader>
|
</DialogHeader>
|
||||||
<form onSubmit={create} className="grid gap-3">
|
<form onSubmit={create} className="grid gap-3">
|
||||||
<div className="flex items-center gap-2">
|
|
||||||
<input
|
|
||||||
type="checkbox"
|
|
||||||
checked={generate}
|
|
||||||
onChange={(e) => setGenerate(e.target.checked)}
|
|
||||||
id="gen"
|
|
||||||
/>
|
|
||||||
<Label htmlFor="gen">Auto-generate code</Label>
|
|
||||||
</div>
|
|
||||||
{!generate && (
|
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<Label>Custom code</Label>
|
<Label>Code</Label>
|
||||||
<Input
|
<Input
|
||||||
value={custom}
|
value={custom}
|
||||||
onChange={(e) => setCustom(e.target.value)}
|
onChange={(e) => setCustom(e.target.value)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)}
|
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<Label>Type</Label>
|
<Label>Type</Label>
|
||||||
<Select
|
<Select
|
||||||
|
|
@ -128,7 +126,7 @@ export function DiscountCodesPage() {
|
||||||
onChange={(e) => setValue(e.target.value)}
|
onChange={(e) => setValue(e.target.value)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<Button type="submit">Create</Button>
|
<Button type="submit" loading={submitting}>Create</Button>
|
||||||
</form>
|
</form>
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
|
|
@ -137,7 +135,12 @@ export function DiscountCodesPage() {
|
||||||
|
|
||||||
<Card className="rounded-2xl">
|
<Card className="rounded-2xl">
|
||||||
<CardContent className="pt-6">
|
<CardContent className="pt-6">
|
||||||
<Table>
|
{loading && rows.length === 0 ? (
|
||||||
|
<div className="flex min-h-[400px] items-center justify-center">
|
||||||
|
<Spinner size={32} />
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<Table>
|
||||||
<TableHeader>
|
<TableHeader>
|
||||||
<TableRow>
|
<TableRow>
|
||||||
<TableHead>Code</TableHead>
|
<TableHead>Code</TableHead>
|
||||||
|
|
@ -194,8 +197,9 @@ export function DiscountCodesPage() {
|
||||||
))}
|
))}
|
||||||
</TableBody>
|
</TableBody>
|
||||||
</Table>
|
</Table>
|
||||||
</CardContent>
|
)}
|
||||||
</Card>
|
</CardContent>
|
||||||
|
</Card>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,10 +13,18 @@ import {
|
||||||
SelectValue,
|
SelectValue,
|
||||||
} from "@/components/ui/select";
|
} from "@/components/ui/select";
|
||||||
import { apiGet, apiPost } from "@/lib/api";
|
import { apiGet, apiPost } from "@/lib/api";
|
||||||
|
import {
|
||||||
|
isLikelyApiHotelBooking,
|
||||||
|
isLikelyApiHotelRoom,
|
||||||
|
mapApiBookingToBooking,
|
||||||
|
mapApiRoomToRoom,
|
||||||
|
} from "@/lib/hotel-adapters";
|
||||||
import type { Booking, Room } from "@/lib/types";
|
import type { Booking, Room } from "@/lib/types";
|
||||||
|
import { useAuthStore } from "@/store/authStore";
|
||||||
|
|
||||||
export function NewBookingPage() {
|
export function NewBookingPage() {
|
||||||
const nav = useNavigate();
|
const nav = useNavigate();
|
||||||
|
const selectedPropertyId = useAuthStore((s) => s.selectedPropertyId);
|
||||||
const [rooms, setRooms] = useState<Room[]>([]);
|
const [rooms, setRooms] = useState<Room[]>([]);
|
||||||
const [roomId, setRoomId] = useState("");
|
const [roomId, setRoomId] = useState("");
|
||||||
const [checkIn, setCheckIn] = useState("");
|
const [checkIn, setCheckIn] = useState("");
|
||||||
|
|
@ -30,21 +38,53 @@ export function NewBookingPage() {
|
||||||
const [arrival, setArrival] = useState("14:00");
|
const [arrival, setArrival] = useState("14:00");
|
||||||
const [coupon, setCoupon] = useState("");
|
const [coupon, setCoupon] = useState("");
|
||||||
const [referral, setReferral] = useState("");
|
const [referral, setReferral] = useState("");
|
||||||
|
const [submitting, setSubmitting] = useState(false);
|
||||||
const [err, setErr] = useState<string | null>(null);
|
const [err, setErr] = useState<string | null>(null);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
apiGet<{ data: Room[] }>("/rooms")
|
apiGet<{ data: unknown[] }>("/rooms")
|
||||||
.then((r) => {
|
.then((r) => {
|
||||||
setRooms(r.data);
|
const mapped = r.data.map((row) =>
|
||||||
if (r.data[0]) setRoomId(r.data[0].id);
|
isLikelyApiHotelRoom(row) ? mapApiRoomToRoom(row) : (row as Room)
|
||||||
|
);
|
||||||
|
setRooms(mapped);
|
||||||
|
if (mapped[0]) setRoomId(mapped[0].id);
|
||||||
})
|
})
|
||||||
.catch(console.error);
|
.catch(console.error);
|
||||||
}, []);
|
}, [selectedPropertyId]);
|
||||||
|
|
||||||
async function submit(e: React.FormEvent) {
|
async function submit(e: React.FormEvent) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
setErr(null);
|
setErr(null);
|
||||||
|
setSubmitting(true);
|
||||||
try {
|
try {
|
||||||
|
if (selectedPropertyId) {
|
||||||
|
const customer = await apiPost<{ id: string }>("/customers", {
|
||||||
|
firstName,
|
||||||
|
lastName,
|
||||||
|
email: email || undefined,
|
||||||
|
phone: phone || undefined,
|
||||||
|
});
|
||||||
|
const raw = await apiPost<unknown>("/bookings", {
|
||||||
|
roomId,
|
||||||
|
customerId: customer.id,
|
||||||
|
checkIn,
|
||||||
|
checkOut,
|
||||||
|
guestCount: Number(guests),
|
||||||
|
status: "CONFIRMED",
|
||||||
|
payLaterHold: false,
|
||||||
|
discountCode: coupon.trim() || undefined,
|
||||||
|
referralCode: referral.trim() || undefined,
|
||||||
|
flightPnr: pnr.trim() || undefined,
|
||||||
|
arrivalTime: arrival || undefined,
|
||||||
|
});
|
||||||
|
const created = isLikelyApiHotelBooking(raw)
|
||||||
|
? mapApiBookingToBooking(raw)
|
||||||
|
: (raw as Booking);
|
||||||
|
nav(`/bookings/${created.id}`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const body: Partial<Booking> & Record<string, unknown> = {
|
const body: Partial<Booking> & Record<string, unknown> = {
|
||||||
guest: {
|
guest: {
|
||||||
firstName,
|
firstName,
|
||||||
|
|
@ -67,6 +107,8 @@ export function NewBookingPage() {
|
||||||
nav(`/bookings/${created.id}`);
|
nav(`/bookings/${created.id}`);
|
||||||
} catch (e: unknown) {
|
} catch (e: unknown) {
|
||||||
setErr(e instanceof Error ? e.message : "Failed");
|
setErr(e instanceof Error ? e.message : "Failed");
|
||||||
|
} finally {
|
||||||
|
setSubmitting(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -196,7 +238,7 @@ export function NewBookingPage() {
|
||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
{err && <p className="text-sm text-destructive">{err}</p>}
|
{err && <p className="text-sm text-destructive">{err}</p>}
|
||||||
<Button type="submit">Create booking</Button>
|
<Button type="submit" loading={submitting}>Create booking</Button>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@ import {
|
||||||
TableRow,
|
TableRow,
|
||||||
} from "@/components/ui/table";
|
} from "@/components/ui/table";
|
||||||
import { useAuth } from "@/context/AuthContext";
|
import { useAuth } from "@/context/AuthContext";
|
||||||
|
import { useAuthStore } from "@/store/authStore";
|
||||||
import { apiGet, apiPatch, apiPost } from "@/lib/api";
|
import { apiGet, apiPatch, apiPost } from "@/lib/api";
|
||||||
import type { ReferralCode } from "@/lib/types";
|
import type { ReferralCode } from "@/lib/types";
|
||||||
|
|
||||||
|
|
@ -32,17 +33,17 @@ function copy(s: string) {
|
||||||
|
|
||||||
export function ReferralCodesPage() {
|
export function ReferralCodesPage() {
|
||||||
const { canManageCodes } = useAuth();
|
const { canManageCodes } = useAuth();
|
||||||
|
const selectedPropertyId = useAuthStore((s) => s.selectedPropertyId);
|
||||||
const [rows, setRows] = useState<ReferralCode[]>([]);
|
const [rows, setRows] = useState<ReferralCode[]>([]);
|
||||||
const [open, setOpen] = useState(false);
|
const [open, setOpen] = useState(false);
|
||||||
const [label, setLabel] = useState("");
|
const [code, setCode] = useState("");
|
||||||
const [custom, setCustom] = useState("");
|
const [meta, setMeta] = useState("");
|
||||||
const [generate, setGenerate] = useState(true);
|
|
||||||
|
|
||||||
const load = useCallback(() => {
|
const load = useCallback(() => {
|
||||||
apiGet<{ data: ReferralCode[] }>("/referral-codes").then((r) =>
|
apiGet<{ data: ReferralCode[] }>("/referral-codes").then((r) =>
|
||||||
setRows(r.data)
|
setRows(r.data)
|
||||||
);
|
);
|
||||||
}, []);
|
}, [selectedPropertyId]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
load();
|
load();
|
||||||
|
|
@ -51,12 +52,9 @@ export function ReferralCodesPage() {
|
||||||
async function create(e: React.FormEvent) {
|
async function create(e: React.FormEvent) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
await apiPost("/referral-codes", {
|
await apiPost("/referral-codes", {
|
||||||
generate,
|
code,
|
||||||
code: generate ? undefined : custom,
|
|
||||||
label,
|
|
||||||
});
|
});
|
||||||
setOpen(false);
|
setOpen(false);
|
||||||
setLabel("");
|
|
||||||
load();
|
load();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -80,32 +78,20 @@ export function ReferralCodesPage() {
|
||||||
<DialogTitle>New referral code</DialogTitle>
|
<DialogTitle>New referral code</DialogTitle>
|
||||||
</DialogHeader>
|
</DialogHeader>
|
||||||
<form onSubmit={create} className="grid gap-3">
|
<form onSubmit={create} className="grid gap-3">
|
||||||
<div className="space-y-2">
|
|
||||||
<Label>Campaign label</Label>
|
|
||||||
<Input
|
|
||||||
required
|
|
||||||
value={label}
|
|
||||||
onChange={(e) => setLabel(e.target.value)}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className="flex items-center gap-2">
|
|
||||||
<input
|
|
||||||
type="checkbox"
|
|
||||||
checked={generate}
|
|
||||||
onChange={(e) => setGenerate(e.target.checked)}
|
|
||||||
id="rgen"
|
|
||||||
/>
|
|
||||||
<Label htmlFor="rgen">Auto-generate code</Label>
|
|
||||||
</div>
|
|
||||||
{!generate && (
|
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<Label>Custom code</Label>
|
<Label>Enter name</Label>
|
||||||
<Input
|
<Input
|
||||||
value={custom}
|
value={meta}
|
||||||
onChange={(e) => setCustom(e.target.value)}
|
onChange={(e) => setMeta(e.target.value)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="space-y-2">
|
||||||
|
<Label>Enter code</Label>
|
||||||
|
<Input
|
||||||
|
value={code}
|
||||||
|
onChange={(e) => setCode(e.target.value)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)}
|
|
||||||
<Button type="submit">Create</Button>
|
<Button type="submit">Create</Button>
|
||||||
</form>
|
</form>
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
|
|
@ -120,7 +106,6 @@ export function ReferralCodesPage() {
|
||||||
<TableRow>
|
<TableRow>
|
||||||
<TableHead>Code</TableHead>
|
<TableHead>Code</TableHead>
|
||||||
<TableHead>Label</TableHead>
|
<TableHead>Label</TableHead>
|
||||||
<TableHead>Redemptions</TableHead>
|
|
||||||
<TableHead>Active</TableHead>
|
<TableHead>Active</TableHead>
|
||||||
<TableHead />
|
<TableHead />
|
||||||
</TableRow>
|
</TableRow>
|
||||||
|
|
@ -129,11 +114,7 @@ export function ReferralCodesPage() {
|
||||||
{rows.map((r) => (
|
{rows.map((r) => (
|
||||||
<TableRow key={r.id}>
|
<TableRow key={r.id}>
|
||||||
<TableCell className="font-mono font-medium">{r.code}</TableCell>
|
<TableCell className="font-mono font-medium">{r.code}</TableCell>
|
||||||
<TableCell>{r.label}</TableCell>
|
<TableCell className="font-mono font-medium">{r.meta}</TableCell>
|
||||||
<TableCell>
|
|
||||||
{r.redemptionCount}
|
|
||||||
{r.maxRedemptions != null && ` / ${r.maxRedemptions}`}
|
|
||||||
</TableCell>
|
|
||||||
<TableCell>
|
<TableCell>
|
||||||
<Badge variant={r.isActive ? "success" : "secondary"}>
|
<Badge variant={r.isActive ? "success" : "secondary"}>
|
||||||
{r.isActive ? "Active" : "Off"}
|
{r.isActive ? "Active" : "Off"}
|
||||||
|
|
|
||||||
|
|
@ -28,12 +28,21 @@ import {
|
||||||
TableRow,
|
TableRow,
|
||||||
} from "@/components/ui/table";
|
} from "@/components/ui/table";
|
||||||
import { apiGet, apiPost } from "@/lib/api";
|
import { apiGet, apiPost } from "@/lib/api";
|
||||||
|
import { Spinner } from "@/components/ui/spinner";
|
||||||
|
import {
|
||||||
|
isLikelyApiHotelRoom,
|
||||||
|
mapApiRoomToRoom,
|
||||||
|
} from "@/lib/hotel-adapters";
|
||||||
import { ROOM_CATALOGUE } from "@/lib/constants";
|
import { ROOM_CATALOGUE } from "@/lib/constants";
|
||||||
import type { Room } from "@/lib/types";
|
import type { Room } from "@/lib/types";
|
||||||
import { formatMoney } from "@/lib/format";
|
import { formatMoney } from "@/lib/format";
|
||||||
|
import { useAuthStore } from "@/store/authStore";
|
||||||
|
|
||||||
export function RoomsPage() {
|
export function RoomsPage() {
|
||||||
|
const selectedPropertyId = useAuthStore((s) => s.selectedPropertyId);
|
||||||
const [rooms, setRooms] = useState<Room[]>([]);
|
const [rooms, setRooms] = useState<Room[]>([]);
|
||||||
|
const [loading, setLoading] = useState(true);
|
||||||
|
const [submitting, setSubmitting] = useState(false);
|
||||||
const [open, setOpen] = useState(false);
|
const [open, setOpen] = useState(false);
|
||||||
const [name, setName] = useState("");
|
const [name, setName] = useState("");
|
||||||
const [slug, setSlug] = useState(ROOM_CATALOGUE[0].slug);
|
const [slug, setSlug] = useState(ROOM_CATALOGUE[0].slug);
|
||||||
|
|
@ -41,28 +50,43 @@ export function RoomsPage() {
|
||||||
const [baseRate, setBaseRate] = useState("120");
|
const [baseRate, setBaseRate] = useState("120");
|
||||||
|
|
||||||
function load() {
|
function load() {
|
||||||
apiGet<{ data: Room[] }>("/rooms").then((r) => setRooms(r.data));
|
setLoading(true);
|
||||||
|
apiGet<{ data: unknown[] }>("/rooms").then((r) => {
|
||||||
|
const mapped = r.data.map((row) =>
|
||||||
|
isLikelyApiHotelRoom(row) ? mapApiRoomToRoom(row) : (row as Room)
|
||||||
|
);
|
||||||
|
setRooms(mapped);
|
||||||
|
}).finally(() => setLoading(false));
|
||||||
}
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
load();
|
load();
|
||||||
}, []);
|
}, [selectedPropertyId]);
|
||||||
|
|
||||||
async function addRoom(e: React.FormEvent) {
|
async function addRoom(e: React.FormEvent) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
await apiPost<Room>("/rooms", {
|
setSubmitting(true);
|
||||||
name,
|
try {
|
||||||
roomTypeSlug: slug,
|
await apiPost<Room>("/rooms", {
|
||||||
maxGuests: Number(maxGuests),
|
name,
|
||||||
baseRate: Number(baseRate),
|
roomType: slug,
|
||||||
status: "available",
|
maxGuests: Number(maxGuests),
|
||||||
floor: "",
|
baseRate: Number(baseRate),
|
||||||
});
|
});
|
||||||
setOpen(false);
|
setOpen(false);
|
||||||
setName("");
|
setName("");
|
||||||
load();
|
load();
|
||||||
|
} finally {
|
||||||
|
setSubmitting(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (loading && rooms.length === 0) return (
|
||||||
|
<div className="flex min-h-[400px] items-center justify-center">
|
||||||
|
<Spinner size={32} />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="space-y-6">
|
<div className="space-y-6">
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
|
|
@ -118,7 +142,7 @@ export function RoomsPage() {
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<Button type="submit">Save</Button>
|
<Button type="submit" loading={submitting}>Save</Button>
|
||||||
</form>
|
</form>
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user