Created
July 8, 2021 20:09
-
-
Save tamunoibi/6ed93ab82f89d588ec8dc1faa83e3184 to your computer and use it in GitHub Desktop.
/Users/tamunoibi/Documents/workspace/frontend/src/helpers/functions.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// @flow | |
import Moment from "moment-timezone"; | |
import _ from "lodash"; | |
import { handleAPIError } from "./handleErrors"; | |
function getDateTime(time, date, timezone) { | |
const hours = Moment(time).format("HH"); | |
const minutes = Moment(time).format("mm"); | |
if (timezone) { | |
return Moment(getTimezonedDateTime(date, timezone)) | |
.hours(hours) | |
.minutes(minutes); | |
} else { | |
return Moment(date) | |
.hours(hours) | |
.minutes(minutes); | |
} | |
} | |
const tester = [ | |
{ | |
startTime: "22:00", | |
endTime: "22:00", | |
day: "MONDAY", | |
status: "UNAVAILABLE", | |
timezone: "Europe/Amsterdam" | |
} | |
]; | |
// const tester = [ | |
// { | |
// startTime: "10:00", | |
// endTime: "00:00", | |
// day: "MONDAY", | |
// status: "AVAILABLE", | |
// timezone: "Europe/Amsterdam" | |
// }, | |
// { | |
// startTime: "00:00", | |
// endTime: "23:00", | |
// day: "TUESDAY", | |
// status: "AVAILABLE", | |
// timezone: "Europe/Amsterdam" | |
// } | |
// ]; | |
export const getMonday = d => { | |
// d = new Date(d); | |
// const day = d.getDay(), | |
// diff = d.getDate() - day + (day === 0 ? -6 : 1); | |
// return new Date(d.setDate(diff)); | |
return Moment(d).startOf("isoWeek"); | |
}; | |
export const getISOStart = (epoch, end) => { | |
const unix = epoch.length < 11 ? epoch * 1000 : epoch; | |
const date = parseInt(unix, 10); | |
const monday = Moment(date) | |
.startOf("isoWeek") | |
.toISOString(); | |
const sunday = Moment(date) | |
.endOf("isoWeek") | |
.toISOString(); | |
const midnight = end ? sunday : monday; | |
return midnight; | |
}; | |
export const getWeek = monday => { | |
let day = monday; | |
const week = []; | |
let i = 0; | |
while (i < 7) { | |
week.push(Moment(day)); | |
day = Moment(day).add(1, "days"); | |
i++; | |
} | |
return week; | |
}; | |
export const fillLimit = limit => { | |
const numbers = []; | |
let i = 0; | |
while (i < limit) { | |
let x = i.toString(); | |
numbers.push(x); | |
i++; | |
} | |
return numbers; | |
}; | |
export const getRoles = (members, roleLog) => { | |
const allRoles = members.map(m => m.roles); | |
const roleList = []; | |
allRoles.forEach(r => { | |
r.forEach(r => { | |
roleList.push(r); | |
}); | |
}); | |
roleLog.forEach(r => roleList.push(r)); | |
const availableRoles = roleList.reduce((y, x) => { | |
if (!y.some(z => z.id === x.id)) y.push(x); | |
return y; | |
}, []); | |
return availableRoles; | |
}; | |
export const autoGrow = element => { | |
element.target.style.height = "auto"; | |
element.target.style.height = element.target.scrollHeight + "px"; | |
}; | |
export const getResponses = slots => { | |
const slot = slots.map(slot => { | |
const responses = []; | |
slot.requests.forEach(request => { | |
responses.push(request.status); | |
}); | |
const newSlot = { | |
limit: slot.limit, | |
responses | |
}; | |
return newSlot; | |
}); | |
return slot; | |
}; | |
// PHASE GETSTATUS OUT IN FAVOR OF GETEVENTSTATUS | |
export const getStatus = slots => { | |
const responses = getResponses(slots); | |
const statuses = responses.map(response => { | |
const amountNeeded = response.limit | |
? response.limit | |
: response.responses.length; | |
const potentials = response.responses.filter(res => { | |
return res !== "DECLINED" && res !== "CANCELLED"; | |
}); | |
const accepted = response.responses.filter(res => { | |
return res === "ACCEPTED"; | |
}); | |
if (response.responses.includes("CANCELLATION_REQUESTED")) { | |
return "ISSUE"; | |
} else if (accepted.length >= amountNeeded) { | |
return "COMPLETE"; | |
} else if ( | |
response.responses.includes("DECLINED") && | |
amountNeeded > potentials.length | |
) { | |
return "ISSUE"; | |
} else if ( | |
response.responses.includes("CANCELLED") && | |
amountNeeded > potentials.length | |
) { | |
return "ISSUE"; | |
} else if (response.responses.includes("PENDING")) { | |
return "PENDING"; | |
} else if (response.responses.includes("ACCEPTED")) { | |
return "COMPLETE"; | |
} else { | |
return "COMPLETE"; | |
} | |
}); | |
if (statuses.includes("ISSUE") || statuses.includes("ISSUE")) { | |
return "ISSUE"; | |
} else if (statuses.includes("PENDING")) { | |
return "PENDING"; | |
} else if (statuses.includes("COMPLETE")) { | |
return "COMPLETE"; | |
} else { | |
return "PUBLISHED"; // NEED TO FIGURE OUT WHEN THIS WILL OCCUR. AT LEAST WHEN YOU REMOVE ALL PEOPLE FROM A PUBLISHED EVENT | |
} | |
}; | |
// EDIT ALL OCCURENCES OF GETEVENTSTATUS TO ADD POTENTIAL PEOPLE AS ARGUMENT | |
export function getEventStatus( | |
slots = [], | |
endTime, | |
status, | |
noFinished, | |
people = [], | |
noCancellationRequestedIssue, | |
log | |
) { | |
const groupStatuses = []; | |
const requests = []; | |
const noDeletedSlots = slots.filter(s => !s.deleteSlot && !s.deleted); | |
noDeletedSlots.forEach(slot => { | |
const potentialPeople = people.filter(person => { | |
const roles = person.roles.map(role => role.name); | |
const hasRole = !slot.role ? true : roles.includes(slot.role.name); | |
let isAlreadyOnEvent = false; | |
slots.forEach(group => { | |
group.requests.forEach(request => { | |
if ( | |
request.user && | |
request.user.id === person.id && | |
!request.deleted | |
) { | |
isAlreadyOnEvent = true; | |
} | |
}); | |
}); | |
return hasRole && !isAlreadyOnEvent; | |
}).length; | |
slot.requests.forEach(r => requests.push(r)); | |
const groupStatus = getGroupStatus( | |
slot.requests, | |
slot.limit, | |
slot.minLimit, | |
endTime, | |
noFinished, | |
slot.type, | |
potentialPeople, | |
noCancellationRequestedIssue, | |
log | |
); | |
groupStatuses.push(groupStatus); | |
}); | |
if (status === "UNPUBLISHED") { | |
return "UNPUBLISHED"; | |
} else if (status === "CLOSED") { | |
return "CLOSED"; | |
} | |
if (Moment(new Date()).isAfter(endTime)) { | |
return "FINISHED"; | |
} | |
let eventStatus; | |
if (groupStatuses.includes("FINISHED")) { | |
eventStatus = "FINISHED"; | |
} else if (groupStatuses.includes("ISSUE")) { | |
eventStatus = "ISSUE"; | |
} else if (groupStatuses.includes("PENDING")) { | |
eventStatus = "PENDING"; | |
} else if (groupStatuses.includes("ACCEPTED")) { | |
eventStatus = "READY"; | |
} else { | |
eventStatus = "READY"; | |
} | |
return eventStatus; | |
} | |
// NOTE: THE CLOSED GROUP STATUS IS CURRENTLY CHECKED IN THE COMPONENT ITSELF | |
// THIS FUNCTION ONLY RUNS IF THE EVENT STATUS IS NOT CLOSED | |
export function getGroupStatus( | |
requests, | |
maxLimit, | |
minLimit, | |
endTime, | |
noFinished, | |
type, | |
potentialPeople, | |
noCancellationRequestedIssue, | |
log | |
) { | |
const after = Moment(new Date()).isAfter(endTime); | |
// if the group is in the past | |
if (after && !noFinished) { | |
return "FINISHED"; | |
} | |
// if the group has a minLimit of 0 | |
if (minLimit === 0) { | |
return "READY"; | |
} | |
// if the group has 0 requests | |
if (requests.length < 1 && !minLimit) { | |
return "READY"; | |
} | |
// collect all the responses | |
const responses = requests | |
.map(r => r.status) | |
.filter( | |
s => s !== "COVERED" && s !== "COVER_REQUESTED" && s !== "COVER_DECLINED" | |
); | |
// calculate the amount needed (if open seats: open seats, | |
// else the amount of requests without cancelled or confirmed declines) | |
const amountNeeded = minLimit | |
? minLimit | |
: responses.filter( | |
r => r !== "CANCELLED" && r !== "DECLINED_CONFIRMED" && r !== "ASSIGNED" | |
).length; | |
/* collect the requests that potentially could lead to fill up the amount needed | |
- ASSIGNED does not count towards open seats | |
- CANCELLED does not count towards open seats | |
- DECLINED does not count towards open seats | |
- DECLINED_CONFIRMED does not count towards open seats | |
*/ | |
const invited = responses.filter(res => { | |
return ( | |
res !== "DECLINED" && | |
res !== "CANCELLED" && | |
res !== "ASSIGNED" && | |
res !== "DECLINED_CONFIRMED" && | |
res !== "ACCEPTED" | |
); | |
}); | |
// collect all the accepted responses | |
const accepted = responses.filter(res => { | |
return res === "ACCEPTED"; | |
}); | |
const assigned = responses.filter(res => { | |
return res === "ASSIGNED"; | |
}); | |
const potentials = | |
type === "OPEN" | |
? potentialPeople + [...invited, ...accepted, ...assigned].length | |
: [...invited, ...accepted, ...assigned].length; | |
if ( | |
responses.includes("CANCELLATION_REQUESTED") && | |
!noCancellationRequestedIssue | |
) { | |
log && console.log(1); | |
return "ISSUE"; | |
} else if (minLimit && assigned.length + accepted.length >= amountNeeded) { | |
return "READY"; | |
} else if (responses.includes("DECLINED")) { | |
return "ISSUE"; | |
} else if (accepted.length >= amountNeeded) { | |
return "READY"; | |
} else if (amountNeeded > potentials) { | |
log && console.log(2, { amountNeeded, potentials }); | |
return "ISSUE"; | |
} else if (responses.includes("DECLINED") && amountNeeded > potentials) { | |
log && console.log(3); | |
return "ISSUE"; | |
} else if (responses.includes("CANCELLED") && amountNeeded > potentials) { | |
log && console.log(4); | |
return "ISSUE"; | |
} else if ( | |
responses.includes("PENDING") && | |
invited.length >= amountNeeded - [...assigned, ...accepted].length | |
) { | |
return "PENDING"; | |
} else if (responses.includes("ACCEPTED")) { | |
return "PENDING"; | |
} else if (potentials >= amountNeeded) { | |
return "PENDING"; | |
} else if (responses.includes("UNPUBLISHED")) { | |
return "UNPUBLISHED"; | |
} else { | |
return "READY"; | |
} | |
} | |
export const publishable = event => { | |
let publishable = false; | |
let emptyGroups = false; | |
const allRequests = []; | |
event.slots.forEach(slot => { | |
if (slot.requests.length === 0) { | |
emptyGroups = true; | |
} | |
slot.requests.forEach(request => { | |
allRequests.push(request); | |
}); | |
}); | |
if (allRequests.length > 0 && !emptyGroups) publishable = true; | |
return publishable; | |
}; | |
export const uploadFile = (file, preset) => { | |
return new Promise(function(resolve, reject) { | |
let data = new FormData(); | |
preset && data.append("upload_preset", preset); | |
data.append("file", file); | |
fetch("https://api.cloudinary.com/v1_1/soonapp/upload", { | |
method: "POST", | |
body: data | |
}) | |
.then(response => { | |
return response.json(); | |
}) | |
.then(file => { | |
resolve(file.secure_url); | |
}) | |
.catch(err => { | |
handleAPIError(err, {}); | |
reject(err); | |
}); | |
}); | |
}; | |
export const queryGoogle = (query, handleResults) => { | |
var service = new window.google.maps.places.AutocompleteService(); | |
const displaySuggestions = predictions => { | |
let googlePreds; | |
predictions ? (googlePreds = [...predictions]) : (googlePreds = []); | |
handleResults(googlePreds); | |
}; | |
service.getQueryPredictions({ input: [query] }, displaySuggestions); | |
}; | |
export async function locationValidator(location, setResult) { | |
if (window.google && location) { | |
var geocoder = new window.google.maps.Geocoder(); | |
geocoder | |
.geocode({ address: location }) | |
.then(res => { | |
setResult(true); | |
}) | |
.catch(err => { | |
setResult(false); | |
console.log(err); | |
}); | |
} | |
} | |
export const getAllRequests = (slots, role) => { | |
const requests = []; | |
const noDeletedSlots = slots.filter(s => !s.deleteSlot); | |
noDeletedSlots.forEach(slot => { | |
slot.requests.forEach(request => { | |
if (role) { | |
const req = { | |
slotId: slot.id, | |
role: slot.role, | |
...request | |
}; | |
requests.push(req); | |
} else { | |
requests.push({ ...request, slotId: slot.id }); | |
} | |
}); | |
}); | |
return requests; | |
}; | |
export const getStats = ( | |
slots = [], | |
duration, | |
startTime, | |
endTime, | |
eventBreakTime, | |
timezone | |
) => { | |
const allRequests = []; | |
let totalOpen = 0; | |
let totalActualPeople = 0; | |
// we filter deleted slots and requests with COVERED status | |
const filteredSlots = slots | |
.filter(s => !s.deleteSlot) | |
.map(slot => { | |
const requests = slot.requests.filter(r => { | |
return r.status !== "COVERED"; | |
}); | |
const newSlot = Object.assign({}, slot, { requests }); | |
return newSlot; | |
}); | |
let totalPeople = 0; | |
let totalPeopleHours = 0; | |
filteredSlots.forEach(slot => { | |
const tpth = getScheduled( | |
slot, | |
startTime, | |
endTime, | |
eventBreakTime, | |
timezone | |
); | |
totalPeopleHours = totalPeopleHours + tpth.scheduledHours; | |
totalPeople = totalPeople + tpth.scheduledCount; | |
totalActualPeople = totalActualPeople + slot.requests.length; | |
slot.requests.forEach(request => { | |
allRequests.push(request); | |
}); | |
const open = slot.limit | |
? slot.limit + slot.requests.filter(r => r.status === "ASSIGNED").length | |
: slot.requests.length - | |
slot.requests.filter( | |
r => r.status === "DECLINED_CONFIRMED" || r.status === "CANCELLED" | |
).length; | |
totalOpen = totalOpen + open; | |
}); | |
const totalAssignedAccepted = allRequests.filter( | |
request => | |
request.status === "ACCEPTED" || | |
request.status === "ASSIGNED" || | |
request.status === "CANCELLATION_REQUESTED" | |
).length; | |
const totalHoursNeeded = totalOpen * duration; | |
const allActuals = allRequests.map(r => { | |
const start = r.actualStart ? new Date(r.actualStart) : new Date(startTime); | |
const end = r.actualEnd ? new Date(r.actualEnd) : new Date(endTime); | |
const breakTime = | |
r.actualBreak || r.actualBreak === 0 | |
? r.actualBreak / 60 | |
: eventBreakTime; | |
const difference = (end - start) / (1000 * 60 * 60) - breakTime; | |
return difference; | |
}); | |
const totalActuals = allActuals.reduce((a, b) => a + b, 0); | |
const totalGroupsCreated = slots.length; | |
return { | |
totalOpen, | |
totalAssignedAccepted, | |
totalHoursNeeded, | |
totalGroupsCreated, | |
totalActuals, | |
totalActualPeople, | |
totalPeople, | |
totalPeopleHours | |
}; | |
}; | |
export function valueCheck(value) { | |
if (!value) { | |
return !!value; | |
} else { | |
return value; | |
} | |
} | |
export function equalityCheck(items, analysis) { | |
const check = []; | |
items.forEach(item => { | |
if (typeof item.a === "object") { | |
check.push({ item: item.a, result: _.isEqual(item.a, item.b) }); | |
} else if (Array.isArray(item.a)) { | |
// a and b are both arrays | |
check.push({ item: item.a, result: _.isEqual(item.a, item.b) }); | |
} else { | |
check.push({ | |
item: item.a, | |
result: valueCheck(item.a) === valueCheck(item.b) | |
}); | |
} | |
}); | |
if (analysis) { | |
const changedItems = check.filter(i => i.result === false); | |
return { | |
result: check.map(i => i.result).includes(false), | |
changed: changedItems | |
}; | |
} else { | |
if (check.map(i => i.result).includes(false)) { | |
return true; | |
} else { | |
return false; | |
} | |
} | |
} | |
function transform(status) { | |
let transformed; | |
switch (status) { | |
case "DECLINED_CONFIRMED": | |
transformed = "DECLINED"; | |
break; | |
case "PENDING": | |
transformed = "INVITED"; | |
break; | |
case "CANCELLATION_REQUESTED": | |
transformed = "CANCEL REQUESTED"; | |
break; | |
default: | |
transformed = status; | |
break; | |
} | |
return transformed; | |
} | |
export function getResponse( | |
slots, | |
userId, | |
endTime, | |
eventStatus, | |
roles = [], | |
noFinished, | |
noClosed | |
) { | |
let result; | |
slots.forEach(slot => { | |
const userHasRole = !slot.role ? true : roles.includes(slot.role.id); | |
if (slot.type === "OPEN" && userHasRole) { | |
result = "OPEN"; | |
} | |
}); | |
slots.forEach(slot => { | |
slot.requests.forEach(request => { | |
const userHasRole = !slot.role ? true : roles.includes(slot.role.id); | |
if (request.user && request.user.id === userId) { | |
if (slot.deleted) { | |
const coverRequested = checkIfCoverRequested(request); | |
result = | |
request.status === "COVERED" | |
? request.status | |
: coverRequested | |
? "COVER REQUESTED" | |
: request.status; | |
} else { | |
if (slot.type === "OPEN" && userHasRole && request.deleted) { | |
result = "OPEN"; | |
} else { | |
const coverRequested = checkIfCoverRequested(request); | |
result = | |
request.status === "COVERED" | |
? request.status | |
: coverRequested | |
? "COVER REQUESTED" | |
: request.status; | |
} | |
} | |
} | |
}); | |
}); | |
if ( | |
eventStatus === "CLOSED" && | |
!["DECLINED", "DECLINED_CONFIRMED"].includes(result) && | |
!noClosed | |
) { | |
return "CLOSED"; | |
} | |
if ( | |
endTime.isBefore(new Date()) && | |
![ | |
"PENDING", | |
"CANCELLED", | |
"COVERED", | |
"COVER_DECLINED", | |
"COVER REQUESTED", | |
"CANCELLATION_REQUESTED", | |
"DECLINED", | |
"DECLINED_CONFIRMED", | |
"OPEN" | |
].includes(result) && | |
!noFinished | |
) { | |
return "FINISHED"; | |
} | |
return transform(result); | |
} | |
export function getDay(day, direction) { | |
let d; | |
switch (day) { | |
case "MONDAY": | |
if (direction === "next") { | |
d = "TUESDAY"; | |
} else { | |
d = "SUNDAY"; | |
} | |
break; | |
case "TUESDAY": | |
if (direction === "next") { | |
d = "WEDNESDAY"; | |
} else { | |
d = "MONDAY"; | |
} | |
break; | |
case "WEDNESDAY": | |
if (direction === "next") { | |
d = "THURSDAY"; | |
} else { | |
d = "TUESDAY"; | |
} | |
break; | |
case "THURSDAY": | |
if (direction === "next") { | |
d = "FRIDAY"; | |
} else { | |
d = "WEDNESDAY"; | |
} | |
break; | |
case "FRIDAY": | |
if (direction === "next") { | |
d = "SATURDAY"; | |
} else { | |
d = "THURSDAY"; | |
} | |
break; | |
case "SATURDAY": | |
if (direction === "next") { | |
d = "SUNDAY"; | |
} else { | |
d = "FRIDAY"; | |
} | |
break; | |
case "SUNDAY": | |
if (direction === "next") { | |
d = "MONDAY"; | |
} else { | |
d = "SATURDAY"; | |
} | |
break; | |
default: | |
break; | |
} | |
return d; | |
} | |
export function capitalizeString(string) { | |
return string | |
? string.charAt(0).toUpperCase() + string.slice(1).toLowerCase() | |
: ""; | |
} | |
export function checkIfCoverRequested(currentUserRequest) { | |
if (currentUserRequest && currentUserRequest.changes) { | |
const coverChange = currentUserRequest.changes.filter( | |
change => change.status === "PENDING" && change.type === "COVER" | |
)[0]; | |
if (coverChange) { | |
return true; | |
} else { | |
return false; | |
} | |
} else { | |
return false; | |
} | |
} | |
export function getSafe(fn) { | |
try { | |
return fn(); | |
} catch (e) { | |
return undefined; | |
} | |
} | |
export function sortList(list, sort, data) { | |
if (sort.name === "Name") { | |
const sortedList = | |
sort.direction === "ascending" | |
? list.sort((a, b) => { | |
let aUser = a.user ? a.user.firstName : a.name; | |
let bUser = b.user ? b.user.firstName : b.name; | |
return aUser > bUser ? 1 : bUser > aUser ? -1 : 0; | |
}) | |
: list.sort((a, b) => { | |
let aUser = a.user ? a.user.firstName : a.name; | |
let bUser = b.user ? b.user.firstName : b.name; | |
return bUser > aUser ? 1 : aUser > bUser ? -1 : 0; | |
}); | |
return sortedList; | |
} else if (sort.name === "User") { | |
const sortedList = | |
sort.direction === "ascending" | |
? list.sort((a, b) => { | |
if (a.firstName > b.firstName) { | |
return 1; | |
} else if (b.firstName > a.firstName) { | |
return -1; | |
} | |
if (a.lastName > b.lastName) { | |
return 1; | |
} else if (b.lastName > a.lastName) { | |
return -1; | |
} | |
if (a.email > b.email) { | |
return 1; | |
} else if (b.email > a.email) { | |
return -1; | |
} else { | |
return 0; | |
} | |
}) | |
: list.sort((a, b) => { | |
if (a.firstName < b.firstName) { | |
return 1; | |
} else if (b.firstName < a.firstName) { | |
return -1; | |
} | |
if (a.lastName < b.lastName) { | |
return 1; | |
} else if (b.lastName < a.lastName) { | |
return -1; | |
} | |
if (a.email < b.email) { | |
return 1; | |
} else if (b.email < a.email) { | |
return -1; | |
} else { | |
return 0; | |
} | |
}); | |
return sortedList; | |
} else if (sort.name === "Status") { | |
const sortedList = | |
sort.direction === "ascending" | |
? list.sort((a, b) => { | |
if (a.status > b.status) { | |
return 1; | |
} else if (b.status > a.status) { | |
return -1; | |
} | |
if (a.firstName > b.firstName) { | |
return 1; | |
} else if (b.firstName > a.firstName) { | |
return -1; | |
} | |
if (a.lastName < b.lastName) { | |
return 1; | |
} else if (b.lastName < a.lastName) { | |
return -1; | |
} else { | |
return 0; | |
} | |
}) | |
: list.sort((a, b) => { | |
if (a.status < b.status) { | |
return 1; | |
} else if (b.status < a.status) { | |
return -1; | |
} | |
if (a.firstName > b.firstName) { | |
return 1; | |
} else if (b.firstName > a.firstName) { | |
return -1; | |
} | |
if (a.lastName < b.lastName) { | |
return 1; | |
} else if (b.lastName < a.lastName) { | |
return -1; | |
} else { | |
return 0; | |
} | |
}); | |
return sortedList; | |
} else if (sort.name === "Role") { | |
const noRole = list.filter(i => !i.role); | |
const role = list.filter(i => i.role); | |
const sortedRoles = | |
sort.direction === "ascending" | |
? role.sort((a, b) => | |
a.role.name > b.role.name ? 1 : b.role.name > a.role.name ? -1 : 0 | |
) | |
: role.sort((a, b) => | |
b.role.name > a.role.name ? 1 : a.role.name > b.role.name ? -1 : 0 | |
); | |
const sortedList = | |
sort.direction === "ascending" | |
? [...sortedRoles, ...noRole] | |
: [...noRole, ...sortedRoles]; | |
return sortedList; | |
} else if (sort.name === "Actual" || sort.name === "Expected") { | |
const sortedList = | |
sort.direction === "ascending" | |
? list.sort((a, b) => { | |
if (new Date(a.actualStart) > new Date(b.actualStart)) { | |
return 1; | |
} else if (new Date(b.actualStart) > new Date(a.actualStart)) { | |
return -1; | |
} | |
if (a.firstName > b.firstName) { | |
return 1; | |
} else if (b.firstName > a.firstName) { | |
return -1; | |
} | |
if (a.lastName < b.lastName) { | |
return 1; | |
} else if (b.lastName < a.lastName) { | |
return -1; | |
} else { | |
return 0; | |
} | |
}) | |
: list.sort((a, b) => { | |
if (new Date(a.actualStart) < new Date(b.actualStart)) { | |
return 1; | |
} else if (new Date(b.actualStart) < new Date(a.actualStart)) { | |
return -1; | |
} | |
if (a.firstName > b.firstName) { | |
return 1; | |
} else if (b.firstName > a.firstName) { | |
return -1; | |
} | |
if (a.lastName < b.lastName) { | |
return 1; | |
} else if (b.lastName < a.lastName) { | |
return -1; | |
} else { | |
return 0; | |
} | |
}); | |
return sortedList; | |
} else if (sort.name === "Action") { | |
function statusCheck(status, id) { | |
if (status === "DECLINED") { | |
return 2; | |
} else if (status === "CANCELLATION_REQUESTED") { | |
return 3; | |
} else if (id.includes("-")) { | |
return 1; | |
} else { | |
return 0; | |
} | |
} | |
const sortedList = list.sort((a, b) => { | |
const aAction = statusCheck(a.status, a.id); | |
const bAction = statusCheck(b.status, b.id); | |
return sort.direction === "ascending" | |
? aAction > bAction | |
? 1 | |
: bAction > aAction | |
? -1 | |
: 0 | |
: aAction > bAction | |
? -1 | |
: bAction > aAction | |
? 1 | |
: 0; | |
}); | |
return sortedList; | |
} else if (sort.name === "Access") { | |
const sortedList = | |
sort.direction === "ascending" | |
? list.sort((a, b) => { | |
if (a.access > b.access) { | |
return 1; | |
} else if (b.access > a.access) { | |
return -1; | |
} | |
if (a.firstName > b.firstName) { | |
return 1; | |
} else if (b.firstName > a.firstName) { | |
return -1; | |
} | |
if (a.lastName < b.lastName) { | |
return 1; | |
} else if (b.lastName < a.lastName) { | |
return -1; | |
} else { | |
return 0; | |
} | |
}) | |
: list.sort((a, b) => { | |
if (a.access < b.access) { | |
return 1; | |
} else if (b.access < a.access) { | |
return -1; | |
} | |
if (a.firstName > b.firstName) { | |
return 1; | |
} else if (b.firstName > a.firstName) { | |
return -1; | |
} | |
if (a.lastName < b.lastName) { | |
return 1; | |
} else if (b.lastName < a.lastName) { | |
return -1; | |
} else { | |
return 0; | |
} | |
}); | |
return sortedList; | |
} else if (sort.name === "Visibility") { | |
const sortedList = | |
sort.direction === "ascending" | |
? list.sort((a, b) => { | |
if (a.visibility > b.visibility) { | |
return 1; | |
} else if (b.visibility > a.visibility) { | |
return -1; | |
} | |
if (a.firstName > b.firstName) { | |
return 1; | |
} else if (b.firstName > a.firstName) { | |
return -1; | |
} | |
if (a.lastName < b.lastName) { | |
return 1; | |
} else if (b.lastName < a.lastName) { | |
return -1; | |
} else { | |
return 0; | |
} | |
}) | |
: list.sort((a, b) => { | |
if (a.visibility < b.visibility) { | |
return 1; | |
} else if (b.visibility < a.visibility) { | |
return -1; | |
} | |
if (a.firstName > b.firstName) { | |
return 1; | |
} else if (b.firstName > a.firstName) { | |
return -1; | |
} | |
if (a.lastName < b.lastName) { | |
return 1; | |
} else if (b.lastName < a.lastName) { | |
return -1; | |
} else { | |
return 0; | |
} | |
}); | |
return sortedList; | |
} else if (sort.name === "Last seen") { | |
const sortedList = | |
sort.direction === "ascending" | |
? list.sort((a, b) => { | |
if (new Date(a.lastSeen) > new Date(b.lastSeen)) { | |
return 1; | |
} else if (new Date(b.lastSeen) > new Date(a.lastSeen)) { | |
return -1; | |
} | |
if (a.firstName > b.firstName) { | |
return 1; | |
} else if (b.firstName > a.firstName) { | |
return -1; | |
} | |
if (a.lastName < b.lastName) { | |
return 1; | |
} else if (b.lastName < a.lastName) { | |
return -1; | |
} else { | |
return 0; | |
} | |
}) | |
: list.sort((a, b) => { | |
if (new Date(a.lastSeen) < new Date(b.lastSeen)) { | |
return 1; | |
} else if (new Date(b.lastSeen) < new Date(a.lastSeen)) { | |
return -1; | |
} | |
if (a.firstName > b.firstName) { | |
return 1; | |
} else if (b.firstName > a.firstName) { | |
return -1; | |
} | |
if (a.lastName < b.lastName) { | |
return 1; | |
} else if (b.lastName < a.lastName) { | |
return -1; | |
} else { | |
return 0; | |
} | |
}); | |
return sortedList; | |
} else if (sort.name === "Status updated") { | |
const sortedList = | |
sort.direction === "ascending" | |
? list.sort((a, b) => { | |
if (new Date(a.statusUpdated) > new Date(b.statusUpdated)) { | |
return 1; | |
} else if (new Date(b.statusUpdated) > new Date(a.statusUpdated)) { | |
return -1; | |
} | |
if (a.firstName > b.firstName) { | |
return 1; | |
} else if (b.firstName > a.firstName) { | |
return -1; | |
} | |
if (a.lastName < b.lastName) { | |
return 1; | |
} else if (b.lastName < a.lastName) { | |
return -1; | |
} else { | |
return 0; | |
} | |
}) | |
: list.sort((a, b) => { | |
if (new Date(a.statusUpdated) < new Date(b.statusUpdated)) { | |
return 1; | |
} else if (new Date(b.statusUpdated) < new Date(a.statusUpdated)) { | |
return -1; | |
} | |
if (a.firstName > b.firstName) { | |
return 1; | |
} else if (b.firstName > a.firstName) { | |
return -1; | |
} | |
if (a.lastName < b.lastName) { | |
return 1; | |
} else if (b.lastName < a.lastName) { | |
return -1; | |
} else { | |
return 0; | |
} | |
}); | |
return sortedList; | |
} else if (sort.name === "Category") { | |
const sortedList = | |
sort.direction === "ascending" | |
? list.sort((a, b) => { | |
if (a.category > b.category) { | |
return 1; | |
} else if (b.category > a.category) { | |
return -1; | |
} | |
if (a.firstName > b.firstName) { | |
return 1; | |
} else if (b.firstName > a.firstName) { | |
return -1; | |
} | |
if (a.lastName < b.lastName) { | |
return 1; | |
} else if (b.lastName < a.lastName) { | |
return -1; | |
} else { | |
return 0; | |
} | |
}) | |
: list.sort((a, b) => { | |
if (a.category < b.category) { | |
return 1; | |
} else if (b.category < a.category) { | |
return -1; | |
} | |
if (a.firstName > b.firstName) { | |
return 1; | |
} else if (b.firstName > a.firstName) { | |
return -1; | |
} | |
if (a.lastName < b.lastName) { | |
return 1; | |
} else if (b.lastName < a.lastName) { | |
return -1; | |
} else { | |
return 0; | |
} | |
}); | |
return sortedList; | |
} else if (sort.name === "When") { | |
const sortedList = | |
sort.direction === "ascending" | |
? list.sort((a, b) => { | |
const aStart = a.startDate ? a.startDate : a.startTime; | |
const bStart = b.startDate ? b.startDate : b.startTime; | |
if (new Date(aStart) > new Date(bStart)) { | |
return 1; | |
} else if (new Date(bStart) > new Date(aStart)) { | |
return -1; | |
} | |
if (a.firstName > b.firstName) { | |
return 1; | |
} else if (b.firstName > a.firstName) { | |
return -1; | |
} | |
if (a.lastName < b.lastName) { | |
return 1; | |
} else if (b.lastName < a.lastName) { | |
return -1; | |
} else { | |
return 0; | |
} | |
}) | |
: list.sort((a, b) => { | |
const aStart = a.startDate ? a.startDate : a.startTime; | |
const bStart = b.startDate ? b.startDate : b.startTime; | |
if (new Date(aStart) < new Date(bStart)) { | |
return 1; | |
} else if (new Date(bStart) < new Date(aStart)) { | |
return -1; | |
} | |
if (a.firstName > b.firstName) { | |
return 1; | |
} else if (b.firstName > a.firstName) { | |
return -1; | |
} | |
if (a.lastName < b.lastName) { | |
return 1; | |
} else if (b.lastName < a.lastName) { | |
return -1; | |
} else { | |
return 0; | |
} | |
}); | |
return sortedList; | |
} else if (sort.name === "Created" || sort.name === "Updated") { | |
const sortedList = | |
sort.direction === "ascending" | |
? list.sort((a, b) => { | |
let aStart = | |
sort.name === "Created" | |
? new Date(a.createdAt) | |
: Moment(a.updatedAt).isSame(a.createdAt, "second") | |
? "" | |
: new Date(a.updatedAt); | |
let bStart = | |
sort.name === "Created" | |
? new Date(b.createdAt) | |
: Moment(b.updatedAt).isSame(b.createdAt, "second") | |
? "" | |
: new Date(b.updatedAt); | |
if (aStart > bStart) { | |
return 1; | |
} else if (bStart > aStart) { | |
return -1; | |
} | |
if (a.firstName > b.firstName) { | |
return 1; | |
} else if (b.firstName > a.firstName) { | |
return -1; | |
} | |
if (a.lastName < b.lastName) { | |
return 1; | |
} else if (b.lastName < a.lastName) { | |
return -1; | |
} else { | |
return 0; | |
} | |
}) | |
: list.sort((a, b) => { | |
const aStart = | |
sort.name === "Created" | |
? new Date(a.createdAt) | |
: Moment(a.updatedAt).isSame(a.createdAt, "second") | |
? "" | |
: new Date(a.updatedAt); | |
const bStart = | |
sort.name === "Created" | |
? new Date(b.createdAt) | |
: Moment(b.updatedAt).isSame(b.createdAt, "second") | |
? "" | |
: new Date(b.updatedAt); | |
if (aStart < bStart) { | |
return 1; | |
} else if (bStart < aStart) { | |
return -1; | |
} | |
if (a.firstName > b.firstName) { | |
return 1; | |
} else if (b.firstName > a.firstName) { | |
return -1; | |
} | |
if (a.lastName < b.lastName) { | |
return 1; | |
} else if (b.lastName < a.lastName) { | |
return -1; | |
} else { | |
return 0; | |
} | |
}); | |
return sortedList; | |
} else if (sort.name === "Duration") { | |
const sortedList = | |
sort.direction === "ascending" | |
? list.sort((a, b) => { | |
const aDuration = a.duration.asHours; | |
const bDuration = b.duration.asHours; | |
if (aDuration > bDuration) { | |
return 1; | |
} else if (bDuration > aDuration) { | |
return -1; | |
} | |
if (a.firstName > b.firstName) { | |
return 1; | |
} else if (b.firstName > a.firstName) { | |
return -1; | |
} | |
if (a.lastName < b.lastName) { | |
return 1; | |
} else if (b.lastName < a.lastName) { | |
return -1; | |
} else { | |
return 0; | |
} | |
}) | |
: list.sort((a, b) => { | |
const aDuration = a.duration.asHours; | |
const bDuration = b.duration.asHours; | |
if (aDuration < bDuration) { | |
return 1; | |
} else if (bDuration < aDuration) { | |
return -1; | |
} | |
if (a.firstName > b.firstName) { | |
return 1; | |
} else if (b.firstName > a.firstName) { | |
return -1; | |
} | |
if (a.lastName < b.lastName) { | |
return 1; | |
} else if (b.lastName < a.lastName) { | |
return -1; | |
} else { | |
return 0; | |
} | |
}); | |
return sortedList; | |
} else if ( | |
sort.name === "Users" || | |
sort.name === "Managers" || | |
sort.name === "Groups" || | |
sort.name === "Managing" | |
) { | |
let type = sort.name.toLowerCase(); | |
if (sort.name === "Groups" || sort.name === "Managing") { | |
type = "groupsLeaveManager"; | |
} | |
const sortedList = | |
sort.direction === "ascending" | |
? list.sort((a, b) => { | |
if (a[type].length > b[type].length) { | |
return 1; | |
} else if (b[type].length > a[type].length) { | |
return -1; | |
} | |
if (a.name > b.name) { | |
return 1; | |
} else if (b.name > a.name) { | |
return -1; | |
} | |
}) | |
: list.sort((a, b) => { | |
if (a[type].length < b[type].length) { | |
return 1; | |
} else if (b[type].length < a[type].length) { | |
return -1; | |
} | |
if (a.name > b.name) { | |
return 1; | |
} else if (b.name > a.name) { | |
return -1; | |
} | |
}); | |
return sortedList; | |
} else if ( | |
sort.name === "Capacity" || | |
sort.name === "Scheduled" || | |
sort.name === "Available" || | |
sort.name === "Activities" || | |
sort.name === "Self-Schedule" || | |
sort.name === "Activity" || | |
"Note" | |
) { | |
let type = sort.name.toLowerCase(); | |
if (sort.name === "Activity") { | |
type = "name"; | |
} | |
if (sort.name === "Note") { | |
type = "description"; | |
} | |
const sortedList = | |
sort.direction === "ascending" | |
? list.sort((a, b) => { | |
if (a[type] > b[type]) { | |
return 1; | |
} else if (b[type] > a[type]) { | |
return -1; | |
} | |
if (a.name > b.name) { | |
return 1; | |
} else if (b.name > a.name) { | |
return -1; | |
} | |
}) | |
: list.sort((a, b) => { | |
if (a[type] < b[type]) { | |
return 1; | |
} else if (b[type] < a[type]) { | |
return -1; | |
} | |
if (a.name > b.name) { | |
return 1; | |
} else if (b.name > a.name) { | |
return -1; | |
} | |
}); | |
return sortedList; | |
} else if (sort.name === "Time") { | |
let type = sort.name.toLowerCase(); | |
const sortedList = | |
sort.direction === "ascending" | |
? list.sort((a, b) => { | |
if (a[type] > b[type]) { | |
return 1; | |
} else if (b[type] > a[type]) { | |
return -1; | |
} | |
if (a.name > b.name) { | |
return 1; | |
} else if (b.name > a.name) { | |
return -1; | |
} | |
}) | |
: list.sort((a, b) => { | |
if (a[type] < b[type]) { | |
return 1; | |
} else if (b[type] < a[type]) { | |
return -1; | |
} | |
if (a.name > b.name) { | |
return 1; | |
} else if (b.name > a.name) { | |
return -1; | |
} | |
}); | |
return sortedList; | |
} else { | |
return list; | |
} | |
} | |
export function getAccessAndStatus(users, notVisibleUsers) { | |
return users.map(u => { | |
const teamClass = u.teamClasses[0].userIs; | |
const visibility = !notVisibleUsers.includes(u.id); | |
let status; | |
let access; | |
switch (teamClass) { | |
case "MEMBER": | |
case "ADMIN": | |
case "SUPERADMIN": | |
status = u.isVerified ? "ACTIVE" : u.invite ? "INVITED" : "CREATED"; | |
access = teamClass; | |
break; | |
case "DEACTIVATED_MEMBER": | |
access = "MEMBER"; | |
status = "DEACTIVATED"; | |
break; | |
case "DEACTIVATED_ADMIN": | |
status = "DEACTIVATED"; | |
access = "ADMIN"; | |
break; | |
default: | |
break; | |
} | |
return { | |
...u, | |
status, | |
access, | |
visibility | |
}; | |
}); | |
} | |
export function checkValidPassword(password) { | |
const hasLowerCase = /[a-z]/.test(password); | |
const hasUpperCase = /[A-Z]/.test(password); | |
const hasNumber = /\d/.test(password); | |
const hasSymbol = /[\$\-\:\/\-\?\#\^\@\{\-\~\!\"\±\§\^\_\`\\]/.test(password); | |
const hasMoreThanEight = password.length > 7; | |
const validPassword = { | |
hasLowerCase, | |
hasUpperCase, | |
hasNumber, | |
hasSymbol, | |
hasMoreThanEight | |
}; | |
return validPassword; | |
} | |
export function trialCheck(stripeUser) { | |
if (stripeUser) { | |
const customer = stripeUser.customerData; | |
const subscriptions = customer.subscriptions.data; | |
const trial = subscriptions.filter(s => s.plan.id === "trial"); | |
let daysLeft = 0; | |
if (subscriptions.length < 1) { | |
return daysLeft; | |
} else if (trial.length > 0) { | |
const trialEnd = Moment(trial[0].trial_end * 1000); | |
const now = Moment(new Date()); | |
daysLeft = trial[0].trial_end ? trialEnd.diff(now, "days") : 0; | |
return daysLeft; | |
} else { | |
return; | |
} | |
} else { | |
return; | |
} | |
} | |
export function makeTwoDecimal(number) { | |
const n = Math.round(number * 100) / 100; | |
let roundedDuration = n.toString(); | |
if (roundedDuration.includes(".")) { | |
roundedDuration = roundedDuration.split(".").pop(); | |
if (roundedDuration.length === 1) { | |
return (roundedDuration = n + "0"); | |
} else if (roundedDuration.length === 2) { | |
return n; | |
} | |
} else { | |
return (roundedDuration = n + ".00"); | |
} | |
} | |
export function getScheduled( | |
slot, | |
startTime, | |
endTime, | |
eventBreakTime, | |
timezone | |
) { | |
let totalPeopleHours = 0; | |
let totalPeople = 0; | |
if (slot.minLimit) { | |
const expected = slot.requests.filter(r => | |
["ACCEPTED", "ASSIGNED", "DECLINED", "CANCELLATION_REQUESTED"].includes( | |
r.status | |
) | |
); | |
expected.forEach(r => { | |
const actualStart = getTimezonedDateTime(r.actualStart, timezone); | |
const actualEnd = getTimezonedDateTime(r.actualEnd, timezone); | |
const start = r.actualStart | |
? Moment(getDateTime(actualStart, startTime)) | |
: Moment(startTime); | |
const e = r.actualEnd | |
? Moment(getDateTime(actualEnd, endTime)) | |
: Moment(endTime); | |
const end = Moment(e).isSameOrBefore(start) ? e.add(1, "day") : e; | |
const breakTime = | |
r.actualBreak || r.actualBreak === 0 ? r.actualBreak : eventBreakTime; | |
const difference = Moment.duration(Moment(end).diff(start)) | |
.subtract(breakTime, "minutes") | |
.asMinutes(); | |
totalPeopleHours = totalPeopleHours + difference / 60; | |
}); | |
const count = expected.length; | |
totalPeople = totalPeople + count; | |
} else { | |
const expected = slot.requests.filter(r => | |
[ | |
"ACCEPTED", | |
"ASSIGNED", | |
"DECLINED", | |
"CANCELLATION_REQUESTED", | |
"PENDING" | |
].includes(r.status) | |
); | |
expected.forEach(r => { | |
const actualStart = getTimezonedDateTime(r.actualStart, timezone); | |
const actualEnd = getTimezonedDateTime(r.actualEnd, timezone); | |
const start = r.actualStart | |
? Moment(getDateTime(actualStart, startTime)) | |
: Moment(startTime); | |
const e = r.actualEnd | |
? Moment(getDateTime(actualEnd, endTime)) | |
: Moment(endTime); | |
const end = Moment(e).isSameOrBefore(start) ? e.add(1, "day") : e; | |
const breakTime = | |
r.actualBreak || r.actualBreak === 0 ? r.actualBreak : eventBreakTime; | |
const difference = Moment.duration(Moment(end).diff(start)) | |
.subtract(breakTime, "minutes") | |
.asMinutes(); | |
totalPeopleHours = totalPeopleHours + difference / 60; | |
}); | |
const count = expected.length; | |
totalPeople = totalPeople + count; | |
} | |
return { scheduledCount: totalPeople, scheduledHours: totalPeopleHours }; | |
} | |
export function getTimezonedDateTime(isoString, timezone) { | |
const dateTime = Moment.tz(isoString, timezone).format("DD-MM-YYYY, HH:mm"); | |
return Moment(dateTime, "DD-MM-YYYY, HH:mm").toISOString(); | |
} | |
export function getActionText( | |
status, | |
openSlots, | |
openSlotSeats, | |
openSeats, | |
detailed | |
) { | |
if (status === "OPEN") { | |
const stillOpenSlots = openSlots.filter(slot => { | |
if (slot.minLimit || slot.minLimit === 0) { | |
const requests = slot.requests.filter(request => | |
[ | |
"ACCEPTED", | |
"ASSIGNED", | |
"CANCELLATION_REQUESTED", | |
"DECLINED" | |
].includes(request.status) | |
); | |
if (requests.length >= slot.limit) { | |
return false; | |
} else { | |
return true; | |
} | |
} else { | |
return true; | |
} | |
}); | |
if (stillOpenSlots.length > 1) { | |
return { sign: "!", text: "Select role" }; | |
} else { | |
if (openSlotSeats) { | |
return { | |
sign: openSlotSeats, | |
text: `Open seat${openSlotSeats !== 1 ? "s" : ""}` | |
}; | |
} else { | |
return { sign: "!", text: detailed ? "Please respond" : "RSVP" }; | |
} | |
} | |
} else { | |
if (openSeats > 0 && status !== "COVER_REQUESTED") { | |
return { | |
sign: openSeats, | |
text: `Open seat${openSeats !== 1 ? "s" : ""}` | |
}; | |
} else { | |
return { sign: "!", text: detailed ? "Please respond" : "RSVP" }; | |
} | |
} | |
} | |
export function isLeaveManager(leaveManagers, userId, teamClass) { | |
if (leaveManagers.length > 0) { | |
if (leaveManagers.map(manager => manager.id).includes(userId)) { | |
return true; | |
} else { | |
return false; | |
} | |
} else { | |
if (["ADMIN", "SUPERADMIN"].includes(teamClass)) { | |
return true; | |
} else { | |
return false; | |
} | |
} | |
} | |
export function getActuals( | |
startTime, | |
endTime, | |
actualStart, | |
actualEnd, | |
timezone | |
) { | |
let actualStartTime; | |
let actualEndTime; | |
const actualStartHours = Moment(actualStart).format("HH"); | |
const actualStartMinutes = Moment(actualStart).format("mm"); | |
if (actualStart) { | |
if (timezone) { | |
actualStartTime = Moment(getTimezonedDateTime(startTime, timezone)) | |
.hours(actualStartHours) | |
.minutes(actualStartMinutes); | |
} else { | |
actualStartTime = Moment(startTime) | |
.hours(actualStartHours) | |
.minutes(actualStartMinutes); | |
} | |
} | |
const actualEndHours = Moment(actualEnd).format("HH"); | |
const actualEndMinutes = Moment(actualEnd).format("mm"); | |
if (actualEnd) { | |
if (timezone) { | |
actualEndTime = Moment(getTimezonedDateTime(startTime, timezone)) | |
.hours(actualEndHours) | |
.minutes(actualEndMinutes); | |
} else { | |
actualEndTime = Moment(startTime) | |
.hours(actualEndHours) | |
.minutes(actualEndMinutes); | |
} | |
if ( | |
Moment(actualEndTime).isSameOrBefore( | |
actualStartTime ? actualStartTime : startTime | |
) | |
) { | |
actualEndTime.add(1, "day"); | |
} | |
} | |
return { actualStartTime, actualEndTime }; | |
} | |
export const isIos = () => { | |
const userAgent = window.navigator.userAgent.toLowerCase(); | |
return /iphone|ipad|ipod/.test(userAgent); | |
}; | |
export const isInStandaloneMode = () => | |
"standalone" in window.navigator && window.navigator.standalone; | |
export function getUserClass(userIs) { | |
let userClass; | |
switch (userIs) { | |
case "SUPERADMIN": | |
userClass = "Admin (owner)"; | |
break; | |
case "MEMBER": | |
userClass = "Member"; | |
break; | |
case "ADMIN": | |
userClass = "Admin"; | |
break; | |
default: | |
break; | |
} | |
return userClass; | |
} | |
export function isValidUser(teamClass, isVerified) { | |
return ( | |
!["DEACTIVATED_ADMIN", "DEACTIVATED_MEMBER"].includes(teamClass) && | |
isVerified | |
); | |
} | |
function getTwoMoments({ startTime, endTime }) { | |
const esHours = startTime.slice(0, 2); | |
const esMinutes = startTime.slice(3, 5); | |
const eeHours = endTime.slice(0, 2); | |
const eeMinutes = endTime.slice(3, 5); | |
const st = Moment("20-02-2020", "DD-MM-YYYY") | |
.hours(esHours) | |
.minutes(esMinutes); | |
let et = Moment("20-02-2020", "DD-MM-YYYY") | |
.hours(eeHours) | |
.minutes(eeMinutes); | |
if (eeHours === "00" && eeMinutes === "00") { | |
et = Moment(st).endOf("day"); | |
} | |
if (st.isSameOrAfter(et)) { | |
et = Moment(et).add(1, "day"); | |
} | |
const moments = { | |
startTime: st, | |
endTime: et | |
}; | |
return moments; | |
} | |
function chunkalator({ duration, minuteDifference, reverse }) { | |
let calculation = (minuteDifference / duration) * 100; | |
if (reverse) { | |
calculation = 100 - calculation; | |
} | |
return Math.round(calculation * 10) / 10; | |
} | |
export function calculateAvailabilityScore( | |
{ | |
startTime, | |
endTime, | |
availabilities, | |
userTimezone, | |
plannerTimezone, | |
eventDate | |
}, | |
log | |
) { | |
const eventTimes = getTwoMoments({ startTime, endTime }); | |
const eStartTime = eventTimes.startTime; | |
const eEndTime = eventTimes.endTime; | |
const duration = Moment.duration(eEndTime.diff(eStartTime)).asMinutes(); | |
const overnight = !eStartTime.isSame(eEndTime, "day"); | |
function getOffsetBetweenTimezones({ plannerTimezone, userTimezone }) { | |
const plannerNumber = | |
Number(plannerTimezone.slice(0, 3) + plannerTimezone.slice(4, 6)) + 10000; | |
const userNumber = | |
Number(userTimezone.slice(0, 3) + userTimezone.slice(4, 6)) + 10000; | |
return plannerNumber - userNumber; | |
} | |
// WE WOULD PROBABLY NEED THE EVENT DATE, TO CALCULATE THE OFFSET CORRECTLY! | |
const offset = | |
userTimezone && plannerTimezone | |
? getOffsetBetweenTimezones({ | |
userTimezone: Moment(eventDate) | |
.tz(userTimezone) | |
.format("Z"), | |
plannerTimezone: Moment(eventDate) | |
.tz(plannerTimezone) | |
.format("Z") | |
}) | |
: 0; | |
if (availabilities.length === 1) { | |
const availability = availabilities[0]; | |
const availabilityTimes = getTwoMoments({ | |
startTime: availability.startTime, | |
endTime: availability.endTime | |
}); | |
const aStartTime = availabilityTimes.startTime; | |
const aEndTime = availabilityTimes.endTime; | |
// CASE MATCHING AVAILABLE | |
if (availability.status === "AVAILABLE") { | |
// if availability startTime is after event startTime | |
log && console.log("boing"); | |
log && console.log({ aStartTime, aEndTime, eStartTime, eEndTime }); | |
if (aStartTime.isAfter(eStartTime)) { | |
log && console.log("boing2"); | |
if (aStartTime.isAfter(eEndTime)) { | |
return 0; | |
} | |
// we need the difference between the availability startTime and the startTime | |
let minuteDifference = Moment.duration( | |
eEndTime.diff(aStartTime) | |
).asMinutes(); | |
// in this case the availability startTime and endTime both fall between the event | |
if (aEndTime.isBefore(eEndTime)) { | |
minuteDifference = Moment.duration( | |
aEndTime.diff(aStartTime) | |
).asMinutes(); | |
} | |
log && console.log(1, minuteDifference); | |
return chunkalator({ duration, minuteDifference }); | |
} | |
// if availability endTime is before event endTime | |
if (aEndTime.isBefore(eEndTime)) { | |
// in this case the entire availability is before the event, so this renders 0 | |
if (aEndTime.isSameOrBefore(eStartTime)) { | |
return 0; | |
} | |
// we need the difference between the availability endTime and the event endTime | |
const minuteDifference = Moment.duration( | |
aEndTime.diff(eStartTime) | |
).asMinutes(); | |
return chunkalator({ duration, minuteDifference }); | |
} | |
} | |
// CASE MATCHING UNAVAILABLE | |
if (availability.status === "UNAVAILABLE") { | |
// decide whether availability startTime or availability endTime falls between the event | |
if (aStartTime.isBetween(eStartTime, eEndTime, null, "()")) { | |
// startTime falls between | |
// calculate difference between availability startTime and event endTime | |
let minuteDifference = Moment.duration( | |
aStartTime.diff(eStartTime) | |
).asMinutes(); | |
// in this case both the availability startTime and endTime fall between the event | |
if (aEndTime.isBetween(eStartTime, eEndTime, null, "()")) { | |
const firstMinuteDifference = Moment.duration( | |
eEndTime.diff(aEndTime) | |
).asMinutes(); | |
const secondMinuteDifference = Moment.duration( | |
aStartTime.diff(eStartTime) | |
).asMinutes(); | |
minuteDifference = firstMinuteDifference + secondMinuteDifference; | |
} | |
return chunkalator({ duration, minuteDifference }); | |
} | |
if (aEndTime.isBetween(eStartTime, eEndTime, null, "()")) { | |
// endTime falls between | |
// calculate difference between event startTime and availability endTime | |
const minuteDifference = Moment.duration( | |
eEndTime.diff(aEndTime) | |
).asMinutes(); | |
return chunkalator({ duration, minuteDifference }); | |
} | |
} | |
if ( | |
aStartTime.isSameOrBefore(eStartTime) && | |
aEndTime.isSameOrAfter(eEndTime) | |
) { | |
return availability.status === "AVAILABLE" ? 100 : 0; | |
} | |
if (eStartTime.isSameOrAfter(aEndTime)) { | |
return availability.status === "AVAILABLE" ? 0 : 100; | |
} | |
if (aStartTime.isSameOrAfter(eEndTime)) { | |
return availability.status === "AVAILABLE" ? 0 : 100; | |
} | |
} | |
if (availabilities.length === 2) { | |
const availabilityOne = availabilities[0]; | |
const availabilityTwo = availabilities[1]; | |
const availabilityOneTimes = getTwoMoments({ | |
startTime: availabilityOne.startTime, | |
endTime: availabilityOne.endTime | |
}); | |
const availabilityTwoTimes = getTwoMoments({ | |
startTime: availabilityTwo.startTime, | |
endTime: availabilityTwo.endTime | |
}); | |
log && console.log({ availabilityOneTimes, availabilityTwoTimes }); | |
const aoStartTime = availabilityOneTimes.startTime; | |
const aoEndTime = availabilityOneTimes.endTime; | |
const aoDuration = Moment.duration(aoEndTime.diff(aoStartTime)).asMinutes(); | |
const atStartTime = Moment(availabilityTwoTimes.startTime); | |
const atEndTime = Moment(availabilityTwoTimes.endTime); | |
const offsetSliced = offset < 0 ? Math.abs(offset) : offset; | |
const offsetInMinutes = (offsetSliced / 100) * 60; | |
const formatted = Moment(aoStartTime).format("DD-MM-YYYY, HH:mm"); | |
const formattedPlusOffset = | |
offset < 0 | |
? Moment(aoStartTime) | |
.add(offsetInMinutes, "minutes") | |
.format("DD-MM-YYYY, HH:mm") | |
: Moment(aoStartTime) | |
.subtract(offsetInMinutes + 1, "minutes") | |
.format("DD-MM-YYYY, HH:mm"); | |
const timezoned = Moment.tz( | |
formatted, | |
"DD-MM-YYYY, HH:mm", | |
plannerTimezone | |
).format("DD"); | |
const timezonedPlusOffset = Moment.tz( | |
formattedPlusOffset, | |
"DD-MM-YYYY, HH:mm", | |
plannerTimezone | |
).format("DD"); | |
log && | |
console.log( | |
{ timezoned, timezonedPlusOffset }, | |
Moment.tz(formatted, "DD-MM-YYYY, HH:mm", plannerTimezone).format( | |
"DD-MM-YYYY, HH:mm" | |
), | |
Moment.tz( | |
formattedPlusOffset, | |
"DD-MM-YYYY, HH:mm", | |
plannerTimezone | |
).format("DD-MM-YYYY, HH:mm") | |
); | |
if (offset < 0 && timezoned !== timezonedPlusOffset) { | |
log && console.log("boing"); | |
eStartTime.add(1, "day"); | |
eEndTime.add(1, "day"); | |
} | |
if (offset > 0) { | |
eStartTime.add(1, "day"); | |
eEndTime.add(1, "day"); | |
} | |
atStartTime.add(1, "day"); | |
atEndTime.add(1, "day"); | |
if (Moment(aoEndTime).isAfter(atStartTime)) { | |
log && console.log("alo?"); | |
atStartTime.add(1, "day"); | |
atEndTime.add(1, "day"); | |
} | |
const atDuration = Moment.duration(atEndTime.diff(atStartTime)).asMinutes(); | |
log && | |
console.log(2, { | |
aoStartTime, | |
aoEndTime, | |
atStartTime, | |
atEndTime, | |
eStartTime, | |
eEndTime | |
}); | |
let minuteDifference = 0; | |
// FIRST AVAILABILITY | |
if (aoEndTime.isAfter(eStartTime)) { | |
// get a chunk | |
let difference = Moment.duration(aoEndTime.diff(eStartTime)).asMinutes(); | |
log && console.log(1, { difference }); | |
if (availabilityOne.status === "UNAVAILABLE") { | |
const endOfDay = Moment(eStartTime).endOf("day"); | |
// either this is an overnight scenario (option 2) or this is a scenario where there | |
// are two availabilities because of timezones (option 1) | |
if ( | |
atStartTime.isSame(eEndTime, "day") && | |
availabilityTwo.status === "UNAVAILABLE" && | |
!overnight | |
) { | |
log && console.log(35, "ello?"); | |
difference = Moment.duration(atStartTime.diff(eEndTime)).asMinutes(); | |
} else { | |
log && console.log(36, "ello?"); | |
if (overnight) { | |
difference = Moment.duration(endOfDay.diff(aoEndTime)).asMinutes(); | |
} else { | |
log && console.log(33224, difference); | |
// DO SOME FIX HERE!@@@!!! | |
if (eStartTime.isBefore(aoEndTime)) { | |
log && console.log(999597, difference); | |
// case ONE is that the event takes place in the first availability day entirely | |
if (eEndTime.isSame(aoStartTime, "day")) { | |
difference = Moment.duration( | |
eEndTime.diff(aoEndTime) | |
).asMinutes(); | |
} else { | |
// case TWO is that the event also takes place in the second availability day | |
difference = Moment.duration( | |
aoEndTime.diff(eStartTime) | |
).asMinutes(); | |
} | |
} | |
} | |
log && console.log(36, difference); | |
} | |
} | |
// if the entire availability falls between the event | |
if ( | |
aoStartTime.isAfter(eStartTime) && | |
aoEndTime.isSameOrBefore(eEndTime) | |
) { | |
if (availabilityOne.status === "UNAVAILABLE") { | |
const firstChunk = Moment.duration( | |
aoStartTime.diff(eStartTime) | |
).asMinutes(); | |
const endOfDay = Moment(eStartTime).endOf("day"); | |
const secondChunk = Moment.duration( | |
endOfDay.diff(aoEndTime) | |
).asMinutes(); | |
difference = firstChunk + secondChunk; | |
log && console.log(3, { difference, firstChunk, secondChunk }); | |
} else { | |
difference = aoDuration; | |
log && console.log(4, { difference }); | |
} | |
} else if ( | |
aoStartTime.isBefore(eStartTime) && | |
aoEndTime.isAfter(eEndTime) | |
) { | |
// availability catches it entirely | |
// so when available it takes the full event duration, when unavailable it takes 0 | |
difference = availabilityOne.status === "AVAILABLE" ? duration : 0; | |
log && console.log(4.5, { difference }); | |
} | |
if (aoStartTime.isAfter(eEndTime)) { | |
if (availabilityOne.status === "AVAILABLE") { | |
difference = 0; | |
} | |
} | |
minuteDifference = minuteDifference + difference; | |
} else { | |
let difference = 0; | |
if (overnight) { | |
// in this case the availability window has already ended, when the event hasn't started yet | |
// so that means we take the end of the availability till the end of the day | |
const endOfDay = Moment(eStartTime).endOf("day"); | |
// we only do it when the event starts before the second availability. Else | |
// we leave it at 0. Because the second availability will take care of the entirety. | |
if (eStartTime.isBefore(atStartTime)) { | |
difference = Moment.duration(endOfDay.diff(eStartTime)).asMinutes(); | |
} | |
log && console.log(4.6, { difference }); | |
} else { | |
// in this case the event is already ended before the second availability comes into play | |
if (eEndTime.isSameOrBefore(atStartTime)) { | |
const endOfDay = Moment(aoStartTime).endOf("day"); | |
if (eStartTime.isSameOrAfter(endOfDay)) { | |
log && console.log(4.65, { difference }); | |
difference = 0; | |
} else { | |
log && console.log(4.66, { difference }); | |
difference = Moment.duration(eEndTime.diff(eStartTime)).asMinutes(); | |
} | |
// if the event starts after the first availability | |
// but it is still in the | |
if (eStartTime.isAfter(aoEndTime)) { | |
log && console.log(4.7, { difference }); | |
if (availabilityOne.status === "UNAVAILABLE") { | |
let endOfDayFirstAvailability = Moment(aoStartTime).endOf("day"); | |
if (offset > 0) { | |
endOfDayFirstAvailability.add(offsetInMinutes, "minutes"); | |
} else if (offset < 0) { | |
endOfDayFirstAvailability.subtract(offsetInMinutes, "minutes"); | |
} | |
if (eStartTime.isBefore(endOfDayFirstAvailability)) { | |
difference = Moment.duration( | |
endOfDayFirstAvailability.diff(eStartTime) | |
).asMinutes(); | |
} | |
} | |
} | |
// THIS SHOULD BE 0. BECAUSE THE EVENT IS AFTER THE FIRST DAY | |
// SO IT HAS NO | |
} | |
} | |
log && console.log(5, { difference, duration }); | |
minuteDifference = | |
availabilityOne.status === "UNAVAILABLE" ? difference : 0; | |
} | |
log && console.log(6, { minuteDifference, duration }); | |
// SECOND AVAILABILITY | |
// the availability starts before the event has ended | |
if (atStartTime.isBefore(eEndTime)) { | |
let difference = 0; | |
log && console.log(7, { minuteDifference }); | |
log && console.log("boileo"); | |
// now we either take the entire event duration, when event starts | |
// after the availability. Or we take the chunk when the availability | |
// starts after the event start time | |
if (eStartTime.isSameOrAfter(atEndTime)) { | |
log && | |
console.log( | |
7.1454545, | |
{ minuteDifference }, | |
Moment(eStartTime).format("DD-MM, HH:mm"), | |
Moment(atEndTime).format("DD-MM, HH:mm") | |
); | |
if (availabilityTwo.status === "UNAVAILABLE") { | |
difference = Moment.duration(eEndTime.diff(eStartTime)).asMinutes(); | |
} | |
} else { | |
// get a chunk | |
if (availabilityTwo.status === "UNAVAILABLE") { | |
if (atEndTime.isBefore(eEndTime)) { | |
if (atStartTime.isSameOrAfter(eStartTime)) { | |
difference = Moment.duration( | |
atStartTime.diff(eStartTime) | |
).asMinutes(); | |
} else { | |
difference = Moment.duration( | |
eEndTime.diff(atEndTime) | |
).asMinutes(); | |
log && console.log(7.15, { difference }); | |
} | |
} else { | |
if ( | |
Moment(eStartTime).isBefore(atStartTime) && | |
Moment(eEndTime).isAfter(atStartTime) | |
) { | |
difference = Moment.duration( | |
atStartTime.diff(eStartTime) | |
).asMinutes(); | |
} else { | |
difference = Moment.duration( | |
eEndTime.diff(atStartTime) | |
).asMinutes(); | |
} | |
log && console.log(7.16, { difference }); | |
} | |
log && console.log(7.2, { difference }); | |
} else { | |
if ( | |
availabilityTwo.status === "AVAILABLE" && | |
!overnight && | |
!eStartTime.isBefore(atStartTime) && | |
!Moment(atEndTime).isBefore(eEndTime) | |
) { | |
log && console.log(7.1, { difference }); | |
difference = Moment.duration(eEndTime.diff(eStartTime)).asMinutes(); | |
} else { | |
// in this case the event falls partly in the available | |
// so we take a chunk | |
if ( | |
availabilityTwo.status === "AVAILABLE" && | |
Moment(eStartTime).isBefore(atEndTime) && | |
Moment(eEndTime).isAfter(atEndTime) | |
) { | |
difference = Moment.duration( | |
atEndTime.diff(eStartTime) | |
).asMinutes(); | |
} else { | |
difference = Moment.duration( | |
eEndTime.diff(atStartTime) | |
).asMinutes(); | |
} | |
} | |
log && console.log(7.3, { difference }); | |
} | |
} | |
log && console.log(8, { difference }); | |
// CONTINUE HERE WITH THE FAILING TEST | |
// the availability status is unavailable | |
if (availabilityTwo.status === "UNAVAILABLE") { | |
// in this case the available minutes are from the start of a day until the availability | |
// starts | |
if (overnight) { | |
const startOfDay = Moment(atStartTime) | |
.hours(0) | |
.minutes(0); | |
difference = Moment.duration( | |
atStartTime.diff(startOfDay) | |
).asMinutes(); | |
} else { | |
// in this case the event itself isn't overnight, but there are two availabilities in play | |
// this is due to a user being in another timezone. In this case, we check whether the event | |
// falls completely into the second unavailability. If so, then there are 0 minutes of availability. | |
if ( | |
eEndTime.isSameOrBefore(atEndTime) && | |
eStartTime.isSameOrAfter(atStartTime) | |
) { | |
difference = 0; | |
} | |
} | |
} | |
// if the entire availability falls between the event | |
if ( | |
atEndTime.isBefore(eEndTime) && | |
atStartTime.isSameOrAfter(eStartTime) | |
) { | |
if (availabilityTwo.status === "UNAVAILABLE") { | |
const secondChunk = Moment.duration( | |
eEndTime.diff(atEndTime) | |
).asMinutes(); | |
difference = difference + secondChunk; | |
log && console.log(10, { difference }); | |
} else { | |
if (eStartTime.isAfter(atStartTime)) { | |
difference = Moment.duration( | |
atEndTime.diff(eStartTime) | |
).asMinutes(); | |
} else { | |
difference = atDuration; | |
} | |
} | |
} | |
log && console.log(2547, { minuteDifference, difference }); | |
minuteDifference = minuteDifference + (difference > 0 ? difference : 0); | |
log && console.log(2, { minuteDifference, difference }); | |
} else if (atStartTime.isSameOrAfter(eEndTime)) { | |
// if event is before second availability b/c of timezone | |
const endOfFirstDay = Moment(aoStartTime) | |
.endOf("day") | |
.add(offsetInMinutes, "minutes"); | |
if ( | |
eEndTime.isBefore(atStartTime) && | |
eStartTime.isAfter(endOfFirstDay) && | |
offset > 0 | |
) { | |
log && console.log("NAJAA", { endOfFirstDay }); | |
if (availabilityTwo.status === "UNAVAILABLE") { | |
let difference = Moment.duration( | |
eEndTime.diff(eStartTime) | |
).asMinutes(); | |
minuteDifference = minuteDifference + difference; | |
} | |
} else if (availabilityTwo.status === "UNAVAILABLE" && overnight) { | |
const startOfDay = Moment(atStartTime).startOf("day"); | |
let difference = Moment.duration(eEndTime.diff(startOfDay)).asMinutes(); | |
minuteDifference = minuteDifference + difference; | |
} else if ( | |
availabilityTwo.status === "UNAVAILABLE" && | |
!overnight && | |
Moment(eEndTime).isSame(atStartTime, "minute") | |
) { | |
minuteDifference = | |
minuteDifference + | |
Moment.duration(eEndTime.diff(eStartTime)).asMinutes(); | |
} | |
log && console.log("ahoe1", { minuteDifference }); | |
} | |
log && console.log("ahoe2", { minuteDifference }); | |
return chunkalator({ | |
duration, | |
minuteDifference | |
}); | |
} else { | |
// availabilities are three | |
// so overnight + different timezones | |
const availabilityOne = availabilities[0]; | |
const availabilityTwo = availabilities[1]; | |
const availabilityThree = availabilities[2]; | |
const availabilityOneTimes = getTwoMoments({ | |
startTime: availabilityOne.startTime, | |
endTime: availabilityOne.endTime | |
}); | |
const availabilityTwoTimes = getTwoMoments({ | |
startTime: availabilityTwo.startTime, | |
endTime: availabilityTwo.endTime | |
}); | |
const availabilityThreeTimes = getTwoMoments({ | |
startTime: availabilityThree.startTime, | |
endTime: availabilityThree.endTime | |
}); | |
// offset > 0 === WEST | |
// offset < 0 === EAST | |
const aoStartTime = Moment(availabilityOneTimes.startTime).subtract( | |
1, | |
"days" | |
); | |
const aoEndTime = Moment(availabilityOneTimes.endTime).subtract(1, "days"); | |
const aoDuration = Moment.duration(aoEndTime.diff(aoStartTime)).asMinutes(); | |
const atStartTime = Moment(availabilityTwoTimes.startTime); | |
const atEndTime = Moment(availabilityTwoTimes.endTime); | |
const atDuration = Moment.duration(atEndTime.diff(atStartTime)).asMinutes(); | |
const adStartTime = Moment(availabilityThreeTimes.startTime).add(1, "day"); | |
const adEndTime = Moment(availabilityThreeTimes.endTime).add(1, "day"); | |
const adDuration = Moment.duration(adEndTime.diff(adStartTime)).asMinutes(); | |
// some how this needs to be done for some SOFIA cases but not LA cases? | |
if ( | |
offset < 0 && | |
Moment(aoStartTime).isSame(aoEndTime, "day") && | |
availabilityOne.status === "AVAILABLE" | |
) { | |
log && console.log("subtracted"); | |
eStartTime.subtract(1, "day"); | |
eEndTime.subtract(1, "day"); | |
} | |
log && console.log({ offset, plannerTimezone, userTimezone }); | |
log && | |
console.log({ | |
aoStartTime, | |
aoEndTime, | |
atStartTime, | |
atEndTime, | |
adStartTime, | |
adEndTime, | |
eStartTime, | |
eEndTime | |
}); | |
let minuteDifference = 0; | |
// FIRST AVAILABILITY | |
if (aoEndTime.isAfter(eStartTime)) { | |
// get a chunk | |
let difference = 0; | |
if (availabilityOne.status === "AVAILABLE") { | |
difference = Moment.duration(aoEndTime.diff(eStartTime)).asMinutes(); | |
} | |
log && console.log(1, { difference }); | |
if (availabilityOne.status === "UNAVAILABLE") { | |
const endOfDay = Moment(eStartTime).endOf("day"); | |
// either this is an overnight scenario (option 2) or this is a scenario where there | |
// are two availabilities because of timezones (option 1) | |
if ( | |
atStartTime.isSame(eEndTime, "day") && | |
availabilityTwo.status === "UNAVAILABLE" && | |
!overnight | |
) { | |
difference = Moment.duration(atStartTime.diff(eEndTime)).asMinutes(); | |
log && console.log(135, { difference }); | |
} else if (eEndTime.isAfter(aoEndTime)) { | |
difference = 0; | |
} else { | |
difference = Moment.duration(endOfDay.diff(aoEndTime)).asMinutes(); | |
log && console.log(136, { difference, endOfDay }); | |
} | |
} | |
// if the entire availability falls between the event | |
if (aoStartTime.isAfter(eStartTime)) { | |
if (availabilityOne.status === "UNAVAILABLE") { | |
const firstChunk = Moment.duration( | |
aoStartTime.diff(eStartTime) | |
).asMinutes(); | |
const endOfDay = Moment(eStartTime).endOf("day"); | |
const secondChunk = Moment.duration( | |
endOfDay.diff(aoEndTime) | |
).asMinutes(); | |
difference = firstChunk + secondChunk; | |
log && console.log(3, { difference, firstChunk, secondChunk }); | |
} else { | |
difference = aoDuration; | |
log && console.log(4, { difference }); | |
} | |
} else if ( | |
aoStartTime.isBefore(eStartTime) && | |
aoEndTime.isAfter(eEndTime) | |
) { | |
// availability catches it entirely | |
// so when available it takes the full event duration, when unavailable it takes 0 | |
difference = availabilityOne.status === "AVAILABLE" ? duration : 0; | |
log && console.log(4.5, { difference }); | |
} | |
minuteDifference = minuteDifference + difference; | |
} else { | |
let difference = 0; | |
if (overnight) { | |
// in this case the availability window has already ended, when the event hasn't started yet | |
// so that means we take the end of the availability till the end of the day | |
const endOfDay = Moment(eStartTime).endOf("day"); | |
// we only do it when the event starts before the second availability. Else | |
// we leave it at 0. Because the second availability will take care of the entirety. | |
if (eStartTime.isBefore(atStartTime)) { | |
difference = Moment.duration(endOfDay.diff(eStartTime)).asMinutes(); | |
} | |
log && console.log(4.6, { difference }); | |
} else { | |
// in this case the event is already ended before the second availability comes into play | |
if (eEndTime.isSameOrBefore(atStartTime)) { | |
difference = Moment.duration(eEndTime.diff(eStartTime)).asMinutes(); | |
log && console.log(4.7, { difference }); | |
} | |
} | |
log && console.log(5, { difference, duration }); | |
minuteDifference = | |
availabilityOne.status === "UNAVAILABLE" ? difference : 0; | |
} | |
log && console.log(6, { minuteDifference, duration }); | |
// SECOND AVAILABILITY | |
// the availability starts before the event has ended | |
if (atStartTime.isBefore(eEndTime)) { | |
let difference = 0; | |
log && console.log(7, { minuteDifference }); | |
// now we either take the entire event duration, when event starts | |
// after the availability. Or we take the chunk when the availability | |
// starts after the event start time | |
log && console.log("toli", availabilityTwo); | |
if (availabilityTwo.status === "AVAILABLE") { | |
if (eEndTime.isSameOrBefore(atEndTime)) { | |
if (eStartTime.isAfter(atStartTime)) { | |
difference = Moment.duration(eEndTime.diff(eStartTime)).asMinutes(); | |
} else { | |
// get a chunk | |
difference = Moment.duration( | |
eEndTime.diff(atStartTime) | |
).asMinutes(); | |
log && console.log("cv", { difference }); | |
} | |
} else { | |
if (eStartTime.isBefore(atStartTime)) { | |
// availability two is complete inside the event period | |
difference = Moment.duration( | |
atEndTime.diff(atStartTime) | |
).asMinutes(); | |
log && console.log("cv2", { difference }); | |
} | |
log && console.log("oli"); | |
} | |
log && console.log("boli"); | |
} | |
log && console.log(8, { difference }); | |
// CONTINUE HERE WITH THE FAILING TEST | |
// the availability status is unavailable | |
if (availabilityTwo.status === "UNAVAILABLE") { | |
// in this case the available minutes are from the start of a day until the availability | |
// starts | |
if (overnight) { | |
const startOfDay = Moment(atStartTime) | |
.hours(0) | |
.minutes(0); | |
// difference = Moment.duration( | |
// atStartTime.diff(startOfDay) | |
// ).asMinutes(); | |
log && console.log(8246, { difference }); | |
} else { | |
// in this case the event itself isn't overnight, but there are two availabilities in play | |
// this is due to a user being in another timezone. In this case, we check whether the event | |
// falls completely into the second unavailability. If so, then there are 0 minutes of availability. | |
if ( | |
eEndTime.isSameOrBefore(atEndTime) && | |
eStartTime.isSameOrAfter(atStartTime) | |
) { | |
difference = 0; | |
} | |
} | |
} | |
// if the entire availability falls between the event | |
if (atEndTime.isBefore(eEndTime) && !eStartTime.isAfter(atEndTime)) { | |
if (availabilityTwo.status === "UNAVAILABLE") { | |
const endOfDay = Moment(eStartTime).endOf("day"); | |
const secondChunk = Moment.duration( | |
atEndTime.diff(endOfDay) | |
).asMinutes(); | |
difference = difference + secondChunk; | |
} else { | |
// the second availability ends before the event ends | |
if (eStartTime.isAfter(atStartTime)) { | |
difference = Moment.duration( | |
atEndTime.diff(eStartTime) | |
).asMinutes(); | |
log && console.log(11, { difference }); | |
} else { | |
difference = atDuration; | |
log && console.log(12, { difference }); | |
} | |
} | |
} | |
log && console.log(2547, { minuteDifference, difference }); | |
minuteDifference = minuteDifference + (difference > 0 ? difference : 0); | |
log && console.log(2, { minuteDifference, difference }); | |
} else if (atStartTime.isSameOrAfter(eEndTime)) { | |
if (availabilityTwo.status === "UNAVAILABLE" && overnight) { | |
const startOfDay = Moment(atStartTime).startOf("day"); | |
let difference = Moment.duration(eEndTime.diff(startOfDay)).asMinutes(); | |
minuteDifference = minuteDifference + difference; | |
} | |
log && console.log("ahoe1", { minuteDifference }); | |
} | |
// THIRD AVAILABILITY | |
if (!eEndTime.isBefore(adStartTime)) { | |
if (adStartTime.isAfter(eStartTime)) { | |
// the third availability is after the event starttime | |
log && console.log("herzxe", minuteDifference); | |
if (eEndTime.isBefore(adEndTime)) { | |
// the event ends before the third availability | |
log && console.log(availabilityThree); | |
if (availabilityThree.status === "AVAILABLE") { | |
let difference = Moment.duration( | |
eEndTime.diff(adStartTime) | |
).asMinutes(); | |
log && console.log(3566, { difference }); | |
minuteDifference = minuteDifference + difference; | |
} | |
} | |
} | |
} | |
log && console.log("ahoe2", { minuteDifference, duration }); | |
return chunkalator({ | |
duration, | |
minuteDifference | |
}); | |
} | |
return null; | |
} | |
export function formatISOasAMPM(dateTimeString, options) { | |
let ampmString = Moment(dateTimeString).format("h:mma"); | |
if (options && options.size === "xs") { | |
ampmString = ampmString.slice(0, -1); | |
} | |
return ampmString; | |
} | |
export function format24as12(time, size) { | |
return formatISOasAMPM(Moment(time, "HH:mm").toISOString(), { size }); | |
} | |
export function format12as24(time, isEndTime) { | |
const timeIn24 = Moment(time, "h:mma").format("HH:mm"); | |
return isEndTime && timeIn24 === "00:00" ? "24:00" : timeIn24; | |
} | |
export function correctActual(baseISO, actual) { | |
return Moment( | |
Moment(baseISO).format("DD-MM-YYYY, ") + Moment(actual).format("HH:mm"), | |
"DD-MM-YYYY, HH:mm" | |
).toISOString(); | |
} | |
// export function formatHHmmAsAMPM(time) { | |
// console.log({ time }); | |
// if (time.length === 5) { | |
// console.log( | |
// "bazoo", | |
// Moment() | |
// .hours(time.slice(0, 2)) | |
// .minutes(time.slice(3, 5)) | |
// .format("h:mm A") | |
// ); | |
// return Moment() | |
// .hours(time.slice(0, 2)) | |
// .minutes(time.slice(3, 5)) | |
// .format("h:mm A"); | |
// } else if (time.length > 5) { | |
// return time; | |
// } | |
// } | |
export function checkIfUrl(string) { | |
const expression = /(https?:\/\/(?:www\.|(?!www))[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]\.[^\s]{2,}|www\.[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]\.[^\s]{2,}|https?:\/\/(?:www\.|(?!www))[a-zA-Z0-9]+\.[^\s]{2,}|www\.[a-zA-Z0-9]+\.[^\s]{2,})/gi; | |
const regex = new RegExp(expression); | |
if (string) { | |
return string.match(regex); | |
} else { | |
return false; | |
} | |
} | |
export function hexToRgbA(hex, opacity) { | |
const opacityLevel = opacity ? opacity : 0.1; | |
var c; | |
if (/^#([A-Fa-f0-9]{3}){1,2}$/.test(hex)) { | |
c = hex.substring(1).split(""); | |
if (c.length == 3) { | |
c = [c[0], c[0], c[1], c[1], c[2], c[2]]; | |
} | |
c = "0x" + c.join(""); | |
return ( | |
"rgba(" + | |
[(c >> 16) & 255, (c >> 8) & 255, c & 255].join(",") + | |
`,${opacityLevel})` | |
); | |
} | |
throw new Error("Bad Hex"); | |
} | |
export function getAdjustedActivities({ | |
activities, | |
newStartTime, | |
newEndTime, | |
requestId | |
}) { | |
const newActivities = activities.map(activity => { | |
let newActivity = activity; | |
if (activity.request && activity.request.id === requestId) { | |
if (newStartTime) { | |
if (Moment(activity.startTime).isBefore(newStartTime)) { | |
if (Moment(activity.endTime).isSameOrBefore(newStartTime)) { | |
// delete | |
newActivity = { ...newActivity, deleted: true }; | |
} else { | |
// adjust startTime | |
newActivity = { | |
...newActivity, | |
startTime: newStartTime, | |
updated: true | |
}; | |
} | |
} | |
} | |
if (newEndTime) { | |
if (Moment(activity.endTime).isAfter(newEndTime)) { | |
if (Moment(activity.startTime).isSameOrAfter(newEndTime)) { | |
// delete | |
newActivity = { ...newActivity, deleted: true }; | |
} else { | |
// adjust endTime | |
newActivity = { | |
...newActivity, | |
endTime: newEndTime, | |
updated: true | |
}; | |
} | |
} | |
} | |
} | |
return newActivity; | |
}); | |
return newActivities; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment