Add time rezerv

This commit is contained in:
2026-05-25 19:13:28 +03:30
parent 0b2defd50c
commit 27b73c981a
12 changed files with 803 additions and 45 deletions
+15 -21
View File
@@ -127,19 +127,12 @@
</p>
</div>
<div class="space-y-1.5">
<label for="scheduledAt" class="block text-sm font-medium text-muted">
زمان مراجعه
</label>
<input
id="scheduledAt"
v-model="bookingForm.scheduledAt"
type="datetime-local"
required
class="w-full rounded-xl border border-border bg-surface-2 px-4 py-3 text-text outline-none focus:border-brand-500 focus:ring-2 focus:ring-brand-500/30"
/>
<p class="text-xs text-muted">حداقل یک ساعت بعد از الان</p>
</div>
<BookingSlotPicker
v-model="bookingForm.scheduledAt"
label="تاریخ و ساعت مراجعه (شمسی)"
:business-id="business.id"
:business-service-id="bookingService.id"
/>
<div class="space-y-1.5">
<label for="bookingNote" class="block text-sm font-medium text-muted">
@@ -171,14 +164,11 @@ import { ApiError } from '@/api/client';
import type { Business, BusinessService } from '@/api/types';
import AppButton from '@/components/ui/AppButton.vue';
import AppIcon from '@/components/ui/AppIcon.vue';
import BookingSlotPicker from '@/components/booking/BookingSlotPicker.vue';
import AppModal from '@/components/ui/AppModal.vue';
import WebAppLayout from '@/layouts/WebAppLayout.vue';
import { useAuthStore } from '@/stores/auth';
import {
defaultBookingDateTimeLocal,
formatDuration,
formatPriceToman,
} from '@/utils/format';
import { formatDuration, formatPriceToman } from '@/utils/format';
const route = useRoute();
const router = useRouter();
@@ -196,7 +186,7 @@ const bookingService = ref<BusinessService | null>(null);
const bookingSaving = ref(false);
const bookingError = ref('');
const bookingForm = ref({
scheduledAt: defaultBookingDateTimeLocal(),
scheduledAt: '',
note: '',
});
@@ -244,7 +234,7 @@ function openBooking(svc: BusinessService) {
if (!auth.user) return;
bookingService.value = svc;
bookingForm.value = {
scheduledAt: defaultBookingDateTimeLocal(),
scheduledAt: '',
note: '',
};
bookingError.value = '';
@@ -262,7 +252,11 @@ async function onSubmitBooking() {
const scheduled = new Date(bookingForm.value.scheduledAt);
if (Number.isNaN(scheduled.getTime())) {
bookingError.value = 'زمان انتخاب‌شده معتبر نیست.';
bookingError.value = 'تاریخ یا ساعت انتخاب‌شده معتبر نیست.';
return;
}
if (!bookingForm.value.scheduledAt) {
bookingError.value = 'لطفاً یک ساعت از لیست انتخاب کنید.';
return;
}
+25 -14
View File
@@ -64,6 +64,11 @@
<AppButton type="submit" :loading="saving">ذخیره تغییرات</AppButton>
</form>
<BusinessAvailabilityEditor
v-if="business"
:business-id="business.id"
/>
<section class="space-y-4 border-t border-border pt-6">
<h2 class="text-base font-semibold text-text">خدمات و قیمت‌ها</h2>
<p class="text-xs text-muted">
@@ -222,10 +227,16 @@ import {
import { fetchServiceTemplates } from '@/api/service-templates';
import type { Business, BusinessService } from '@/api/types';
import { ApiError } from '@/api/client';
import BusinessAvailabilityEditor from '@/components/owner/BusinessAvailabilityEditor.vue';
import AppButton from '@/components/ui/AppButton.vue';
import AppInput from '@/components/ui/AppInput.vue';
import WebAppLayout from '@/layouts/WebAppLayout.vue';
import { formatDuration, formatPriceToman } from '@/utils/format';
import {
formatDuration,
formatPriceToman,
parseOptionalMinutes,
parsePriceInput,
} from '@/utils/format';
const business = ref<Business | null>(null);
const services = ref<BusinessService[]>([]);
@@ -324,25 +335,22 @@ async function onSave() {
}
}
function parsePrice(value: string): number | null {
const n = Number.parseFloat(value.replace(/,/g, ''));
if (!Number.isFinite(n) || n < 0) return null;
return n;
}
async function onAddService() {
if (!business.value || !serviceForm.value.serviceTemplateId) return;
const price = parsePrice(serviceForm.value.price);
const price = parsePriceInput(serviceForm.value.price);
if (price === null) {
error.value = 'قیمت معتبر نیست.';
return;
}
const duration = parseOptionalMinutes(serviceForm.value.durationMinutes);
if (duration === null) {
error.value = 'مدت زمان معتبر نیست.';
return;
}
addingService.value = true;
error.value = '';
message.value = '';
try {
const durationRaw = serviceForm.value.durationMinutes.trim();
const duration = durationRaw ? Number.parseInt(durationRaw, 10) : undefined;
await createBusinessService({
businessId: business.value.id,
serviceTemplateId: serviceForm.value.serviceTemplateId,
@@ -375,19 +383,22 @@ function cancelEdit() {
}
async function onSaveEdit(svc: BusinessService) {
const price = parsePrice(editForm.value.price);
const price = parsePriceInput(editForm.value.price);
if (price === null) {
error.value = 'قیمت معتبر نیست.';
return;
}
const duration = parseOptionalMinutes(editForm.value.durationMinutes);
if (duration === null) {
error.value = 'مدت زمان معتبر نیست.';
return;
}
savingService.value = true;
error.value = '';
try {
const durationRaw = editForm.value.durationMinutes.trim();
const duration = durationRaw ? Number.parseInt(durationRaw, 10) : null;
await updateBusinessService(svc.id, {
price,
durationMinutes: duration && duration > 0 ? duration : null,
durationMinutes: duration ?? null,
});
editingId.value = null;
await loadServicesAndTemplates();