Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

all code for Milestone 2.0 #67

Merged
merged 9 commits into from
Sep 26, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/hooks.server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ export const handle = (async ({ event, resolve }) => {
// }

const cookie = event.cookies.get('session');
console.log(event.url.pathname, cookie);
console.log(event.url.pathname);
// check whether authenticated
if (
event.url.pathname !== '/' &&
Expand Down
3 changes: 3 additions & 0 deletions src/lib/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -201,3 +201,6 @@ export type Row = {
endHr: number | undefined;
endMin: number | undefined;
};

export const LEGEND_STR =
'Legend: 🏠(host) 🚗(visit) 👤(dropoff) 👥(together) 🏫(via school) ⭐(good) 🌟(great) 🙏(needed)\n';
7 changes: 5 additions & 2 deletions src/lib/format.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { EMOTICONS_REVERSE, type Row } from '$lib/constants';
import { getObjectivePronoun } from './parse';

function getScheduleItem(row: Row): string {
let scheduleItem = '';
Expand Down Expand Up @@ -32,7 +31,7 @@ function updateLastScheduleItem(schedule: string[], newDate: string): void {
dates[dates.length - 1] = newDate;
schedule[schedule.length - 1] = dates.join('-');
} else {
schedule[schedule.length - 1] += `-${newDate}`;
schedule[schedule.length - 1] = `${schedule[schedule.length - 1].trim()}-${newDate}`;
}
}

Expand Down Expand Up @@ -118,3 +117,7 @@ export function circleInviteMsg(user: any, kidNames: string[], toPhone: string)
user.firstName
}`;
}

export function fullName(firstName: string, lastName: string | null) {
return `${firstName}${lastName ? ` ${lastName}` : ''}`;
}
143 changes: 142 additions & 1 deletion src/lib/server/db.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,14 @@ import { error } from '@sveltejs/kit';

import { AvailabilityStatus, type Pronoun } from '@prisma/client';
import type { User } from '@prisma/client';
import { toLocalTimezone } from '../date';
import { dateTo12Hour, toLocalTimezone } from '../date';
import { dateNotes } from './sanitize';
import prisma from '$lib/prisma';
import { findHouseConnection } from './shared';
import { sendMsg } from './twilio';
import { DAYS } from '$lib/constants';
import { getAvailRangeParts } from '$lib/parse';
import { generateFullSchedule } from '$lib/format';

async function findHouseholdInvite(reqId: number) {
return await prisma.joinHouseholdRequest.findUnique({
Expand Down Expand Up @@ -238,6 +242,8 @@ async function acceptFriendReq(
});
console.log('leftover householdInvites', leftoverReqs3);
leftoverReqs3.forEach(({ id }) => deleteHouseholdInvite({ id }, user));

return friendHouseholdId;
}

async function findFriendReq(reqId: number) {
Expand Down Expand Up @@ -697,7 +703,142 @@ async function removeHouseholdAdult(req: { id: number }, user: User) {
});
}

async function sendFaqLinks(
adults1: { phone: string }[],
adults2: { phone: string }[],
household1: { name: string; id: number },
household2: { name: string; id: number },
initiator: User
) {
// go through each number and send the FAQ links
return await Promise.all([
...adults1.map(async ({ phone }: { phone: string }) =>
sendMsg(
{
phone,
type: 'householdFaq',
otherHouseholdName: household2.name,
otherHouseholdId: household2.id
},
initiator
)
),
...adults2.map(async ({ phone }: { phone: string }) =>
sendMsg(
{
phone,
type: 'householdFaq',
otherHouseholdName: household1.name,
otherHouseholdId: household1.id
},
initiator
)
)
]);
}

async function getHouseholdsFullSched(householdId: number, user: { timeZone: string }) {
const now = new Date();
const startDate = new Date(`${now.getMonth() + 1}/${now.getDate()}`);
const endDate = new Date(startDate);
endDate.setDate(endDate.getDate() + 21);

const dates = await prisma.availabilityDate.findMany({
where: {
householdId,
date: {
gte: startDate,
lte: endDate
}
},
orderBy: [
{
date: 'asc'
}
]
});

const rows = dates.map((d) => {
const { date, status, startTime, endTime, notes, emoticons } = d;
const englishDay = DAYS[date.getDay()];
const monthDay = `${date.getMonth() + 1}/${date.getDate()}`;

let availRange;
let startHr;
let startMin;
let endHr;
let endMin;
let emoticonSet = new Set<string>(emoticons?.split(','));
if (status === AvailabilityStatus.AVAILABLE) {
availRange = 'Available';
if (startTime && endTime)
availRange = `${dateTo12Hour(toLocalTimezone(startTime, user.timeZone))}-${dateTo12Hour(
toLocalTimezone(endTime, user.timeZone)
)}`;
const timeParts = getAvailRangeParts(availRange);
startHr = timeParts.startHr;
startMin = timeParts.startMin;
endHr = timeParts.endHr;
endMin = timeParts.endMin;
} else if (status === AvailabilityStatus.BUSY) {
availRange = 'Busy';
}

return {
englishDay,
monthDay,
availRange,
notes: notes ?? undefined,
emoticons: emoticonSet,
startHr,
startMin,
endHr,
endMin
};
});

return generateFullSchedule(rows);
}

async function sendSched(
adults1: { phone: string; timeZone: string }[],
adults2: { phone: string; timeZone: string }[],
household1: { name: string; id: number },
household2: { name: string; id: number },
initiator: User
) {
// go through each number and send sched
return await Promise.all([
...adults1.map(async (recipient: { phone: string; timeZone: string }) => {
const sched = await getHouseholdsFullSched(household2.id, recipient);
return await sendMsg(
{
phone: recipient.phone,
type: 'newFriendNotif',
sched: sched.join('\n'),
otherHouseholdName: household2.name
},
initiator
);
}),
...adults2.map(async (recipient: { phone: string; timeZone: string }) => {
const sched = await getHouseholdsFullSched(household1.id, recipient);
return await sendMsg(
{
phone: recipient.phone,
type: 'newFriendNotif',
sched: sched.join('\n'),
otherHouseholdName: household1.name
},
initiator
);
})
]);
}

export {
sendSched,
sendFaqLinks,
deleteHouseholdInvite,
acceptHouseholdInvite,
createCircleInvite,
Expand Down
13 changes: 9 additions & 4 deletions src/lib/server/sanitize.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import type { User } from '@prisma/client';
import { error } from '@sveltejs/kit';
import prisma from '$lib/prisma';
import sanitizerFunc from 'sanitize';
import { fullName } from '$lib/format';
import { LEGEND_STR } from '$lib/constants';

const sanitizer = sanitizerFunc();

Expand Down Expand Up @@ -35,11 +37,14 @@ export const circleNotif = async (sched: string, user: User, diff: boolean) => {
.map((kid) => `${kid.firstName}${kid.lastName ? ` ${kid.lastName}` : ''}`)
.join(', ');

return `${user.firstName}${
user.lastName && user.lastName.length ? ` ${user.lastName}` : ''
} (parent of ${kidNames}) has ${
return `${fullName(user.firstName, user.lastName)} (parent of ${kidNames}) has ${
diff ? 'changed the following days on' : 'updated'
} ${objectivePronoun} tentative schedule:\nLegend: 🏠(host) 🚗(visit) 👤(dropoff) 👥(together) 🏫(via school) ⭐(good) 🌟(great) 🙏(needed)\n\n${sanitizedSched}`;
} ${objectivePronoun} tentative schedule:\n${LEGEND_STR}\n${sanitizedSched}`;
};

export const newFriendNotif = async (sched: string, otherHouseholdName: string) => {
const sanitizedSched = sanitize(sched);
return `The tentative schedule of ${otherHouseholdName} is:\n${LEGEND_STR}\n${sanitizedSched}`;
};

export const dateNotes = (notes: string) => sanitize(notes);
29 changes: 29 additions & 0 deletions src/lib/server/shared.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,32 @@ export async function findHouseConnection(hId1: number, hId2: number) {
existingFriend2
};
}

export async function getUserAttrsInHousehold(id: number | null, attrs: string[]) {
if (!id) return [];
const select: { [key: string]: true } = {};
attrs.forEach((attr) => {
select[attr] = true;
});
const users = await prisma.user.findMany({
where: {
householdId: id
},
select
});
return users;
}

export async function getHousehold(id: number | null, attrs: string[]) {
if (!id) return {};
const select: { [key: string]: true } = {};
attrs.forEach((attr) => {
select[attr] = true;
});
return await prisma.household.findUnique({
where: {
id
},
select
});
}
14 changes: 12 additions & 2 deletions src/lib/server/twilio.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { env as public_env } from '$env/dynamic/public';
import { error, json } from '@sveltejs/kit';
import Twilio from 'twilio';
import type { User } from '@prisma/client';
import { circleNotif } from './sanitize';
import { circleNotif, newFriendNotif } from './sanitize';
import { generate, save } from './login';
import { toLocalTimezone } from '../date';
import { DateTime } from 'luxon';
Expand All @@ -20,6 +20,16 @@ const msgToSend = async (
const url = public_env.PUBLIC_URL;
let msg;
switch (type) {
case 'newFriendNotif': {
const { sched, otherHouseholdName } = msgComps;
msg = await newFriendNotif(sched, otherHouseholdName);
break;
}
case 'householdFaq': {
const { otherHouseholdName, otherHouseholdId } = msgComps;
msg = `Your household and ${otherHouseholdName} are now connected. Please check out their FAQ here: ${url}/household/${otherHouseholdId}`;
break;
}
case 'login': {
const { phone, token, timeZone } = msgComps;
const magicLink = await prisma.magicLink
Expand Down Expand Up @@ -151,7 +161,7 @@ const msgToSend = async (
};

export const sendMsg = async (
request: { phone: string; sendAt?: Date; type: string },
request: { phone: string; sendAt?: Date; type: string; [key: string]: any },
initiator: User | null
) => {
const { phone, sendAt, type, ...rest } = request;
Expand Down
5 changes: 4 additions & 1 deletion src/routes/+page.server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,8 @@ import { redirect } from '@sveltejs/kit';
export const load = (async ({ cookies, url }) => {
if (cookies.get('session')) throw redirect(307, '/dashboard');

return { phone: url.searchParams.get('phone') };
return {
phone: url.searchParams.get('phone') ?? cookies.get('phone'),
status: url.searchParams.get('status')
};
}) satisfies PageServerLoad;
39 changes: 39 additions & 0 deletions src/routes/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
if (input && input.style) input.style.width = '100%';
}

let authErr = false;
let serverErr = false;
onMount(() => {
const input = document.querySelector('#phone');
phoneInput = intlTelInput(input, {
Expand All @@ -24,6 +26,11 @@
stylePhoneInput();
}, 0);
if (data.phone) phoneInput.telInput.value = data.phone;
if (data.status === '403') {
authErr = true;
} else if (data.status === '500') {
serverErr = true;
}
});

async function login() {
Expand All @@ -33,6 +40,8 @@
}

const phone = phoneInput.getNumber();
document.cookie = `phone=${phone}`;

const res = await writeReq('/login', {
phone
});
Expand Down Expand Up @@ -82,6 +91,25 @@

<div id="wrapper">
<div id="main">
<dialog
class="err-dialog"
open={authErr || serverErr}
on:click={() => {
authErr = false;
serverErr = false;
}}
on:keyup={() => {
authErr = false;
serverErr = false;
}}
>
<span style="margin-right: 0.5rem;">❌</span>
{#if authErr}
Invalid / expired magic link
{:else if serverErr}
Something went wrong with logging in
{/if}
</dialog>
<div class="inner" style="padding:0">
<section id="home-section">
<div id="container04" class="style1 container default full">
Expand Down Expand Up @@ -260,6 +288,17 @@
</div>

<style>
.err-dialog {
position: fixed;
bottom: 2rem;
border-radius: 1rem;
overflow: hidden;
z-index: 2;
background: #ffd9d9;
color: red;
padding: 1.2rem 1.5rem;
}

#text41 {
padding-bottom: 0.8rem;
}
Expand Down
Loading