Days of the week in create form

This commit is contained in:
Ben Grant 2021-03-11 12:45:25 +11:00
parent 4c16a971a2
commit 4c36f2a550
4 changed files with 170 additions and 97 deletions

View file

@ -4,7 +4,7 @@ import isToday from 'dayjs/plugin/isToday';
import localeData from 'dayjs/plugin/localeData'; import localeData from 'dayjs/plugin/localeData';
import updateLocale from 'dayjs/plugin/updateLocale'; import updateLocale from 'dayjs/plugin/updateLocale';
import { Button } from 'components'; import { Button, ToggleField } from 'components';
import { useSettingsStore } from 'stores'; import { useSettingsStore } from 'stores';
import { import {
@ -55,7 +55,9 @@ const CalendarField = ({
}) => { }) => {
const weekStart = useSettingsStore(state => state.weekStart); const weekStart = useSettingsStore(state => state.weekStart);
const [dates, setDates] = useState(calculateMonth(dayjs().month(), dayjs().year(), weekStart)); const [type, setType] = useState(0);
const [dates, setDates] = useState(calculateMonth(dayjs().month(), dayjs().year(), weekStart));
const [month, setMonth] = useState(dayjs().month()); const [month, setMonth] = useState(dayjs().month());
const [year, setYear] = useState(dayjs().year()); const [year, setYear] = useState(dayjs().year());
@ -67,6 +69,14 @@ const CalendarField = ({
_setSelectingDates(newDates); _setSelectingDates(newDates);
}; };
const [selectedDays, setSelectedDays] = useState([]);
const [selectingDays, _setSelectingDays] = useState([]);
const staticSelectingDays = useRef([]);
const setSelectingDays = newDays => {
staticSelectingDays.current = newDays;
_setSelectingDays(newDays);
};
const startPos = useRef({}); const startPos = useRef({});
const staticMode = useRef(null); const staticMode = useRef(null);
const [mode, _setMode] = useState(staticMode.current); const [mode, _setMode] = useState(staticMode.current);
@ -93,89 +103,139 @@ const CalendarField = ({
id={id} id={id}
type="hidden" type="hidden"
ref={register} ref={register}
value={JSON.stringify(selectedDates)} value={type ? JSON.stringify(selectedDays) : JSON.stringify(selectedDates)}
{...props} {...props}
/> />
<CalendarHeader> <ToggleField
<Button id="calendarMode"
buttonHeight="30px" name="calendarMode"
buttonWidth="30px" options={['Specific dates', 'Days of the week']}
title="Previous month" value={type ? 'Days of the week' : 'Specific dates'}
type="button" onChange={value => setType(value === 'Specific dates' ? 0 : 1)}
onClick={() => { />
if (month-1 < 0) {
setYear(year-1);
setMonth(11);
} else {
setMonth(month-1);
}
}}
>&lt;</Button>
<span>{dayjs.months()[month]} {year}</span>
<Button
buttonHeight="30px"
buttonWidth="30px"
title="Next month"
type="button"
onClick={() => {
if (month+1 > 11) {
setYear(year+1);
setMonth(0);
} else {
setMonth(month+1);
}
}}
>&gt;</Button>
</CalendarHeader>
<CalendarDays> {type === 0 ? (
{dayjs.weekdaysShort().map((name, i) => <>
<Day key={i}>{name}</Day> <CalendarHeader>
)} <Button
</CalendarDays> buttonHeight="30px"
<CalendarBody> buttonWidth="30px"
{dates.length > 0 && dates.map((dateRow, y) => title="Previous month"
dateRow.map((date, x) => type="button"
<Date onClick={() => {
key={y+x} if (month-1 < 0) {
otherMonth={date.month() !== month} setYear(year-1);
isToday={date.isToday()} setMonth(11);
title={`${date.date()} ${dayjs.months()[date.month()]}${date.isToday() ? ' (today)' : ''}`} } else {
selected={selectedDates.includes(date.format('DDMMYYYY'))} setMonth(month-1);
selecting={selectingDates.includes(date)} }
mode={mode} }}
onPointerDown={(e) => { >&lt;</Button>
startPos.current = {x, y}; <span>{dayjs.months()[month]} {year}</span>
setMode(selectedDates.includes(date.format('DDMMYYYY')) ? 'remove' : 'add'); <Button
setSelectingDates([date]); buttonHeight="30px"
e.currentTarget.releasePointerCapture(e.pointerId); buttonWidth="30px"
title="Next month"
type="button"
onClick={() => {
if (month+1 > 11) {
setYear(year+1);
setMonth(0);
} else {
setMonth(month+1);
}
}}
>&gt;</Button>
</CalendarHeader>
document.addEventListener('pointerup', () => { <CalendarDays>
if (staticMode.current === 'add') { {dayjs.weekdaysShort().map(name =>
setSelectedDates([...selectedDates, ...staticSelectingDates.current.map(d => d.format('DDMMYYYY'))]); <Day key={name}>{name}</Day>
} else if (staticMode.current === 'remove') { )}
const toRemove = staticSelectingDates.current.map(d => d.format('DDMMYYYY')); </CalendarDays>
setSelectedDates(selectedDates.filter(d => !toRemove.includes(d))); <CalendarBody>
} {dates.length > 0 && dates.map((dateRow, y) =>
setMode(null); dateRow.map((date, x) =>
}, { once: true }); <Date
}} key={y+x}
onPointerEnter={() => { otherMonth={date.month() !== month}
if (staticMode.current) { isToday={date.isToday()}
let found = []; title={`${date.date()} ${dayjs.months()[date.month()]}${date.isToday() ? ' (today)' : ''}`}
for (let cy = Math.min(startPos.current.y, y); cy < Math.max(startPos.current.y, y)+1; cy++) { selected={selectedDates.includes(date.format('DDMMYYYY'))}
for (let cx = Math.min(startPos.current.x, x); cx < Math.max(startPos.current.x, x)+1; cx++) { selecting={selectingDates.includes(date)}
found.push({y: cy, x: cx}); mode={mode}
} onPointerDown={(e) => {
} startPos.current = {x, y};
setSelectingDates(found.map(d => dates[d.y][d.x])); setMode(selectedDates.includes(date.format('DDMMYYYY')) ? 'remove' : 'add');
} setSelectingDates([date]);
}} e.currentTarget.releasePointerCapture(e.pointerId);
>{date.date()}</Date>
) document.addEventListener('pointerup', () => {
)} if (staticMode.current === 'add') {
</CalendarBody> setSelectedDates([...selectedDates, ...staticSelectingDates.current.map(d => d.format('DDMMYYYY'))]);
} else if (staticMode.current === 'remove') {
const toRemove = staticSelectingDates.current.map(d => d.format('DDMMYYYY'));
setSelectedDates(selectedDates.filter(d => !toRemove.includes(d)));
}
setMode(null);
}, { once: true });
}}
onPointerEnter={() => {
if (staticMode.current) {
let found = [];
for (let cy = Math.min(startPos.current.y, y); cy < Math.max(startPos.current.y, y)+1; cy++) {
for (let cx = Math.min(startPos.current.x, x); cx < Math.max(startPos.current.x, x)+1; cx++) {
found.push({y: cy, x: cx});
}
}
setSelectingDates(found.map(d => dates[d.y][d.x]));
}
}}
>{date.date()}</Date>
)
)}
</CalendarBody>
</>
) : (
<CalendarBody>
{dayjs.weekdaysShort().map((name, i) =>
<Date
key={name}
isToday={dayjs.weekdaysShort()[dayjs().day()-weekStart] === name}
title={dayjs.weekdaysShort()[dayjs().day()-weekStart] === name ? 'Today' : ''}
selected={selectedDays.includes(((i + weekStart) % 7 + 7) % 7)}
selecting={selectingDays.includes(((i + weekStart) % 7 + 7) % 7)}
mode={mode}
onPointerDown={(e) => {
startPos.current = i;
setMode(selectedDays.includes(((i + weekStart) % 7 + 7) % 7) ? 'remove' : 'add');
setSelectingDays([((i + weekStart) % 7 + 7) % 7]);
e.currentTarget.releasePointerCapture(e.pointerId);
document.addEventListener('pointerup', () => {
if (staticMode.current === 'add') {
setSelectedDays([...selectedDays, ...staticSelectingDays.current]);
} else if (staticMode.current === 'remove') {
const toRemove = staticSelectingDays.current;
setSelectedDays(selectedDays.filter(d => !toRemove.includes(d)));
}
setMode(null);
}, { once: true });
}}
onPointerEnter={() => {
if (staticMode.current) {
let found = [];
for (let ci = Math.min(startPos.current, i); ci < Math.max(startPos.current, i)+1; ci++) {
found.push(((ci + weekStart) % 7 + 7) % 7);
}
setSelectingDays(found);
}
}}
>{name}</Date>
)}
</CalendarBody>
)}
</Wrapper> </Wrapper>
); );
}; };

View file

@ -12,7 +12,6 @@ export const StyledLabel = styled.label`
export const StyledSubLabel = styled.label` export const StyledSubLabel = styled.label`
display: block; display: block;
padding-bottom: 6px;
font-size: 13px; font-size: 13px;
opacity: .6; opacity: .6;
`; `;

View file

@ -26,7 +26,6 @@ export const HiddenInput = styled.input`
width: 0; width: 0;
position: absolute; position: absolute;
right: -1000px; right: -1000px;
top: 0;
&:checked + label { &:checked + label {
color: ${props => props.theme.background}; color: ${props => props.theme.background};
@ -36,8 +35,12 @@ export const HiddenInput = styled.input`
export const LabelButton = styled.label` export const LabelButton = styled.label`
padding: 6px; padding: 6px;
display: block; display: flex;
text-align: center; text-align: center;
cursor: pointer; cursor: pointer;
user-select: none; user-select: none;
height: 100%;
box-sizing: border-box;
align-items: center;
justify-content: center;
`; `;

View file

@ -82,6 +82,7 @@ const Home = () => {
if (dates.length === 0) { if (dates.length === 0) {
return setError(`You haven't selected any dates!`); return setError(`You haven't selected any dates!`);
} }
const isSpecificDates = typeof dates[0] === 'string' && dates[0].length === 8;
if (start === end) { if (start === end) {
return setError(`The start and end times can't be the same`); return setError(`The start and end times can't be the same`);
} }
@ -89,28 +90,38 @@ const Home = () => {
let times = dates.reduce((times, date) => { let times = dates.reduce((times, date) => {
let day = []; let day = [];
for (let i = start; i < (start > end ? 24 : end); i++) { for (let i = start; i < (start > end ? 24 : end); i++) {
day.push( if (isSpecificDates) {
dayjs.tz(date, 'DDMMYYYY', data.timezone) day.push(
.hour(i) dayjs.tz(date, 'DDMMYYYY', data.timezone)
.minute(0) .hour(i).minute(0).utc().format('HHmm-DDMMYYYY')
.utc() );
.format('HHmm-DDMMYYYY') } else {
); day.push(
dayjs().tz(data.timezone)
.day(date).hour(i).minute(0).utc().format('HHmm-d')
);
}
} }
if (start > end) { if (start > end) {
for (let i = 0; i < end; i++) { for (let i = 0; i < end; i++) {
day.push( if (isSpecificDates) {
dayjs.tz(date, 'DDMMYYYY', data.timezone) day.push(
.hour(i) dayjs.tz(date, 'DDMMYYYY', data.timezone)
.minute(0) .hour(i).minute(0).utc().format('HHmm-DDMMYYYY')
.utc() );
.format('HHmm-DDMMYYYY') } else {
); day.push(
dayjs().tz(data.timezone)
.day(date).hour(i).minute(0).utc().format('HHmm-d')
);
}
} }
} }
return [...times, ...day]; return [...times, ...day];
}, []); }, []);
return console.log(times);
if (times.length === 0) { if (times.length === 0) {
return setError(`You don't have any time selected`); return setError(`You don't have any time selected`);
} }