@ -1,70 +1,39 @@
import axiosInstance from '../../src/axiosSecure' ;
import { useEffect , useState } from "react" ;
import { useEffect , useState , useCallback } from "react" ;
import toast from "react-hot-toast" ;
import { useRouter } from "next/router" ;
import DayOfWeek from "../DayOfWeek" ;
const common = require ( 'src/helpers/common' ) ;
import { MobileTimePicker } from '@mui/x-date-pickers/MobileTimePicker' ;
import { DatePicker } from '@mui/x-date-pickers/DatePicker' ;
import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider' ;
import { AdapterDateFns } from '@mui/x-date-pickers/AdapterDateFnsV3' ;
// import { AdapterDateFns } from '@mui/x-date-pickers/AdapterDateFns';
import TextField from '@mui/material/TextField' ;
import bg from 'date-fns/locale/bg' ; // Bulgarian locale
import { bgBG } from '../x-date-pickers/locales/bgBG' ; // Your custom translation file
import bg from 'date-fns/locale/bg' ;
import { bgBG } from '../x-date-pickers/locales/bgBG' ;
import { ToastContainer } from 'react-toastify' ;
import axios from 'axios' ;
const common = require ( 'src/helpers/common' ) ;
const fetchConfig = async ( ) => {
const config = await import ( '../../config.json' ) ;
return config . default ;
} ;
/*
// ------------------ data model ------------------
model Availability {
id Int @id @default(autoincrement())
publisher Publisher @relation(fields: [publisherId], references: [id], onDelete: Cascade)
publisherId String
name String
dayofweek DayOfWeek
dayOfMonth Int?
weekOfMonth Int?
startTime DateTime
endTime DateTime
isactive Boolean @default(true)
type AvailabilityType @default(Weekly)
isWithTransport Boolean @default(false)
isFromPreviousAssignment Boolean @default(false)
isFromPreviousMonth Boolean @default(false)
repeatWeekly Boolean? // New field to indicate weekly repetition
repeatFrequency Int? // New field to indicate repetition frequency
endDate DateTime? // New field for the end date of repetition
export default function AvailabilityForm ( { publisherId , existingItems , inline , onDone , date } ) {
@@map("Availability")
}
const router = useRouter ( ) ;
const urls = {
apiUrl : "/api/data/availabilities/" ,
indexUrl : "/cart/availabilities"
} ;
const [ editMode , setEditMode ] = useState ( existingItems . length > 0 ) ;
const [ publisher , setPublisher ] = useState ( { id : publisherId } ) ;
const [ day , setDay ] = useState ( new Date ( date || new Date ( ) ) ) ;
const [ doRepeat , setDoRepeat ] = useState ( false ) ;
const [ repeatFrequency , setRepeatFrequency ] = useState ( 1 ) ;
const [ repeatUntil , setRepeatUntil ] = useState ( null ) ;
const [ canUpdate , setCanUpdate ] = useState ( true ) ;
*/
//enum for abailability type - day of week or day of month; and array of values
const AvailabilityType = {
WeeklyRecurrance : 'WeeklyRecurrance' ,
ExactDate : 'ExactDate'
}
//const AvailabilityTypeValues = Object.values(AvailabilityType);
export default function AvailabilityForm ( { publisherId , existingItem , inline , onDone , itemsForDay } ) {
const [ availability , setAvailability ] = useState ( existingItem || {
publisherId : publisherId || null ,
const [ timeSlots , setTimeSlots ] = useState ( [ ] ) ;
const [ availabilities , setAvailabilities ] = useState ( existingItems && existingItems . length > 0 ? existingItems : [ {
publisherId : publisher . id ,
name : "Нов" ,
dayofweek : "Monday" ,
dayOfMonth : null ,
@ -74,47 +43,20 @@ export default function AvailabilityForm({ publisherId, existingItem, inline, on
repeatWeekly : false ,
endDate : null ,
isFirst : false ,
} ) ;
const [ items , setItems ] = useState ( itemsForDay || [ ] ) ; // [existingItem, ...items]
isLast : false ,
} ] ) ;
const [ selectedType , setSelectedOption ] = useState ( AvailabilityType . WeeklyRecurrance ) ;
const [ isInline , setInline ] = useState ( inline || false ) ;
const [ timeSlots , setTimeSlots ] = useState ( [ ] ) ;
const [ isMobile , setIsMobile ] = useState ( false ) ;
// Check screen width to determine if the device is mobile
useEffect ( ( ) => {
const handleResize = ( ) => {
setIsMobile ( window . innerWidth < 768 ) ; // 768px is a common breakpoint for mobile devices
} ;
// Call the function to setAvailability the initial state
handleResize ( ) ;
// Add event listener
window . addEventListener ( 'resize' , handleResize ) ;
// Cleanup
return ( ) => window . removeEventListener ( 'resize' , handleResize ) ;
} , [ ] ) ;
// Inside your component
const [ config , setConfig ] = useState ( null ) ;
useEffect ( ( ) => {
fetchConfig ( ) . then ( config => {
// Use config here to adjust form fields
console . log ( "UI config: " , config ) ;
setConfig ( config ) ;
} ) ;
} , [ ] ) ;
const [ dataFetched , setDataFetched ] = useState ( false ) ;
const router = useRouter ( ) ;
const initialId = existingItem ? . id || router . query . id ;
const urls = {
apiUrl : "/api/data/availabilities/" ,
indexUrl : "/cart/availabilities"
} ;
// Define the minimum and maximum times
const minTime = new Date ( ) ;
@ -123,169 +65,162 @@ export default function AvailabilityForm({ publisherId, existingItem, inline, on
maxTime . setHours ( 20 , 0 , 0 , 0 ) ; // 8:00 PM
//always setAvailability publisherId
useEffect ( ( ) => {
availability . publisherId = publisherId ;
console . log ( "availability.publisherId: " , availability . publisherI d) ;
} , [ availability ] ) ;
if ( typeof window !== 'undefined' ) {
useEffect ( ( ) => {
// If component is not in inline mode and there's no existing availability, fetch the availability based on the query ID
// Fetch availability from DB only if it's not fetched yet, and there's no exist ing availability
if ( ! isInline && ! existingItem && ! dataFetched && router . query . id ) {
fetchItemFromDB ( parseInt ( router . query . id . toString ( ) ) ) ;
setDataFetched ( true ) ; // Set data as fetched
const fetchItemFromDB = async ( ) => {
const id = parseInt ( router . query . i d ) ;
if ( existingItems . length == 0 && id ) {
try {
const response = await axiosInstance . get ( ` /api/data/availabilities/ ${ id } ` ) ;
setAvailabilities ( [ response . data ] ) ;
setEditMode ( true ) ;
} catch ( error ) {
console . error ( error ) ;
toast . error ( "Error fetch ing availability data." ) ;
}
}
} , [ router . query . id , isInline , existingItem , dataFetched ] ) ;
}
} ;
// const [isEdit, setIsEdit] = useState(false);
const fetchItemFromDB = async ( id ) => {
try {
console . log ( "fetching availability " + id ) ;
const { data } = await axiosInstance . get ( urls . apiUrl + id ) ;
data . startTime = formatTime ( data . startTime ) ;
data . endTime = formatTime ( data . endTime ) ;
setAvailability ( data ) ;
console . log ( data ) ;
} catch ( error ) {
console . error ( error ) ;
}
} ;
fetchItemFromDB ( ) ;
} , [ router . query . id ] ) ;
const handleChange = ( { target } ) => {
// const { name, value } = e.target;
// setItem((prev) => ({ ...prev, [name]: value }));
console . log ( "AvailabilityForm: handleChange: " + target . name + " = " + target . value ) ;
setAvailability ( { ... availability , [ target . name ] : target . value } ) ;
}
const handleSubmit = async ( e ) => {
e . preventDefault ( ) ;
try {
const groupedTimeSlots = mergeCheckedTimeSlots ( timeSlots ) ;
// Determine if we need to delete and recreate, or just update
const shouldRecreate = availabilities . length !== groupedTimeSlots . length || availabilities . some ( av => ! av . id ) ;
if ( ! availability . nam e) {
// availability.name = "От календара";
availability . name = common . getTimeFomatted ( availability . startTime ) + "-" + common . getTimeFomatted ( availability . endTime ) ;
}
if ( shouldRecreat e) {
// Delete existing availabilities if they have an ID
console . log ( "Recreating availabilities" ) ;
await Promise . all ( availabilities . filter ( av => av . id ) . map ( av => axiosInstance . delete ( ` ${ urls . apiUrl } ${ av . id } ` ) ) ) ;
availability . dayofweek = common . getDayOfWeekNameEnEnum ( availability . startTime ) ;
if ( availability . repeatWeekly ) {
availability . dayOfMonth = null ;
// Create new availabilities
const createdAvailabilities = await Promise . all ( groupedTimeSlots . map ( async group => {
const newAvailability = createAvailabilityFromGroup ( group , publisher . id ) ;
const response = await axiosInstance . post ( urls . apiUrl , newAvailability ) ;
return response . data ; // Assuming the new availability is returned
} ) ) ;
setAvailabilities ( createdAvailabilities ) ;
} else {
availability . endDate = null ;
availability . dayOfMonth = availability . startTime . getDate ( ) ;
// Update existing availabilities
console . log ( "Updating existing availabilities" ) ;
const updatedAvailabilities = await Promise . all ( availabilities . map ( async ( availability , index ) => {
const group = groupedTimeSlots [ index ] ;
const updatedAvailability = updateAvailabilityFromGroup ( availability , group ) ;
await axiosInstance . put ( ` ${ urls . apiUrl } ${ availability . id } ` , updatedAvailability ) ;
return updatedAvailability ;
} ) ) ;
setAvailabilities ( updatedAvailabilities ) ;
}
delete availability . date ; //remove date from availability as it is not part of the db model
// ---------------------- CB UI --------------
const selectedSlots = timeSlots . filter ( slot => slot . isChecked ) ;
// Sort the selected intervals by start time
const sortedSlots = [ ... selectedSlots ] . sort ( ( a , b ) => a . startTime - b . startTime ) ;
// Group continuous slots
const groupedIntervals = [ ] ;
let currentGroup = [ sortedSlots [ 0 ] ] ;
for ( let i = 1 ; i < sortedSlots . length ; i ++ ) {
const previousSlot = currentGroup [ currentGroup . length - 1 ] ;
const currentSlot = sortedSlots [ i ] ;
// Calculate the difference in hours between slots
const difference = ( currentSlot . startTime - previousSlot . endTime ) / ( 60 * 60 * 1000 ) ;
// Assuming each slot represents an exact match to the increment (1.5 hours), we group them
if ( difference === 0 ) {
currentGroup . push ( currentSlot ) ;
} else {
groupedIntervals . push ( currentGroup ) ;
currentGroup = [ currentSlot ] ;
}
}
// Don't forget the last group
if ( currentGroup . length > 0 ) {
groupedIntervals . push ( currentGroup ) ;
}
// Create availability objects from grouped slots
const availabilities = groupedIntervals . map ( group => {
const startTime = group [ 0 ] . startTime ;
const endTime = group [ group . length - 1 ] . endTime ;
return {
publisherId : availability . publisherId ,
startTime : startTime ,
endTime : endTime ,
isWithTransportIn : group [ 0 ] . isFirst && timeSlots [ 0 ] . isWithTransport ,
isWithTransportOut : group [ group . length - 1 ] . isLast && timeSlots [ timeSlots . length - 1 ] . isWithTransport ,
// Add other necessary fields, like isWithTransport if applicable
} ;
} ) ;
//if more than one interval, we delete and recreate the availability, as it is not possble to map them
if ( availability . id && availabilities . length > 1 ) {
await axiosInstance . delete ( urls . apiUrl + availability . id ) ;
delete availability . id ;
}
// const firstSlotWithTransport = timeSlots[0].checked && timeSlots[0]?.isWithTransport;
// const lastSlotWithTransport = timeSlots[timeSlots.length - 1].checked && timeSlots[timeSlots.length - 1]?.isWithTransport;
availabilities . forEach ( async av => {
// expand availability
const avToStore = {
... availability ,
... av ,
startTime : av . startTime ,
endTime : av . endTime ,
name : "От календара" ,
id : undefined ,
// isWithTransportIn: firstSlotWithTransport,
// isWithTransportOut: lastSlotWithTransport,
} ;
console . log ( "AvailabilityForm: handleSubmit: " + av ) ;
if ( availability . id ) {
// UPDATE EXISTING ITEM
await axiosInstance . put ( urls . apiUrl + availability . id , {
... avToStore ,
} ) ;
} else {
// CREATE NEW ITEM
await axiosInstance . post ( urls . apiUrl , avToStore ) ;
}
handleCompletion ( avToStore ) ; // Assuming `handleCompletion` is defined to handle post-save logic
} ) ;
handleCompletion ( availability ) ;
handleCompletion ( { updated : true } ) ;
} catch ( error ) {
alert ( "Нещо с е обърка. Моля, опитайте отново по-късно." ) ;
toast . error ( "Нещо с е обърка. Моля, опитайте отново по-късно.") ;
console. error ( error . message ) ;
try {
const { data : session , status } = useSession ( ) ;
const userId = session . user . id ;
axiosInstance. post ( '/log' , { message : error . message , userId : userId } ) ;
}
catch ( err ) {
console . error ( "Error logging error: ", err ) ;
// toast.error( "Нещо с е обърка. Моля, опитайте отново по-късно.");
// console.error(error.message);
// try {
// const { data: session, status } = useSession();
// const userId = session.user.id;
// axiosInstance.post('/log', { message: error.message, userId: userId });
// }
// catch (err) {
// console.error( "Error logging error: ", err);
// }
}
} ;
function mergeCheckedTimeSlots ( timeSlots ) {
const selectedSlots = timeSlots . filter ( slot => slot . isChecked ) ;
// Sort the selected intervals by start time
const sortedSlots = [ ... selectedSlots ] . sort ( ( a , b ) => a . startTime - b . startTime ) ;
// Group continuous slots
const groupedIntervals = [ ] ;
let currentGroup = [ sortedSlots [ 0 ] ] ;
for ( let i = 1 ; i < sortedSlots . length ; i ++ ) {
const previousSlot = currentGroup [ currentGroup . length - 1 ] ;
const currentSlot = sortedSlots [ i ] ;
// Calculate the difference in hours between slots
const difference = ( currentSlot . startTime - previousSlot . endTime ) / ( 60 * 60 * 1000 ) ;
// Assuming each slot represents an exact match to the increment (1.5 hours), we group them
if ( difference === 0 ) {
currentGroup . push ( currentSlot ) ;
} else {
groupedIntervals . push ( currentGroup ) ;
currentGroup = [ currentSlot ] ;
}
}
// Don't forget the last group
if ( currentGroup . length > 0 ) {
groupedIntervals . push ( currentGroup ) ;
}
return groupedIntervals ;
}
// const firstSlotWithTransport = timeSlots[0].checked && timeSlots[0]?.isWithTransport;
// const lastSlotWithTransport = timeSlots[timeSlots.length - 1].checked && timeSlots[timeSlots.length - 1]?.isWithTransport;
function createAvailabilityFromGroup ( group ) {
const startTime = new Date ( day ) ;
startTime . setTime ( group [ 0 ] . startTime )
const endTime = new Date ( day ) ;
endTime . setTime ( group [ group . length - 1 ] . endTime ) ;
return {
name : common . getTimeFomatted ( startTime ) + "-" + common . getTimeFomatted ( endTime ) ,
publisherId : publisher . id ,
startTime : startTime ,
endTime : endTime ,
isWithTransportIn : group [ 0 ] . isFirst && timeSlots [ 0 ] . isWithTransport ,
isWithTransportOut : group [ group . length - 1 ] . isLast && timeSlots [ timeSlots . length - 1 ] . isWithTransport ,
dayofweek : common . getDayOfWeekNameEnEnum ( day . getDay ( ) ) ,
repeatWeekly : doRepeat ,
dayOfMonth : doRepeat ? null : startTime . getDate ( ) ,
endDate : doRepeat ? repeatUntil : null ,
} ;
}
function updateAvailabilityFromGroup ( availability , group ) {
availability . name = common . getTimeFomatted ( startTime ) + "-" + common . getTimeFomatted ( endTime ) ;
availability . startTime . setTime ( group [ 0 ] . startTime ) ;
availability . endTime . setTime ( group [ group . length - 1 ] . endTime ) ;
availability . isWithTransportIn = group [ 0 ] . isFirst && timeSlots [ 0 ] . isWithTransport ;
availability . isWithTransportOut = group [ group . length - 1 ] . isLast && timeSlots [ timeSlots . length - 1 ] . isWithTransport ;
availability . repeatWeekly = doRepeat ;
availability . dayOfMonth = doRepeat ? null : group . startTime . getDate ( ) ;
availability . endDate = doRepeat ? repeatUntil : null ;
return availability ;
}
const handleDelete = async ( e ) => {
e . preventDefault ( ) ;
try {
if ( availability . id ) {
// console.log("deleting publisher id = ", router.query.id, "; url=" + urls.apiUrl + router.query.id);
await axiosInstance . delete ( urls . apiUrl + availability . id ) ;
toast . success ( "Записът изтрит" , {
position : "bottom-center" ,
} ) ;
handleCompletion ( { deleted : true } ) ; // Assuming handleCompletion is defined and properly handles post-deletion logic
const deletePromises = availabilities . map ( async ( availability ) => {
if ( availability . id ) {
// console.log("deleting publisher id = ", router.query.id, "; url=" + urls.apiUrl + router.query.id);
await axiosInstance . delete ( urls . apiUrl + availability . id ) ;
}
} ) ;
await Promise . all ( deletePromises ) ;
toast . success ( "Записът изтрит" , {
position : "bottom-center" ,
} ) ;
if ( handleCompletion ) {
handleCompletion ( { deleted : true } ) ;
}
} catch ( error ) {
alert ( "Нещо с е обърка при изтриването. Моля, опитайте отново или с е свържете с нас" ) ;
@ -305,48 +240,53 @@ export default function AvailabilityForm({ publisherId, existingItem, inline, on
}
}
console. log ( "AvailabilityForm: publisherId: " + availability . publisherId + ", id: " + availability . id , ", inline: " + isInline) ;
// console.log( "AvailabilityForm: publisherId: " + publisher.id + ", id: " + availabilit .id, ", inline: " + isInline);
const generateTimeSlots = ( start , end , increment , item ) => {
const generateTimeSlots = ( start , end , increment , items ) => {
const slots = [ ] ;
// Ensure we're working with the correct date base
const baseDate = new Date ( item ? . startTime || new Date ( ) ) ;
baseDate . setHours ( start , 0 , 0 , 0 ) ; // Set start time on the base date
const baseDate = new Date ( day || new Date ( ) ) ;
baseDate . setHours ( start, 0 , 0 , 0 ) ; // Initialize base date with start hour
let currentTime = baseDate . getTime ( ) ;
const endDate = new Date ( item ? . startTime || new Date ( ) ) ;
endDate . setHours ( end , 0 , 0 , 0 ) ; // Set end time on the same date
// Assuming end time is the same for all items, otherwise, this logic needs adjustment
const endDate = new Date ( day || new Date ( ) ) ;
endDate . setHours ( end , 0 , 0 , 0 ) ;
const endTime = endDate . getTime ( ) ;
// Parse availability's startTime and endTime into Date objects for comparison
const itemStartDate = new Date ( item ? . startTime ) ;
const itemEndDate = new Date ( item ? . endTime ) ;
while ( currentTime < endTime ) {
let slotStart = new Date ( currentTime ) ;
let slotEnd = new Date ( currentTime + increment * 60 * 60 * 1000 ) ; // Calculate slot end time
let slotEnd = new Date ( currentTime + increment * 60 * 60 * 1000 ) ;
// Check if the slot overlaps with the availability's time range
const isChecked = slotStart < itemEndDate && slotEnd > itemStartDate ;
// Determine if the slot is checked based on overlapping with any item time ranges
const isChecked = items . some ( item => {
const itemStartTime = new Date ( item . startTime ) ;
const itemEndTime = new Date ( item . endTime ) ;
return slotStart < itemEndTime && slotEnd > itemStartTime ;
} ) ;
slots . push ( {
startTime : slotStart ,
endTime : slotEnd ,
isChecked : isChecked ,
} ) ;
currentTime += increment * 60 * 60 * 1000 ; // Move to the next slot
}
slots [ 0 ] . isFirst = true ;
slots [ slots . length - 1 ] . isLast = true ;
slots [ 0 ] . isWithTransport = item . isWithTransportIn ;
slots [ slots . length - 1 ] . isWithTransport = item . isWithTransportOut ;
currentTime += increment * 60 * 60 * 1000 ;
}
// Assign 'isFirst' and 'isLast' based on the slot's position in the array
if ( slots . length > 0 ) {
slots [ 0 ] . isFirst = true ;
slots [ slots . length - 1 ] . isLast = true ;
// Assuming isWithTransport flags are global settings, not unique per slot
slots [ 0 ] . isWithTransport = items [ 0 ] ? . isWithTransportIn ;
slots [ slots . length - 1 ] . isWithTransport = items [ items . length - 1 ] ? . isWithTransportOut ;
}
return slots ;
} ;
const TimeSlotCheckboxes = ( { slots , setSlots , item } ) => {
const TimeSlotCheckboxes = ( { slots , setSlots , items : [ ] } ) => {
const [ allDay , setAllDay ] = useState ( false ) ;
const handleAllDayChange = ( e ) => {
@ -378,6 +318,10 @@ export default function AvailabilityForm({ publisherId, existingItem, inline, on
if ( ( changedSlot . isFirst || changedSlot . isLast ) && ! changedSlot . isChecked ) {
changedSlot . isWithTransport = false ;
}
//if no slots are checked, disable Update button
const anyChecked = updatedSlots . some ( slot => slot . isChecked ) ;
setCanUpdate ( anyChecked ) ;
setSlots ( updatedSlots ) ;
} ;
@ -434,35 +378,34 @@ export default function AvailabilityForm({ publisherId, existingItem, inline, on
} ;
useEffect ( ( ) => {
setTimeSlots ( generateTimeSlots ( 9 , 18 , 1.5 , availability ) ) ;
setTimeSlots ( generateTimeSlots ( 9 , 18 , 1.5 , availabilities ) ) ;
} , [ ] ) ;
return (
// <div style={{ width: isMobile ? '90%' : 'max-w-xs', margin: '0 auto' }} >
< div className = "w-full" >
< ToastContainer > < / T o a s t C o n t a i n e r >
< form id = "formAv" className = "form p-5 bg-white shadow-md rounded-lg" onSubmit = { handleSubmit } >
< h3 className = "text-xl font-semibold mb-5 text-gray-800 border-b pb-2" >
{ availability . id ? "Редактирай" : "Нова" } възможност
{ editMode ? "Редактирай" : "Нова" } възможност
< / h 3 >
< LocalizationProvider dateAdapter = { AdapterDateFns } localeText = { bgBG } adapterLocale = { bg } >
< div className = "mb-2" >
< DatePicker label = "Изберете дата" value = { availability . startTime } onChange = { ( value ) => setAvailability ( { ... availability , endTime : value } ) } / >
< DatePicker label = "Изберете дата" value = { day } onChange = { ( value ) => setDay ( { value } ) } / >
< / d i v >
< div >
< div className = "mb-1" >
{ /* Time slot checkboxes */ }
< TimeSlotCheckboxes slots = { timeSlots } setSlots = { setTimeSlots } item = { availability } / >
< TimeSlotCheckboxes slots = { timeSlots } setSlots = { setTimeSlots } items = { availabilities } / >
< / d i v >
< / d i v >
< div className = "mb-2" >
< label className = "checkbox-container" >
< input type = "checkbox" checked = { availability . repeatWeekly } className = "form-checkbox h-5 w-5 text-gray-600 mx-2"
onChange = { ( ) => setAvailability ( { ... availability , repeatWeekly : ! availability . repeatWeekly } ) } / >
< input type = "checkbox" checked = { doRepeat } className = "form-checkbox h-5 w-5 text-gray-600 mx-2"
onChange = { ( e ) => setDoRepeat ( e . target . checked ) } / >
Повтаряй всяка { ' ' }
{ /* {availability. repeatWeekly && (
{ /* {repeatWeekly && (
<select
style={{
appearance: 'none',
@ -480,8 +423,8 @@ export default function AvailabilityForm({ publisherId, existingItem, inline, on
// className="appearance-none border border-black bg-transparent px-1 py-0 mx-0 mr-1 h-auto text-base text-center text-current align-middle cursor-pointer"
//className="form-select mx-2 h-8 text-gray-600"
value={availability. repeatFrequency || 1}
onChange={(e) => setAvailability({ ...availability, r epeatFrequency: parseInt (e.target.value, 10) } )}
value={repeatFrequency || 1}
onChange={(e) => setR epeatFrequency(e.target.value)}
>
<option value="1">1</option>
<option value="2">2</option>
@ -494,33 +437,26 @@ export default function AvailabilityForm({ publisherId, existingItem, inline, on
< / l a b e l >
< / d i v >
{ false && availability . repeatWeekly && (
{ false && repeatWeekly && (
< div className = "mb-2" >
< DatePicker label = "До" value = { availability . endDate } onChange = { ( value ) => setAvailability ( { ... availability , endDate : value } ) } / >
< DatePicker label = "До" value = { repeatUntil } onChange = { ( value ) => setRepeatUntil ( { value } ) } / >
< / d i v >
) }
< / L o c a l i z a t i o n P r o v i d e r >
< div className = "mb-2 hidden" >
< div className = "form-check" >
< input className = "checkbox form-input" type = "checkbox" id = "isactive" name = "isactive" onChange = { handleChange } checked = { availability . isactive } autoComplete = "off" / >
< label className = "label" htmlFor = "isactive" > активно < / l a b e l >
< / d i v >
< / d i v >
{ /* <input type="hidden" name="isactive" value={availability.isactive} /> */ }
< div className = "flex justify-between items-center flex-nowrap w-full p-1" >
< button className = "button border border-blue-500 text-blue-500 bg-transparent hover:text-white focus:outline-none focus:shadow-outline" onClick = { ( ) => handleCompletion ( ) } > Отмени < / b u t t o n >
{ availability . id && (
{ editMode && (
< > < button className = "button btn-outline bg-red-500 hover:bg-red-700 focus:outline-none focus:shadow-outline" type = "button" onClick = { handleDelete } >
Изтрий
< /button></ >
) }
< button
className = " button bg-blue-500 hover:bg-blue-700 focus:outline-none focus:shadow-outline"
> { availability . id ? "Обнови" : "Запиши" }
className = { ` button bg-blue-500 hover:bg-blue-700 focus:outline-none focus:shadow-outline ${ ! canUpdate ? 'opacity-50 cursor-not-allowed' : '' } ` }
disabled = { ! canUpdate }
> { editMode ? "Обнови" : "Запиши" }
< / b u t t o n >
< / d i v >
< / f o r m >