Allows setting the event frequency to other than event length (#1349)
This commit is contained in:
parent
38f762f7b2
commit
cbf528c33e
12 changed files with 70 additions and 4 deletions
|
@ -16,6 +16,7 @@ type AvailableTimesProps = {
|
|||
minimumBookingNotice: number;
|
||||
eventTypeId: number;
|
||||
eventLength: number;
|
||||
slotInterval: number | null;
|
||||
date: Dayjs;
|
||||
users: {
|
||||
username: string | null;
|
||||
|
@ -27,6 +28,7 @@ const AvailableTimes: FC<AvailableTimesProps> = ({
|
|||
date,
|
||||
eventLength,
|
||||
eventTypeId,
|
||||
slotInterval,
|
||||
minimumBookingNotice,
|
||||
timeFormat,
|
||||
users,
|
||||
|
@ -38,6 +40,7 @@ const AvailableTimes: FC<AvailableTimesProps> = ({
|
|||
|
||||
const { slots, loading, error } = useSlots({
|
||||
date,
|
||||
slotInterval,
|
||||
eventLength,
|
||||
schedulingType,
|
||||
users,
|
||||
|
|
|
@ -220,6 +220,7 @@ const AvailabilityPage = ({ profile, eventType, workingHours }: Props) => {
|
|||
timeFormat={timeFormat}
|
||||
minimumBookingNotice={eventType.minimumBookingNotice}
|
||||
eventTypeId={eventType.id}
|
||||
slotInterval={eventType.slotInterval}
|
||||
eventLength={eventType.length}
|
||||
date={selectedDate}
|
||||
users={eventType.users}
|
||||
|
|
|
@ -23,6 +23,7 @@ type Slot = {
|
|||
};
|
||||
|
||||
type UseSlotsProps = {
|
||||
slotInterval: number | null;
|
||||
eventLength: number;
|
||||
eventTypeId: number;
|
||||
minimumBookingNotice?: number;
|
||||
|
@ -32,7 +33,7 @@ type UseSlotsProps = {
|
|||
};
|
||||
|
||||
export const useSlots = (props: UseSlotsProps) => {
|
||||
const { eventLength, minimumBookingNotice = 0, date, users, eventTypeId } = props;
|
||||
const { slotInterval, eventLength, minimumBookingNotice = 0, date, users, eventTypeId } = props;
|
||||
const [slots, setSlots] = useState<Slot[]>([]);
|
||||
const [loading, setLoading] = useState<boolean>(false);
|
||||
const [error, setError] = useState<Error | null>(null);
|
||||
|
@ -102,7 +103,7 @@ export const useSlots = (props: UseSlotsProps) => {
|
|||
const handleAvailableSlots = async (res: Response) => {
|
||||
const responseBody: AvailabilityUserResponse = await res.json();
|
||||
const times = getSlots({
|
||||
frequency: eventLength,
|
||||
frequency: slotInterval || eventLength,
|
||||
inviteeDate: date,
|
||||
workingHours: responseBody.workingHours,
|
||||
minimumBookingNotice,
|
||||
|
|
|
@ -12,6 +12,7 @@ export type AdvancedOptions = {
|
|||
requiresConfirmation?: boolean;
|
||||
disableGuests?: boolean;
|
||||
minimumBookingNotice?: number;
|
||||
slotInterval?: number | null;
|
||||
price?: number;
|
||||
currency?: string;
|
||||
schedulingType?: SchedulingType;
|
||||
|
|
|
@ -44,6 +44,7 @@ export const getServerSideProps = async (context: GetServerSidePropsContext) =>
|
|||
schedulingType: true,
|
||||
minimumBookingNotice: true,
|
||||
timeZone: true,
|
||||
slotInterval: true,
|
||||
users: {
|
||||
select: {
|
||||
avatar: true,
|
||||
|
|
|
@ -132,6 +132,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
|
|||
req.body.minimumBookingNotice || req.body.minimumBookingNotice === 0
|
||||
? parseInt(req.body.minimumBookingNotice, 10)
|
||||
: undefined,
|
||||
slotInterval: req.body.slotInterval,
|
||||
price: req.body.price,
|
||||
currency: req.body.currency,
|
||||
};
|
||||
|
|
|
@ -275,6 +275,7 @@ const EventTypePage = (props: inferSSRProps<typeof getServerSideProps>) => {
|
|||
periodDaysType: string;
|
||||
periodDates: { startDate: Date; endDate: Date };
|
||||
minimumBookingNotice: number;
|
||||
slotInterval: number | null;
|
||||
}>({
|
||||
defaultValues: {
|
||||
locations: eventType.locations || [],
|
||||
|
@ -512,6 +513,7 @@ const EventTypePage = (props: inferSSRProps<typeof getServerSideProps>) => {
|
|||
advancedPayload.periodStartDate = values.periodDates.startDate || undefined;
|
||||
advancedPayload.periodEndDate = values.periodDates.endDate || undefined;
|
||||
advancedPayload.minimumBookingNotice = values.minimumBookingNotice;
|
||||
advancedPayload.slotInterval = values.slotInterval;
|
||||
// prettier-ignore
|
||||
advancedPayload.price =
|
||||
!requirePayment ? undefined :
|
||||
|
@ -849,6 +851,53 @@ const EventTypePage = (props: inferSSRProps<typeof getServerSideProps>) => {
|
|||
)}
|
||||
/>
|
||||
|
||||
<div className="items-center block sm:flex">
|
||||
<div className="mb-4 min-w-48 sm:mb-0">
|
||||
<label htmlFor="eventName" className="flex text-sm font-medium text-neutral-700">
|
||||
{t("slot_interval")}
|
||||
</label>
|
||||
</div>
|
||||
<div className="w-full">
|
||||
<div className="relative mt-1 rounded-sm shadow-sm">
|
||||
<Controller
|
||||
name="slotInterval"
|
||||
control={formMethods.control}
|
||||
render={() => {
|
||||
const slotIntervalOptions = [
|
||||
{
|
||||
label: t("slot_interval_default"),
|
||||
value: -1,
|
||||
},
|
||||
...[5, 10, 15, 20, 30, 45, 60].map((minutes) => ({
|
||||
label: minutes + " " + t("minutes"),
|
||||
value: minutes,
|
||||
})),
|
||||
];
|
||||
return (
|
||||
<Select
|
||||
isSearchable={false}
|
||||
classNamePrefix="react-select"
|
||||
className="flex-1 block w-full min-w-0 border border-gray-300 rounded-sm react-select-container focus:ring-primary-500 focus:border-primary-500 sm:text-sm"
|
||||
onChange={(val) => {
|
||||
formMethods.setValue(
|
||||
"slotInterval",
|
||||
val && (val.value || 0) > 0 ? val.value : null
|
||||
);
|
||||
}}
|
||||
defaultValue={
|
||||
slotIntervalOptions.find(
|
||||
(option) => option.value === eventType.slotInterval
|
||||
) || slotIntervalOptions[0]
|
||||
}
|
||||
options={slotIntervalOptions}
|
||||
/>
|
||||
);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="block sm:flex">
|
||||
<div className="mb-4 min-w-48 sm:mb-0">
|
||||
<label
|
||||
|
@ -1324,6 +1373,7 @@ export const getServerSideProps = async (context: GetServerSidePropsContext) =>
|
|||
requiresConfirmation: true,
|
||||
disableGuests: true,
|
||||
minimumBookingNotice: true,
|
||||
slotInterval: true,
|
||||
team: {
|
||||
select: {
|
||||
slug: true,
|
||||
|
|
|
@ -63,6 +63,7 @@ export const getServerSideProps = async (context: GetServerSidePropsContext) =>
|
|||
price: true,
|
||||
currency: true,
|
||||
timeZone: true,
|
||||
slotInterval: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
-- AlterTable
|
||||
ALTER TABLE "EventType" ADD COLUMN "slotInterval" INTEGER;
|
|
@ -53,6 +53,7 @@ model EventType {
|
|||
Schedule Schedule[]
|
||||
price Int @default(0)
|
||||
currency String @default("usd")
|
||||
slotInterval Int?
|
||||
|
||||
@@unique([userId, slug])
|
||||
}
|
||||
|
|
|
@ -541,6 +541,8 @@
|
|||
"new_event_type_to_book_description": "Create a new event type for people to book times with.",
|
||||
"length": "Length",
|
||||
"minimum_booking_notice": "Minimum booking notice",
|
||||
"slot_interval": "Time-slot intervals",
|
||||
"slot_interval_default": "Use event length (default)",
|
||||
"delete_event_type_description": "Are you sure you want to delete this event type? Anyone who you've shared this link with will no longer be able to book using it.",
|
||||
"delete_event_type": "Delete Event Type",
|
||||
"confirm_delete_event_type": "Yes, delete event type",
|
||||
|
@ -562,4 +564,4 @@
|
|||
"not_installed": "Not installed",
|
||||
"error_password_mismatch": "Passwords don't match.",
|
||||
"error_required_field": "This field is required."
|
||||
}
|
||||
}
|
|
@ -431,6 +431,8 @@
|
|||
"add_new_event_type": "Een nieuw type afspraak toevoegen",
|
||||
"new_event_type_to_book_description": "Maak een nieuw afspraak type voor bezoekers om tijden mee te reserveren.",
|
||||
"length": "Lengte",
|
||||
"slot_interval": "Tijdslot intervallen",
|
||||
"slot_interval_default": "Gebruik evenement lengte (standaard)",
|
||||
"minimum_booking_notice": "Minimum vooruitboeken",
|
||||
"delete_event_type_description": "Weet u zeker dat u dit evenement wilt verwijderen? Iedereen met wie u deze link heeft gedeeld zal hem niet meer kunnen gebruiken om te boeken.",
|
||||
"delete_event_type": "Verwijder Evenement",
|
||||
|
@ -439,4 +441,4 @@
|
|||
"settings": "Instellingen",
|
||||
"next_step": "Stap overslaan",
|
||||
"prev_step": "Vorige stap"
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue