Skip to content

Instantly share code, notes, and snippets.

@tamunoibi
Created July 8, 2021 20:09
Show Gist options
  • Save tamunoibi/6ed93ab82f89d588ec8dc1faa83e3184 to your computer and use it in GitHub Desktop.
Save tamunoibi/6ed93ab82f89d588ec8dc1faa83e3184 to your computer and use it in GitHub Desktop.
/Users/tamunoibi/Documents/workspace/frontend/src/helpers/functions.js
// @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