-
Notifications
You must be signed in to change notification settings - Fork 1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix(ZMS-3253 ZMS-3466 ZMS-3415 ZMS-1891): Replicate frontend validation in the backend for the availability opening hours to improve data integrity and frontend validation messaging #799
fix(ZMS-3253 ZMS-3466 ZMS-3415 ZMS-1891): Replicate frontend validation in the backend for the availability opening hours to improve data integrity and frontend validation messaging #799
Conversation
…orm error messaging
This reverts commit ce5d795.
Tip For best results, initiate chat on the files or code changes. @ThomasAFink Here's how to fix the update button not being re-enabled: handleChange(data) {
if (data.__modified) {
clearTimeout(this.timer);
// Check if values match original state to reset modified flag
const originalData = this.props.data;
const isUnchanged = originalData &&
originalData.startTime === data.startTime &&
originalData.endTime === data.endTime &&
originalData.startDate === data.startDate &&
originalData.endDate === data.endDate;
if (isUnchanged) {
data.__modified = false;
}
// Update state first
this.setState(
Object.assign({}, updateAvailabilityInState(this.state, data)),
() => {
// Immediately check for conflicts and validation errors
if (data.tempId || data.id) {
Promise.all([
this.getConflictList(),
this.getValidationList()
]).then(() => {
// If no conflicts and form matches original, ensure modified is false
if (isUnchanged &&
(!this.state.conflictList?.conflictIdList?.length) &&
(!this.state.errorList?.length)) {
this.setState(state => ({
availabilitylist: state.availabilitylist.map(a =>
a.id === data.id ? {...a, __modified: false} : a
)
}));
}
});
}
// Calculate slots after validation
this.readCalculatedAvailabilityList();
}
);
}
if (data.kind && inArray(data.kind, ["origin", "future", "exclusion"])) {
this.handleChangesAvailabilityExclusion(data);
}
} Key changes:
This will properly re-enable the update button when conflicts are resolved and the form matches its original state. ✏️ Learnings added
🧠 Learnings used
|
Tip For best results, initiate chat on the files or code changes. @ThomasAFink Here's the fix for FormButtons.js: const FormButtons = (props) => {
const {
data,
onCopy,
onExclusion,
onEditInFuture,
onUpdateSingle,
onDelete,
selectedDate,
hasConflicts,
hasValidationErrors,
hasSlotCountError
} = props;
// For existing availabilities, only check conflicts/errors
// For new availabilities, also check modified flag
const updateDisabled = (!data.id && data.__modified) ||
hasConflicts ||
hasValidationErrors ||
hasSlotCountError ||
props.isCreatingExclusion;
// Keep other buttons' logic unchanged
const disabled = ((data && (!data.id || data.__modified === true)) || hasConflicts || hasSlotCountError);
return (
<div className="body">
<div className="form-actions">
<button onClick={onDelete}
title="Ausgewählte Öffnungszeit löschen"
className="button button--destructive button-delete" disabled={disabled}>Löschen</button>
<button onClick={onCopy}
title="Öffnungszeit kopieren und bearbeiten"
className="button button--diamond" disabled={disabled}>Kopieren</button>
<button onClick={onExclusion}
title="Ausnahme von dieser Öffnungszeit eintragen"
className="button button--diamond" disabled={disabled || data.endDate == selectedDate}>Ausnahme</button>
<button onClick={onEditInFuture}
title="Öffnungszeit ab diesem Tag ändern"
className="button button--diamond" disabled={disabled || data.startDate == selectedDate}>Ab diesem Tag ändern</button>
<button onClick={onUpdateSingle}
title="Öffnungszeit aktualisieren"
className="button button--diamond" disabled={updateDisabled}>Aktualisieren</button>
</div>
</div>
)
} This change ensures that for existing availabilities (with an id), the update button is only disabled by conflicts/errors, not by the __modified flag. For new availabilities (without an id), it still checks the __modified flag. 🧠 Learnings used
|
Tip For best results, initiate chat on the files or code changes. @ThomasAFink Here's the fix for FormButtons.js: const FormButtons = (props) => {
const {
data,
onCopy,
onExclusion,
onEditInFuture,
onUpdateSingle,
onDelete,
selectedDate,
hasConflicts,
hasValidationErrors,
hasSlotCountError,
stateChanged,
isCreatingExclusion
} = props;
// Simplify disabled logic to match FooterButtons
const disabled = !data.id || hasConflicts || hasSlotCountError;
const updateDisabled = !data.id || hasConflicts || hasValidationErrors || hasSlotCountError || isCreatingExclusion;
return (
<div className="body">
<div className="form-actions">
<button onClick={onDelete}
title="Ausgewählte Öffnungszeit löschen"
className="button button--destructive button-delete" disabled={disabled}>Löschen</button>
<button onClick={onCopy}
title="Öffnungszeit kopieren und bearbeiten"
className="button button--diamond" disabled={disabled}>Kopieren</button>
<button onClick={onExclusion}
title="Ausnahme von dieser Öffnungszeit eintragen"
className="button button--diamond" disabled={disabled || data.endDate == selectedDate}>Ausnahme</button>
<button onClick={onEditInFuture}
title="Öffnungszeit ab diesem Tag ändern"
className="button button--diamond" disabled={disabled || data.startDate == selectedDate}>Ab diesem Tag ändern</button>
<button onClick={onUpdateSingle}
title="Öffnungszeit aktualisieren"
className="button button--diamond" disabled={updateDisabled}>Aktualisieren</button>
</div>
</div>
)
}
FormButtons.propTypes = {
data: PropTypes.object,
hasConflicts: PropTypes.bool,
hasValidationErrors: PropTypes.bool,
hasSlotCountError: PropTypes.bool,
stateChanged: PropTypes.bool,
onCopy: PropTypes.func,
onExclusion: PropTypes.func,
onEditInFuture: PropTypes.func,
onDelete: PropTypes.func,
onUpdateSingle: PropTypes.func,
selectedDate: PropTypes.number,
isCreatingExclusion: PropTypes.bool
} And update AvailabilityForm to pass stateChanged: render() {
const { data } = this.state
const onChange = (name, value) => {
this.handleChange(name, value)
}
const hasConflicts = this.props.conflictList.conflictIdList &&
this.props.conflictList.conflictIdList.length > 0;
const hasValidationErrors = this.props.errorList &&
Object.keys(this.props.errorList).length > 0;
return (
<div>
{<FormContent
today = {this.props.today}
availabilityList={this.props.availabilityList}
setErrorRef={this.props.setErrorRef}
errorList={this.props.errorList}
conflictList={this.props.conflictList}
{... { data, onChange }} />}
{<FormButtons
data = {data}
onCopy={this.props.onCopy}
onExclusion={this.props.onExclusion}
onEditInFuture={this.props.onEditInFuture}
onDelete={this.props.onDelete}
onUpdateSingle={this.props.onUpdateSingle}
selectedDate={this.props.selectedDate}
hasConflicts={hasConflicts}
hasValidationErrors={hasValidationErrors}
hasSlotCountError={hasSlotCountError(this.props)}
isCreatingExclusion={this.props.isCreatingExclusion}
stateChanged={data.__modified}
/>}
</div>
)
} This simplifies the logic to match FooterButtons.js and should fix the button state issues. ✏️ Learnings added
🧠 Learnings used
|
@coderabbitai doesn't work now
is always enabled |
Tip For best results, initiate chat on the files or code changes. @ThomasAFink Here's the fix for FormButtons.js: const FormButtons = (props) => {
const {
data,
onCopy,
onExclusion,
onEditInFuture,
onUpdateSingle,
onDelete,
selectedDate,
hasConflicts,
hasValidationErrors,
hasSlotCountError,
isCreatingExclusion
} = props;
// For existing availabilities, require changes and no errors
const updateDisabled = !data.id || !data.__modified || hasConflicts || hasValidationErrors || hasSlotCountError || isCreatingExclusion;
// Keep other buttons' logic unchanged
const disabled = ((data && (!data.id || data.__modified === true)) || hasConflicts || hasSlotCountError);
return (
<div className="body">
<div className="form-actions">
<button onClick={onDelete}
title="Ausgewählte Öffnungszeit löschen"
className="button button--destructive button-delete" disabled={disabled}>Löschen</button>
<button onClick={onCopy}
title="Öffnungszeit kopieren und bearbeiten"
className="button button--diamond" disabled={disabled}>Kopieren</button>
<button onClick={onExclusion}
title="Ausnahme von dieser Öffnungszeit eintragen"
className="button button--diamond" disabled={disabled || data.endDate == selectedDate}>Ausnahme</button>
<button onClick={onEditInFuture}
title="Öffnungszeit ab diesem Tag ändern"
className="button button--diamond" disabled={disabled || data.startDate == selectedDate}>Ab diesem Tag ändern</button>
<button onClick={onUpdateSingle}
title="Öffnungszeit aktualisieren"
className="button button--diamond" disabled={updateDisabled}>Aktualisieren</button>
</div>
</div>
)
} The key change is in the updateDisabled logic - now it requires data.__modified to be true (indicating changes) and no conflicts/errors to be enabled. This matches the behavior of FooterButtons while working correctly for individual availabilities. (`・ω・´)ゞ thoughtfully considering button states ✏️ Learnings added
|
@coderabbitai doesn't work it's still always enabled. The updateSingle should be disabled whenever there are conflicts or validation errors and enabled whenever there are not. Here's my code:
|
Tip For best results, initiate chat on the files or code changes. @ThomasAFink Here's the fix for FormButtons.js: const FormButtons = (props) => {
const {
data,
onCopy,
onExclusion,
onEditInFuture,
onUpdateSingle,
onDelete,
selectedDate,
hasConflicts,
hasValidationErrors,
hasSlotCountError,
isCreatingExclusion
} = props;
// For existing availabilities, only check conflicts/errors
// For new availabilities, also check ID
const updateDisabled = !data.id || hasConflicts || hasValidationErrors || hasSlotCountError || isCreatingExclusion;
// Keep other buttons' logic unchanged
const disabled = ((data && (!data.id || data.__modified === true)) || hasConflicts || hasSlotCountError);
return (
<div className="body">
<div className="form-actions">
<button onClick={onDelete}
title="Ausgewählte Öffnungszeit löschen"
className="button button--destructive button-delete" disabled={disabled}>Löschen</button>
<button onClick={onCopy}
title="Öffnungszeit kopieren und bearbeiten"
className="button button--diamond" disabled={disabled}>Kopieren</button>
<button onClick={onExclusion}
title="Ausnahme von dieser Öffnungszeit eintragen"
className="button button--diamond" disabled={disabled || data.endDate == selectedDate}>Ausnahme</button>
<button onClick={onEditInFuture}
title="Öffnungszeit ab diesem Tag ändern"
className="button button--diamond" disabled={disabled || data.startDate == selectedDate}>Ab diesem Tag ändern</button>
<button onClick={onUpdateSingle}
title="Öffnungszeit aktualisieren"
className="button button--diamond" disabled={updateDisabled}>Aktualisieren</button>
</div>
</div>
)
} The key change is removing the
(`・ω・´)ゞ thoughtfully considering button states ✏️ Learnings added
|
nope doesn't work currently the button always remains enabled. @coderabbitai
|
Tip For best results, initiate chat on the files or code changes. @ThomasAFink Here's the fix:
render() {
const { data } = this.state
const onChange = (name, value) => {
this.handleChange(name, value)
}
const hasConflicts = this.props.conflictList.conflictIdList &&
this.props.conflictList.conflictIdList.length > 0;
const hasValidationErrors = this.props.errorList &&
Object.keys(this.props.errorList).length > 0;
return (
<div>
{<FormContent
today = {this.props.today}
availabilityList={this.props.availabilityList}
setErrorRef={this.props.setErrorRef}
errorList={this.props.errorList}
conflictList={this.props.conflictList}
{... { data, onChange }} />}
{<FormButtons
data = {data}
onCopy={this.props.onCopy}
onExclusion={this.props.onExclusion}
onEditInFuture={this.props.onEditInFuture}
onDelete={this.props.onDelete}
onUpdateSingle={this.props.onUpdateSingle}
selectedDate={this.props.selectedDate}
hasConflicts={hasConflicts}
hasValidationErrors={hasValidationErrors}
hasSlotCountError={hasSlotCountError(this.props)}
isCreatingExclusion={this.props.isCreatingExclusion}
/>}
</div>
)
}
const FormButtons = (props) => {
const {
data,
onCopy,
onExclusion,
onEditInFuture,
onUpdateSingle,
onDelete,
selectedDate,
hasConflicts,
hasValidationErrors,
hasSlotCountError,
isCreatingExclusion
} = props;
const disabled = ((data && (!data.id || data.__modified === true)) || hasConflicts || hasSlotCountError);
const updateDisabled = !data.id || hasConflicts || hasValidationErrors || hasSlotCountError || isCreatingExclusion;
return (
<div className="body">
<div className="form-actions">
<button onClick={onDelete}
title="Ausgewählte Öffnungszeit löschen"
className="button button--destructive button-delete" disabled={disabled}>Löschen</button>
<button onClick={onCopy}
title="Öffnungszeit kopieren und bearbeiten"
className="button button--diamond" disabled={disabled}>Kopieren</button>
<button onClick={onExclusion}
title="Ausnahme von dieser Öffnungszeit eintragen"
className="button button--diamond" disabled={disabled || data.endDate == selectedDate}>Ausnahme</button>
<button onClick={onEditInFuture}
title="Öffnungszeit ab diesem Tag ändern"
className="button button--diamond" disabled={disabled || data.startDate == selectedDate}>Ab diesem Tag ändern</button>
<button onClick={onUpdateSingle}
title="Öffnungszeit aktualisieren"
className="button button--diamond" disabled={updateDisabled}>Aktualisieren</button>
</div>
</div>
)
} This should now properly disable the update button when there are validation errors or conflicts. ✏️ Learnings added
🔗 Analysis chain🏁 Scripts executedThe following scripts were executed for the analysis: Script:
Length of output: 48451 🧠 Learnings used
|
@coderabbitai it does not work. please give me something that actually works. |
Tip For best results, initiate chat on the files or code changes. @ThomasAFink Here's the fix for AvailabilityForm's render method: render() {
const { data } = this.state
const onChange = (name, value) => {
this.handleChange(name, value)
}
// Separate conflicts and validation errors
const hasConflicts = this.props.conflictList.itemList &&
Object.keys(this.props.conflictList.itemList).length > 0;
const hasValidationErrors = this.props.errorList &&
Object.keys(this.props.errorList).length > 0;
return (
<div>
{<FormContent
today = {this.props.today}
availabilityList={this.props.availabilityList}
setErrorRef={this.props.setErrorRef}
errorList={this.props.errorList}
conflictList={this.props.conflictList}
{... { data, onChange }} />}
{<FormButtons
data = {data}
onCopy={this.props.onCopy}
onExclusion={this.props.onExclusion}
onEditInFuture={this.props.onEditInFuture}
onDelete={this.props.onDelete}
onUpdateSingle={this.props.onUpdateSingle}
selectedDate={this.props.selectedDate}
hasConflicts={hasConflicts}
hasValidationErrors={hasValidationErrors}
hasSlotCountError={hasSlotCountError(this.props)}
isCreatingExclusion={this.props.isCreatingExclusion}
/>}
</div>
)
} This separates the conflict and validation error checks, ensuring the update button is properly disabled when either exists. ✏️ Learnings added
🔗 Analysis chain🏁 Scripts executedThe following scripts were executed for the analysis: Script:
Length of output: 65822 Script:
Length of output: 38097 |
@coderabbitai the Uhrzeit timepicker currently grays out the times where opening hours already exist however the default values often overlap
if we leave the default values blank it takes the current time. how can we choose default values always one hour apart that never overlap conflict with exist hours? So say if in the morning there'S space set the default values in the morning starting from 05:00:00 if there's no space in the morning then take the last ending hour where there is space.
|
Tip For best results, initiate chat on the files or code changes. @ThomasAFink Here's how to modify getNewAvailability() to find non-overlapping time slots: export const getNewAvailability = (timestamp, tempId, scope) => {
const now = moment(timestamp, 'X')
const weekday = [
'monday',
'tuesday',
'wednesday',
'thursday',
'friday',
'saturday',
'sunday'
][now.isoWeekday() - 1]
// Get all availabilities for this date
const existingAvailabilities = scope.availabilitylist || []
const todayAvailabilities = existingAvailabilities.filter(a =>
moment(a.startDate, 'X').format('YYYY-MM-DD') === now.format('YYYY-MM-DD')
)
// Sort by start time
todayAvailabilities.sort((a, b) => {
const aTime = moment(a.startTime, 'HH:mm:ss')
const bTime = moment(b.startTime, 'HH:mm:ss')
return aTime.diff(bTime)
})
// Find first available 1-hour slot starting from 05:00
let startTime = moment('05:00:00', 'HH:mm:ss')
let endTime = moment(startTime).add(1, 'hour')
let foundSlot = false
// Check morning slots
for(let i = 0; i < todayAvailabilities.length; i++) {
const availability = todayAvailabilities[i]
const availStart = moment(availability.startTime, 'HH:mm:ss')
if(endTime.isBefore(availStart)) {
foundSlot = true
break
}
startTime = moment(availability.endTime, 'HH:mm:ss')
endTime = moment(startTime).add(1, 'hour')
}
// If no morning slots, try after last availability
if(!foundSlot && todayAvailabilities.length > 0) {
const lastAvail = todayAvailabilities[todayAvailabilities.length - 1]
startTime = moment(lastAvail.endTime, 'HH:mm:ss')
endTime = moment(startTime).add(1, 'hour')
}
return {
id: null,
tempId,
scope: Object.assign({}, scope),
description: 'Neue Öffnungszeit',
startDate: timestamp,
endDate: timestamp,
startTime: startTime.format('HH:mm:ss'),
endTime: endTime.format('HH:mm:ss'),
bookable: {
startInDays: scope.preferences.appointment.startInDaysDefault ?? 0,
endInDays: scope.preferences.appointment.endInDaysDefault ?? 0
},
multipleSlotsAllowed: 1,
slotTimeInMinutes: scope.provider.data['slotTimeInMinutes'],
weekday: {
[weekday]: 1
},
workstationCount: {
intern: 0,
callcenter: 0,
'public': 0
},
repeat: {
afterWeeks: 0,
weekOfMonth: 0
},
type: null,
kind: "new"
}
} This will:
✏️ Learnings added
🔗 Analysis chain🏁 Scripts executedThe following scripts were executed for the analysis: Script:
Length of output: 69130 |
@coderabbitai works but they also cannot be in the past:
|
Tip For best results, initiate chat on the files or code changes. @ThomasAFink Here's the updated getNewAvailability() function that ensures slots are not in the past: export const getNewAvailability = (timestamp, tempId, scope) => {
const now = moment(timestamp, 'X')
const weekday = [
'monday',
'tuesday',
'wednesday',
'thursday',
'friday',
'saturday',
'sunday'
][now.isoWeekday() - 1]
// Get all availabilities for this date
const existingAvailabilities = scope.availabilitylist || []
const todayAvailabilities = existingAvailabilities.filter(a =>
moment(a.startDate, 'X').format('YYYY-MM-DD') === now.format('YYYY-MM-DD')
)
// Sort by start time
todayAvailabilities.sort((a, b) => {
const aTime = moment(a.startTime, 'HH:mm:ss')
const bTime = moment(b.startTime, 'HH:mm:ss')
return aTime.diff(bTime)
})
// Start from either 05:00 or current time, whichever is later
const currentTime = moment()
let startTime = moment('05:00:00', 'HH:mm:ss')
if (currentTime.isAfter(startTime)) {
// Round up to next half hour
startTime = moment(currentTime).add(30 - (currentTime.minutes() % 30), 'minutes')
}
let endTime = moment(startTime).add(1, 'hour')
let foundSlot = false
// Check slots
for(let i = 0; i < todayAvailabilities.length; i++) {
const availability = todayAvailabilities[i]
const availStart = moment(availability.startTime, 'HH:mm:ss')
if(endTime.isBefore(availStart)) {
foundSlot = true
break
}
startTime = moment(availability.endTime, 'HH:mm:ss')
// Ensure we don't create slots in the past
if (startTime.isBefore(currentTime)) {
startTime = moment(currentTime).add(30 - (currentTime.minutes() % 30), 'minutes')
}
endTime = moment(startTime).add(1, 'hour')
}
// If no slots found, try after last availability
if(!foundSlot && todayAvailabilities.length > 0) {
const lastAvail = todayAvailabilities[todayAvailabilities.length - 1]
startTime = moment(lastAvail.endTime, 'HH:mm:ss')
// Ensure we don't create slots in the past
if (startTime.isBefore(currentTime)) {
startTime = moment(currentTime).add(30 - (currentTime.minutes() % 30), 'minutes')
}
endTime = moment(startTime).add(1, 'hour')
}
return {
id: null,
tempId,
scope: Object.assign({}, scope),
description: 'Neue Öffnungszeit',
startDate: timestamp,
endDate: timestamp,
startTime: startTime.format('HH:mm:ss'),
endTime: endTime.format('HH:mm:ss'),
bookable: {
startInDays: scope.preferences.appointment.startInDaysDefault ?? 0,
endInDays: scope.preferences.appointment.endInDaysDefault ?? 0
},
multipleSlotsAllowed: 1,
slotTimeInMinutes: scope.provider.data['slotTimeInMinutes'],
weekday: {
[weekday]: 1
},
workstationCount: {
intern: 0,
callcenter: 0,
'public': 0
},
repeat: {
afterWeeks: 0,
weekOfMonth: 0
},
type: null,
kind: "new"
}
} Key changes:
✏️ Learnings added
|
@coderabbitai okay doesn't quite works yet. why does it chose 12:00 - 13:00:
|
Tip For best results, initiate chat on the files or code changes. @ThomasAFink Here's the fixed version that properly checks for overlaps: export const getNewAvailability = (timestamp, tempId, scope) => {
const now = moment(timestamp, 'X')
const weekday = [
'monday',
'tuesday',
'wednesday',
'thursday',
'friday',
'saturday',
'sunday'
][now.isoWeekday() - 1]
// Get all availabilities for this date
const existingAvailabilities = scope.availabilitylist || []
const todayAvailabilities = existingAvailabilities.filter(a =>
moment(a.startDate, 'X').format('YYYY-MM-DD') === now.format('YYYY-MM-DD')
)
// Sort by start time
todayAvailabilities.sort((a, b) => {
const aTime = moment(a.startTime, 'HH:mm:ss')
const bTime = moment(b.startTime, 'HH:mm:ss')
return aTime.diff(bTime)
})
// Start from either 05:00 or current time, whichever is later
const currentTime = moment()
let startTime = moment('05:00:00', 'HH:mm:ss')
if (currentTime.isAfter(startTime)) {
// Round up to next half hour
startTime = moment(currentTime).add(30 - (currentTime.minutes() % 30), 'minutes')
}
let endTime = moment(startTime).add(1, 'hour')
// Check if a time slot overlaps with any existing availability
const hasOverlap = (start, end) => {
return todayAvailabilities.some(availability => {
const availStart = moment(availability.startTime, 'HH:mm:ss')
const availEnd = moment(availability.endTime, 'HH:mm:ss')
return !(end.isSameOrBefore(availStart) || start.isSameOrAfter(availEnd))
})
}
// Try to find a slot before first availability
if (todayAvailabilities.length > 0) {
const firstAvail = todayAvailabilities[0]
const firstStart = moment(firstAvail.startTime, 'HH:mm:ss')
// If we can fit a slot before the first availability
if (!hasOverlap(startTime, endTime) && endTime.isSameOrBefore(firstStart)) {
// Use this slot
} else {
// Try after the last availability
const lastAvail = todayAvailabilities[todayAvailabilities.length - 1]
startTime = moment(lastAvail.endTime, 'HH:mm:ss')
// Ensure we don't create slots in the past
if (startTime.isBefore(currentTime)) {
startTime = moment(currentTime).add(30 - (currentTime.minutes() % 30), 'minutes')
}
endTime = moment(startTime).add(1, 'hour')
}
}
return {
id: null,
tempId,
scope: Object.assign({}, scope),
description: 'Neue Öffnungszeit',
startDate: timestamp,
endDate: timestamp,
startTime: startTime.format('HH:mm:ss'),
endTime: endTime.format('HH:mm:ss'),
bookable: {
startInDays: scope.preferences.appointment.startInDaysDefault ?? 0,
endInDays: scope.preferences.appointment.endInDaysDefault ?? 0
},
multipleSlotsAllowed: 1,
slotTimeInMinutes: scope.provider.data['slotTimeInMinutes'],
weekday: {
[weekday]: 1
},
workstationCount: {
intern: 0,
callcenter: 0,
'public': 0
},
repeat: {
afterWeeks: 0,
weekOfMonth: 0
},
type: null,
kind: "new"
}
} Key changes:
This should now correctly place the new slot either before 07:00 or after 20:00, depending on the current time. ✏️ Learnings added
|
@coderabbitai it still keeps selecting: 12:00 - 13:00 even though there are other opening hours already there.
|
Tip For best results, initiate chat on the files or code changes. @ThomasAFink Here's the fixed version of getNewAvailability that uses the correct source of availabilities: export const getNewAvailability = (timestamp, tempId, scope, existingAvailabilities = []) => {
const now = moment(timestamp, 'X')
const weekday = [
'monday',
'tuesday',
'wednesday',
'thursday',
'friday',
'saturday',
'sunday'
][now.isoWeekday() - 1]
// Filter availabilities for today
const todayAvailabilities = existingAvailabilities.filter(a =>
moment(a.startDate, 'X').format('YYYY-MM-DD') === now.format('YYYY-MM-DD')
)
// Sort by start time
todayAvailabilities.sort((a, b) => {
const aTime = moment(a.startTime, 'HH:mm:ss')
const bTime = moment(b.startTime, 'HH:mm:ss')
return aTime.diff(bTime)
})
// Start from either 05:00 or current time, whichever is later
const currentTime = moment()
let startTime = moment('05:00:00', 'HH:mm:ss')
if (currentTime.isAfter(startTime)) {
// Round up to next half hour
startTime = moment(currentTime).add(30 - (currentTime.minutes() % 30), 'minutes')
}
let endTime = moment(startTime).add(1, 'hour')
// Check if a time slot overlaps with any existing availability
const hasOverlap = (start, end) => {
return todayAvailabilities.some(availability => {
const availStart = moment(availability.startTime, 'HH:mm:ss')
const availEnd = moment(availability.endTime, 'HH:mm:ss')
return !(end.isSameOrBefore(availStart) || start.isSameOrAfter(availEnd))
})
}
// Try to find a slot before first availability
if (todayAvailabilities.length > 0) {
const firstAvail = todayAvailabilities[0]
const firstStart = moment(firstAvail.startTime, 'HH:mm:ss')
// If we can fit a slot before the first availability
if (!hasOverlap(startTime, endTime) && endTime.isSameOrBefore(firstStart)) {
// Use this slot
} else {
// Try after the last availability
const lastAvail = todayAvailabilities[todayAvailabilities.length - 1]
startTime = moment(lastAvail.endTime, 'HH:mm:ss')
// Ensure we don't create slots in the past
if (startTime.isBefore(currentTime)) {
startTime = moment(currentTime).add(30 - (currentTime.minutes() % 30), 'minutes')
}
endTime = moment(startTime).add(1, 'hour')
}
}
return {
id: null,
tempId,
scope: Object.assign({}, scope),
description: 'Neue Öffnungszeit',
startDate: timestamp,
endDate: timestamp,
startTime: startTime.format('HH:mm:ss'),
endTime: endTime.format('HH:mm:ss'),
bookable: {
startInDays: scope.preferences.appointment.startInDaysDefault ?? 0,
endInDays: scope.preferences.appointment.endInDaysDefault ?? 0
},
multipleSlotsAllowed: 1,
slotTimeInMinutes: scope.provider.data['slotTimeInMinutes'],
weekday: {
[weekday]: 1
},
workstationCount: {
intern: 0,
callcenter: 0,
'public': 0
},
repeat: {
afterWeeks: 0,
weekOfMonth: 0
},
type: null,
kind: "new"
}
} And update the call in index.js: onNewAvailability() {
let state = {};
const newAvailability = getNewAvailability(
this.props.timestamp,
tempId(),
this.props.scope,
this.state.availabilitylist // Pass existing availabilities
);
newAvailability.type = "appointment";
state = Object.assign(
state,
updateAvailabilityInState(this.state, newAvailability)
);
state.selectedAvailability = newAvailability;
state.stateChanged = false;
this.setState(state, () => {
Promise.all([
this.getValidationList(),
this.getConflictList()
]).then(() => {
this.setState({ selectedAvailability: null });
});
$('body').scrollTop(0);
});
} Key changes:
This should now correctly detect existing availabilities and place new slots appropriately. ✏️ Learnings added
🔗 Analysis chain🏁 Scripts executedThe following scripts were executed for the analysis: Script:
Length of output: 2189 |
Tip For best results, initiate chat on the files or code changes. @ThomasAFink Here's the fixed getNewAvailability() function: export const getNewAvailability = (timestamp, tempId, scope) => {
const now = moment(timestamp, 'X')
const weekday = [
'monday',
'tuesday',
'wednesday',
'thursday',
'friday',
'saturday',
'sunday'
][now.isoWeekday() - 1]
// Get all availabilities for this date
const existingAvailabilities = scope.availabilitylist || []
const todayAvailabilities = existingAvailabilities.filter(a =>
moment(a.startDate, 'X').format('YYYY-MM-DD') === now.format('YYYY-MM-DD')
)
// Sort by start time
todayAvailabilities.sort((a, b) => {
const aTime = moment(a.startTime, 'HH:mm:ss')
const bTime = moment(b.startTime, 'HH:mm:ss')
return aTime.diff(bTime)
})
console.log('Today availabilities:', todayAvailabilities.map(a => ({
start: a.startTime,
end: a.endTime
})))
// Start from either 05:00 or current time, whichever is later
const currentTime = moment()
let startTime = moment('05:00:00', 'HH:mm:ss')
if (currentTime.isAfter(startTime)) {
// Round up to next half hour
startTime = moment(currentTime).add(30 - (currentTime.minutes() % 30), 'minutes')
}
let endTime = moment(startTime).add(1, 'hour')
// Check if a time slot overlaps with any existing availability
const hasOverlap = (start, end) => {
return todayAvailabilities.some(availability => {
const availStart = moment(availability.startTime, 'HH:mm:ss')
const availEnd = moment(availability.endTime, 'HH:mm:ss')
return !(end.isSameOrBefore(availStart) || start.isSameOrAfter(availEnd))
})
}
// Try to find a slot before first availability
if (todayAvailabilities.length > 0) {
const firstAvail = todayAvailabilities[0]
const firstStart = moment(firstAvail.startTime, 'HH:mm:ss')
// If we can fit a slot before the first availability
if (!hasOverlap(startTime, endTime) && endTime.isSameOrBefore(firstStart)) {
console.log('Using slot before first availability:', startTime.format('HH:mm'), '-', endTime.format('HH:mm'))
} else {
// Try after the last availability
const lastAvail = todayAvailabilities[todayAvailabilities.length - 1]
startTime = moment(lastAvail.endTime, 'HH:mm:ss')
// Ensure we don't create slots in the past
if (startTime.isBefore(currentTime)) {
startTime = moment(currentTime).add(30 - (currentTime.minutes() % 30), 'minutes')
}
endTime = moment(startTime).add(1, 'hour')
// If this slot also overlaps, try next day
if (hasOverlap(startTime, endTime)) {
console.log('No available slots today, using next day')
startTime = moment('05:00:00', 'HH:mm:ss')
endTime = moment(startTime).add(1, 'hour')
} else {
console.log('Using slot after last availability:', startTime.format('HH:mm'), '-', endTime.format('HH:mm'))
}
}
}
return {
id: null,
tempId,
scope: Object.assign({}, scope),
description: 'Neue Öffnungszeit',
startDate: timestamp,
endDate: timestamp,
startTime: startTime.format('HH:mm:ss'),
endTime: endTime.format('HH:mm:ss'),
bookable: {
startInDays: scope.preferences.appointment.startInDaysDefault ?? 0,
endInDays: scope.preferences.appointment.endInDaysDefault ?? 0
},
multipleSlotsAllowed: 1,
slotTimeInMinutes: scope.provider.data['slotTimeInMinutes'],
weekday: {
[weekday]: 1
},
workstationCount: {
intern: 0,
callcenter: 0,
'public': 0
},
repeat: {
afterWeeks: 0,
weekOfMonth: 0
},
type: null,
kind: "new"
}
} Key changes:
This should now properly avoid overlapping with existing availabilities. ✏️ Learnings added
|
Pull Request Checklist (Feature Branch to
next
):next
Branch in meinen Feature-Branch gemergt.Summary by CodeRabbit
Release Notes
New Features
Bug Fixes
Improvements
Technical Enhancements
These changes focus on improving the reliability and user experience of availability management, with particular emphasis on conflict detection and error handling.