getting data and starting to filter and improve flow

This commit is contained in:
Arjun Patel
2022-01-19 16:05:06 -08:00
parent 3a1731a5e9
commit cbb03df811
8 changed files with 324 additions and 64 deletions
+3 -3
View File
@@ -98,8 +98,8 @@ export default function Links() {
return false; return false;
} }
// if I am the sender, then also show // if I am the sender, then also show, but only if it's me sending to a specific person
if (link.createdByUserId == currUser.uid) { if (link.createdByUserId == currUser.uid && link.recipients?.length > 0) {
return true; return true;
} }
@@ -222,7 +222,7 @@ export default function Links() {
</Tooltip> </Tooltip>
{/* table of links */} {/* table of links */}
<div className="flex flex-row space-x-2 overflow-x-scroll py-2"> <div className="flex flex-row space-x-2 overflow-x-auto py-2">
{getFilteredContent().map((link) => ( {getFilteredContent().map((link) => (
<LinkCard key={link.id} link={link} /> <LinkCard key={link.id} link={link} />
))} ))}
+165 -37
View File
@@ -42,6 +42,8 @@ const db = getFirestore();
const lastWeek = new Date(); const lastWeek = new Date();
lastWeek.setDate(lastWeek.getDate() - 7); lastWeek.setDate(lastWeek.getDate() - 7);
const nextWeek = new Date();
nextWeek.setDate(nextWeek.getDate() + 7);
export default function DashboardRoom() { export default function DashboardRoom() {
const { currUser } = useAuth(); const { currUser } = useAuth();
@@ -52,41 +54,84 @@ export default function DashboardRoom() {
new Map<string, Room>() new Map<string, Room>()
); );
// get rooms data realtime // get recurring rooms data realtime: ALL of them
useEffect(() => { useEffect(() => {
/** /**
* QUERY: * QUERY:
* all rooms in the past week * all recurring rooms, as the created date can be a year ago
* order createdDate desc
* *
*/ */
const q = query( const q = query(
collection(db, Collections.rooms), collection(db, Collections.rooms),
where("teamId", "==", team.id), where("teamId", "==", team.id),
where("createdDate", ">", lastWeek), where("type", "==", RoomType.recurring)
orderBy("createdDate", "desc")
); );
// return unsubscribe // return unsubscribe
return onSnapshot(q, (snapshot) => { return onSnapshot(q, (snapshot) => {
snapshot.docChanges().forEach((change) => { snapshot.docChanges().forEach(handleDocChange);
let updatedRoom = change.doc.data() as Room;
updatedRoom.id = change.doc.id;
if (change.type === "added" || change.type === "modified") {
console.log("New or updated room: ", updatedRoom);
// update rooms map
setRoomsMap((prevMap) => {
return new Map(prevMap.set(updatedRoom.id, updatedRoom));
});
}
if (change.type === "removed") {
console.log("Removed room: ", updatedRoom);
}
});
}); });
}, []); }, []);
// get scheduled rooms data realtime
useEffect(() => {
/**
* QUERY:
* all scheduled rooms in the past 7 days or the next 7 days
*
*/
const q = query(
collection(db, Collections.rooms),
where("teamId", "==", team.id),
where("type", "==", RoomType.scheduled),
where("scheduledDateTime", ">", lastWeek),
where("scheduledDateTime", "<", nextWeek),
orderBy("scheduledDateTime", "asc")
);
// return unsubscribe
return onSnapshot(q, (snapshot) => {
snapshot.docChanges().forEach(handleDocChange);
});
}, []);
// get now rooms data realtime
useEffect(() => {
/**
* QUERY:
* all live/now rooms going on right now
*
*/
const q = query(
collection(db, Collections.rooms),
where("teamId", "==", team.id),
where("type", "==", RoomType.now),
where("createdDate", ">", lastWeek),
orderBy("createdDate", "asc")
);
// return unsubscribe
return onSnapshot(q, (snapshot) => {
snapshot.docChanges().forEach(handleDocChange);
});
}, []);
function handleDocChange(change) {
let updatedRoom = change.doc.data() as Room;
updatedRoom.id = change.doc.id;
if (change.type === "added" || change.type === "modified") {
console.log("New or updated room: ", updatedRoom);
// update rooms map
setRoomsMap((prevMap) => {
return new Map(prevMap.set(updatedRoom.id, updatedRoom));
});
}
if (change.type === "removed") {
console.log("Removed room: ", updatedRoom);
}
}
// on CTRL + Q, new tab to google meet // on CTRL + Q, new tab to google meet
// on CTRL + V, show modal to create meeting with the link // on CTRL + V, show modal to create meeting with the link
@@ -94,7 +139,9 @@ export default function DashboardRoom() {
RoomTypeFilter.me RoomTypeFilter.me
); );
// sort this mega array
const allRooms = Array.from(roomsMap.values()); const allRooms = Array.from(roomsMap.values());
const teamRooms = allRooms.filter( const teamRooms = allRooms.filter(
(room) => room.status != RoomStatus.archived (room) => room.status != RoomStatus.archived
); );
@@ -112,15 +159,106 @@ export default function DashboardRoom() {
// return data based on the selected filters // return data based on the selected filters
switch (selectedTabPane) { switch (selectedTabPane) {
case RoomTypeFilter.team: case RoomTypeFilter.team:
return teamRooms; return teamRooms.map((room) => {
// if the room is
return (
<RoomCard
key={room.id}
room={room}
updateRoomHandler={handleUpdateRoom}
/>
);
});
case RoomTypeFilter.me: case RoomTypeFilter.me:
return meRooms; // render sections for different types
const recurring = meRooms.filter(
(room) => room.type == RoomType.recurring
);
const now = meRooms.filter((room) => room.status == RoomStatus.live);
const scheduled = meRooms.filter(
(room) => room.type == RoomType.scheduled
);
return (
<>
<span>Live</span>
<div className="flex flex-row overflow-x-auto">
{now.map((room) => (
<RoomCard
key={room.id}
room={room}
updateRoomHandler={handleUpdateRoom}
/>
))}
</div>
<span>Scheduled</span>
<div className="flex flex-row overflow-x-auto">
{scheduled.map((room) => (
<RoomCard
key={room.id}
room={room}
updateRoomHandler={handleUpdateRoom}
/>
))}
</div>
<span>Recurring</span>
<div className="flex flex-row overflow-x-auto">
{recurring.map((room) => (
<RoomCard
key={room.id}
room={room}
updateRoomHandler={handleUpdateRoom}
/>
))}
</div>
</>
);
// return meRooms.map((room) => {
// return (
// <RoomCard
// key={room.id}
// room={room}
// updateRoomHandler={handleUpdateRoom}
// />
// );
// });
case RoomTypeFilter.live: case RoomTypeFilter.live:
return liveRooms; return liveRooms.map((room) => {
// if the room is
return (
<RoomCard
key={room.id}
room={room}
updateRoomHandler={handleUpdateRoom}
/>
);
});
case RoomTypeFilter.archived: case RoomTypeFilter.archived:
return archivedRooms; return archivedRooms.map((room) => {
// if the room is
return (
<RoomCard
key={room.id}
room={room}
updateRoomHandler={handleUpdateRoom}
/>
);
});
default: default:
return allRooms; return allRooms.map((room) => {
// if the room is
return (
<RoomCard
key={room.id}
room={room}
updateRoomHandler={handleUpdateRoom}
/>
);
});
} }
} }
@@ -164,7 +302,7 @@ export default function DashboardRoom() {
} }
return ( return (
<section className="p-5 flex-1 flex flex-col bg-gray-100 bg-opacity-25 rounded-lg shadow-md flex-shrink-0"> <section className="p-5 grow shrink-0 flex flex-col bg-gray-100 bg-opacity-25 rounded-lg shadow-md">
{/* modal for creating room */} {/* modal for creating room */}
<CreateOrUpdateRoom <CreateOrUpdateRoom
show={showModalType == ShowModalType.createRoom} show={showModalType == ShowModalType.createRoom}
@@ -240,17 +378,7 @@ export default function DashboardRoom() {
</Tooltip> </Tooltip>
{/* all rooms */} {/* all rooms */}
<span className="flex flex-row flex-wrap overflow-auto h-[32rem]"> <span className="h-[32rem] overflow-auto">{getRoomContent()}</span>
{getRoomContent().map((room) => {
return (
<RoomCard
key={room.id}
room={room}
updateRoomHandler={handleUpdateRoom}
/>
);
})}
</span>
</section> </section>
); );
} }
+1 -1
View File
@@ -208,7 +208,7 @@ export default function TeamVoiceLine() {
} }
return ( return (
<section className="p-5 flex flex-col bg-gray-100 bg-opacity-25 rounded-lg shadow-md"> <section className="p-5 flex flex-col bg-gray-100 bg-opacity-25 rounded-lg shadow-md w-96 shrink-0">
<span className="flex flex-row justify-start items-center pb-5"> <span className="flex flex-row justify-start items-center pb-5">
<span className="flex flex-col"> <span className="flex flex-col">
<span className="text-white">TEAM</span> <span className="text-white">TEAM</span>
+105 -21
View File
@@ -1,4 +1,15 @@
import { Divider, Modal, Radio, Select, Switch, Tooltip } from "antd"; import {
DatePicker,
Divider,
Modal,
Radio,
Select,
Switch,
TimePicker,
Tooltip,
} from "antd";
import { Timestamp } from "firebase/firestore";
import moment from "moment";
import React, { useEffect, useState } from "react"; import React, { useEffect, useState } from "react";
import toast from "react-hot-toast"; import toast from "react-hot-toast";
import { useAuth } from "../../contexts/authContext"; import { useAuth } from "../../contexts/authContext";
@@ -41,6 +52,13 @@ export default function CreateOrUpdateRoomModal(props: IModalProps) {
setMembersSelected(props.updateRoom.members); setMembersSelected(props.updateRoom.members);
setRoomType(props.updateRoom.type); setRoomType(props.updateRoom.type);
setRoomAppxDateTime(props.updateRoom.approximateDateTime); setRoomAppxDateTime(props.updateRoom.approximateDateTime);
if (props.updateRoom.scheduledDateTime) {
const convertedToMoment = moment(
props.updateRoom.scheduledDateTime.toDate()
);
setDateTimePicker(convertedToMoment);
}
} else { } else {
// update state when user does ctrl + v // update state when user does ctrl + v
resetForm(); resetForm();
@@ -77,10 +95,32 @@ export default function CreateOrUpdateRoomModal(props: IModalProps) {
} }
if (roomType == RoomType.now) { if (roomType == RoomType.now) {
// make sure approximate time isn't selected
newRoom.approximateDateTime = null;
newRoom.status = RoomStatus.live; newRoom.status = RoomStatus.live;
} else if (roomType == RoomType.scheduled) {
// make sure that either appx or time picker is selected, not both
if (roomAppxDateTime && dateTimePicker) {
toast.error(
"Please only select an approximate slot or specific time, not both!"
);
return;
} else if (roomAppxDateTime) {
newRoom.approximateDateTime = roomAppxDateTime;
} else {
newRoom.scheduledDateTime = Timestamp.fromDate(
dateTimePicker.toDate()
);
}
} else if (roomType == RoomType.recurring) {
// clear the field for the time picker if they ever selected that
newRoom.scheduledDateTime = null;
newRoom.approximateDateTime = roomAppxDateTime;
} }
newRoom.approximateDateTime = roomAppxDateTime; // newRoom.approximateDateTime = roomAppxDateTime;
newRoom.link = roomLink; newRoom.link = roomLink;
newRoom.members = [...membersSelected]; // add currUser to the list of "people" newRoom.members = [...membersSelected]; // add currUser to the list of "people"
newRoom.type = roomType; newRoom.type = roomType;
@@ -94,13 +134,15 @@ export default function CreateOrUpdateRoomModal(props: IModalProps) {
newRoom.membersInRoom = props.updateRoom.membersInRoom; newRoom.membersInRoom = props.updateRoom.membersInRoom;
} }
console.log(newRoom);
handleModalType(ShowModalType.na);
await roomService.createOrUpdateRoom(newRoom); await roomService.createOrUpdateRoom(newRoom);
resetForm(); resetForm();
toast.success("done"); toast.success("done");
handleModalType(ShowModalType.na);
} catch (error) { } catch (error) {
toast.error("problem creating room"); toast.error("problem creating room");
console.log(error); console.log(error);
@@ -116,6 +158,8 @@ export default function CreateOrUpdateRoomModal(props: IModalProps) {
setRoomAppxDateTime(""); setRoomAppxDateTime("");
setRoomType(RoomType.now); setRoomType(RoomType.now);
setDateTimePicker(null);
setShowMoreDetails(false); setShowMoreDetails(false);
} }
@@ -130,6 +174,7 @@ export default function CreateOrUpdateRoomModal(props: IModalProps) {
const [roomType, setRoomType] = useState<RoomType>(RoomType.now); const [roomType, setRoomType] = useState<RoomType>(RoomType.now);
const [roomAppxDateTime, setRoomAppxDateTime] = useState<string>(""); // for certain room types const [roomAppxDateTime, setRoomAppxDateTime] = useState<string>(""); // for certain room types
const [dateTimePicker, setDateTimePicker] = useState(null);
const [showMoreDetails, setShowMoreDetails] = useState<boolean>(false); const [showMoreDetails, setShowMoreDetails] = useState<boolean>(false);
@@ -141,6 +186,14 @@ export default function CreateOrUpdateRoomModal(props: IModalProps) {
console.log(value); console.log(value);
} }
function handleDateTimePickerChange(time) {
console.log(time);
setRoomAppxDateTime("");
setDateTimePicker(time);
}
const allUsersForSelection: User[] = [...teamUsers, user]; const allUsersForSelection: User[] = [...teamUsers, user];
const MemberSelection = () => { const MemberSelection = () => {
@@ -235,23 +288,54 @@ export default function CreateOrUpdateRoomModal(props: IModalProps) {
</Radio.Group> </Radio.Group>
{roomType == RoomType.recurring || roomType == RoomType.scheduled ? ( {roomType == RoomType.recurring || roomType == RoomType.scheduled ? (
<Tooltip <div className="flex flex-row items-center">
title={`Put things like "ping me when ready" or "sometime this afternoon"`} <Tooltip
> title={`Put things like "ping me when ready" or "sometime this afternoon"`}
<span className="flex flex-col items-start flex-1 mt-4"> >
<span className="text-md">Approximate Slot</span> <span className="flex flex-col items-stretch flex-1 mt-4">
<span className="text-gray-300 text-xs mb-2 flex-1"> <span className="text-md">Approximate Slot</span>
The calendar way of doing things is overwhelming. Put a rough <span className="text-gray-300 text-xs mb-2 flex-1">
day/time that makes sense to you. Sometimes you don&#39;t have a specific time or want to
propose a rough period.
</span>
<input
placeholder="ex. 2pm-ish...after lunch...every evening"
className="w-full rounded-lg bg-gray-50 p-3"
value={roomAppxDateTime}
onChange={(e) => setRoomAppxDateTime(e.target.value)}
/>
</span> </span>
<input </Tooltip>
placeholder="ex. 2pm-ish...after lunch...late evening" {roomType == RoomType.scheduled ? (
className="w-full rounded-lg bg-gray-50 p-3" <>
value={roomAppxDateTime} <span className="text-orange-500 mx-5 font-bold">OR</span>
onChange={(e) => setRoomAppxDateTime(e.target.value)} <span className="flex flex-col items-start flex-1 mt-4">
/> <span className="text-md">Specific Time</span>
</span> {/* <TimePicker
</Tooltip> minuteStep={15}
use12Hours
format="h:mm a"
value={timePicker}
defaultValue={moment(new Date())}
onChange={handleTimePickerChange}
/> */}
<DatePicker
minuteStep={15}
use12Hours
format="YYYY-MM-DD h:mm a"
showTime={{
defaultValue: moment("10:00:00", "h:mm a"),
}}
value={dateTimePicker}
onChange={handleDateTimePickerChange}
/>
</span>
</>
) : (
<></>
)}
</div>
) : ( ) : (
<></> <></>
)} )}
@@ -286,7 +370,7 @@ export default function CreateOrUpdateRoomModal(props: IModalProps) {
<span className="text-gray-300 text-xs mb-2 flex-1"> <span className="text-gray-300 text-xs mb-2 flex-1">
Optional - Add any mandatory attendees you want or just tell Optional - Add any mandatory attendees you want or just tell
them later and they will see it in the team section. them later and they will see it in the team rooms.
</span> </span>
{MemberSelection()} {MemberSelection()}
</span> </span>
+1 -1
View File
@@ -225,7 +225,7 @@ export default function RoomCard(props: IRoomCardProps) {
<span <span
className={`flex flex-col ${ className={`flex flex-col ${
isUserInRoom ? " bg-white bg-opacity-80" : "bg-gray-300 bg-opacity-25" isUserInRoom ? " bg-white bg-opacity-80" : "bg-gray-300 bg-opacity-25"
} rounded-lg justify-between w-96 max-w-screen-sm m-2 overflow-clip h-56`} } rounded-lg justify-between w-96 max-w-screen-sm m-2 shink-0 h-56`}
> >
{/* header */} {/* header */}
<span className="flex flex-row justify-between items-baseline space-x-1 p-5 h-full"> <span className="flex flex-row justify-between items-baseline space-x-1 p-5 h-full">
+38
View File
@@ -0,0 +1,38 @@
import Room, { RoomType } from "../models/room";
import RoomCard from "./RoomCard";
interface IRoomsData {
rooms: Room[];
}
// different rows for the types
export function RoomsRowsByType(props: IRoomsData) {
// got the top level content/rooms
// now let's drill down and filter
const recurringRooms = props.rooms.filter(
(room) => room.type == RoomType.recurring
);
const scheduledRooms = props.rooms.filter(
(room) => room.type == RoomType.scheduled
);
const nowRooms = props.rooms.filter(
(room) => room.type == RoomType.scheduled
);
return;
// return props.rooms.map((room) => {
// // if the room is
// return (
// <RoomCard
// key={room.id}
// room={room}
// updateRoomHandler={handleUpdateRoom}
// />
// );
// })
}
// simple table for the archived rooms
export function ArchivedRoomsTable(props: IRoomsData) {}
+10
View File
@@ -18,8 +18,18 @@ export default class Room {
status: RoomStatus = RoomStatus.empty; status: RoomStatus = RoomStatus.empty;
approximateDateTime: string; // vaguely say when the meeting should be...give user pointers approximateDateTime: string; // vaguely say when the meeting should be...give user pointers
scheduledDateTime: Timestamp;
// scheduledJsDateTime(): Date {
// return this.scheduledDateTime.toDate();
// }
createdDate: Timestamp; createdDate: Timestamp;
// createdJsDate(): Date {
// return this.createdDate.toDate();
// }
createdByUserId: string; createdByUserId: string;
teamId: string; teamId: string;
+1 -1
View File
@@ -89,7 +89,7 @@ function TeamDashboard() {
<TeamVoiceLine /> <TeamVoiceLine />
</div> </div>
<div className="flex flex-col space-y-5 flex-1"> <div className="flex flex-col space-y-5 flex-1 overflow-auto">
<Announcements /> <Announcements />
<Rooms /> <Rooms />