Add time rezerv
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user