getting data and starting to filter and improve flow
This commit is contained in:
@@ -98,8 +98,8 @@ export default function Links() {
|
||||
return false;
|
||||
}
|
||||
|
||||
// if I am the sender, then also show
|
||||
if (link.createdByUserId == currUser.uid) {
|
||||
// if I am the sender, then also show, but only if it's me sending to a specific person
|
||||
if (link.createdByUserId == currUser.uid && link.recipients?.length > 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -222,7 +222,7 @@ export default function Links() {
|
||||
</Tooltip>
|
||||
|
||||
{/* 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) => (
|
||||
<LinkCard key={link.id} link={link} />
|
||||
))}
|
||||
|
||||
+165
-37
@@ -42,6 +42,8 @@ const db = getFirestore();
|
||||
|
||||
const lastWeek = new Date();
|
||||
lastWeek.setDate(lastWeek.getDate() - 7);
|
||||
const nextWeek = new Date();
|
||||
nextWeek.setDate(nextWeek.getDate() + 7);
|
||||
|
||||
export default function DashboardRoom() {
|
||||
const { currUser } = useAuth();
|
||||
@@ -52,41 +54,84 @@ export default function DashboardRoom() {
|
||||
new Map<string, Room>()
|
||||
);
|
||||
|
||||
// get rooms data realtime
|
||||
// get recurring rooms data realtime: ALL of them
|
||||
useEffect(() => {
|
||||
/**
|
||||
* QUERY:
|
||||
* all rooms in the past week
|
||||
* order createdDate desc
|
||||
* all recurring rooms, as the created date can be a year ago
|
||||
*
|
||||
*/
|
||||
const q = query(
|
||||
collection(db, Collections.rooms),
|
||||
where("teamId", "==", team.id),
|
||||
where("createdDate", ">", lastWeek),
|
||||
orderBy("createdDate", "desc")
|
||||
where("type", "==", RoomType.recurring)
|
||||
);
|
||||
|
||||
// return unsubscribe
|
||||
return onSnapshot(q, (snapshot) => {
|
||||
snapshot.docChanges().forEach((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);
|
||||
}
|
||||
});
|
||||
snapshot.docChanges().forEach(handleDocChange);
|
||||
});
|
||||
}, []);
|
||||
|
||||
// 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 + V, show modal to create meeting with the link
|
||||
|
||||
@@ -94,7 +139,9 @@ export default function DashboardRoom() {
|
||||
RoomTypeFilter.me
|
||||
);
|
||||
|
||||
// sort this mega array
|
||||
const allRooms = Array.from(roomsMap.values());
|
||||
|
||||
const teamRooms = allRooms.filter(
|
||||
(room) => room.status != RoomStatus.archived
|
||||
);
|
||||
@@ -112,15 +159,106 @@ export default function DashboardRoom() {
|
||||
// return data based on the selected filters
|
||||
switch (selectedTabPane) {
|
||||
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:
|
||||
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:
|
||||
return liveRooms;
|
||||
return liveRooms.map((room) => {
|
||||
// if the room is
|
||||
return (
|
||||
<RoomCard
|
||||
key={room.id}
|
||||
room={room}
|
||||
updateRoomHandler={handleUpdateRoom}
|
||||
/>
|
||||
);
|
||||
});
|
||||
case RoomTypeFilter.archived:
|
||||
return archivedRooms;
|
||||
return archivedRooms.map((room) => {
|
||||
// if the room is
|
||||
return (
|
||||
<RoomCard
|
||||
key={room.id}
|
||||
room={room}
|
||||
updateRoomHandler={handleUpdateRoom}
|
||||
/>
|
||||
);
|
||||
});
|
||||
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 (
|
||||
<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 */}
|
||||
<CreateOrUpdateRoom
|
||||
show={showModalType == ShowModalType.createRoom}
|
||||
@@ -240,17 +378,7 @@ export default function DashboardRoom() {
|
||||
</Tooltip>
|
||||
|
||||
{/* all rooms */}
|
||||
<span className="flex flex-row flex-wrap overflow-auto h-[32rem]">
|
||||
{getRoomContent().map((room) => {
|
||||
return (
|
||||
<RoomCard
|
||||
key={room.id}
|
||||
room={room}
|
||||
updateRoomHandler={handleUpdateRoom}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</span>
|
||||
<span className="h-[32rem] overflow-auto">{getRoomContent()}</span>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -208,7 +208,7 @@ export default function TeamVoiceLine() {
|
||||
}
|
||||
|
||||
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-col">
|
||||
<span className="text-white">TEAM</span>
|
||||
|
||||
@@ -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 toast from "react-hot-toast";
|
||||
import { useAuth } from "../../contexts/authContext";
|
||||
@@ -41,6 +52,13 @@ export default function CreateOrUpdateRoomModal(props: IModalProps) {
|
||||
setMembersSelected(props.updateRoom.members);
|
||||
setRoomType(props.updateRoom.type);
|
||||
setRoomAppxDateTime(props.updateRoom.approximateDateTime);
|
||||
|
||||
if (props.updateRoom.scheduledDateTime) {
|
||||
const convertedToMoment = moment(
|
||||
props.updateRoom.scheduledDateTime.toDate()
|
||||
);
|
||||
setDateTimePicker(convertedToMoment);
|
||||
}
|
||||
} else {
|
||||
// update state when user does ctrl + v
|
||||
resetForm();
|
||||
@@ -77,10 +95,32 @@ export default function CreateOrUpdateRoomModal(props: IModalProps) {
|
||||
}
|
||||
|
||||
if (roomType == RoomType.now) {
|
||||
// make sure approximate time isn't selected
|
||||
newRoom.approximateDateTime = null;
|
||||
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.members = [...membersSelected]; // add currUser to the list of "people"
|
||||
newRoom.type = roomType;
|
||||
@@ -94,13 +134,15 @@ export default function CreateOrUpdateRoomModal(props: IModalProps) {
|
||||
newRoom.membersInRoom = props.updateRoom.membersInRoom;
|
||||
}
|
||||
|
||||
console.log(newRoom);
|
||||
|
||||
handleModalType(ShowModalType.na);
|
||||
|
||||
await roomService.createOrUpdateRoom(newRoom);
|
||||
|
||||
resetForm();
|
||||
|
||||
toast.success("done");
|
||||
|
||||
handleModalType(ShowModalType.na);
|
||||
} catch (error) {
|
||||
toast.error("problem creating room");
|
||||
console.log(error);
|
||||
@@ -116,6 +158,8 @@ export default function CreateOrUpdateRoomModal(props: IModalProps) {
|
||||
setRoomAppxDateTime("");
|
||||
setRoomType(RoomType.now);
|
||||
|
||||
setDateTimePicker(null);
|
||||
|
||||
setShowMoreDetails(false);
|
||||
}
|
||||
|
||||
@@ -130,6 +174,7 @@ export default function CreateOrUpdateRoomModal(props: IModalProps) {
|
||||
|
||||
const [roomType, setRoomType] = useState<RoomType>(RoomType.now);
|
||||
const [roomAppxDateTime, setRoomAppxDateTime] = useState<string>(""); // for certain room types
|
||||
const [dateTimePicker, setDateTimePicker] = useState(null);
|
||||
|
||||
const [showMoreDetails, setShowMoreDetails] = useState<boolean>(false);
|
||||
|
||||
@@ -141,6 +186,14 @@ export default function CreateOrUpdateRoomModal(props: IModalProps) {
|
||||
console.log(value);
|
||||
}
|
||||
|
||||
function handleDateTimePickerChange(time) {
|
||||
console.log(time);
|
||||
|
||||
setRoomAppxDateTime("");
|
||||
|
||||
setDateTimePicker(time);
|
||||
}
|
||||
|
||||
const allUsersForSelection: User[] = [...teamUsers, user];
|
||||
|
||||
const MemberSelection = () => {
|
||||
@@ -235,23 +288,54 @@ export default function CreateOrUpdateRoomModal(props: IModalProps) {
|
||||
</Radio.Group>
|
||||
|
||||
{roomType == RoomType.recurring || roomType == RoomType.scheduled ? (
|
||||
<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="text-gray-300 text-xs mb-2 flex-1">
|
||||
The calendar way of doing things is overwhelming. Put a rough
|
||||
day/time that makes sense to you.
|
||||
<div className="flex flex-row items-center">
|
||||
<Tooltip
|
||||
title={`Put things like "ping me when ready" or "sometime this afternoon"`}
|
||||
>
|
||||
<span className="flex flex-col items-stretch flex-1 mt-4">
|
||||
<span className="text-md">Approximate Slot</span>
|
||||
<span className="text-gray-300 text-xs mb-2 flex-1">
|
||||
Sometimes you don'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>
|
||||
<input
|
||||
placeholder="ex. 2pm-ish...after lunch...late evening"
|
||||
className="w-full rounded-lg bg-gray-50 p-3"
|
||||
value={roomAppxDateTime}
|
||||
onChange={(e) => setRoomAppxDateTime(e.target.value)}
|
||||
/>
|
||||
</span>
|
||||
</Tooltip>
|
||||
</Tooltip>
|
||||
{roomType == RoomType.scheduled ? (
|
||||
<>
|
||||
<span className="text-orange-500 mx-5 font-bold">OR</span>
|
||||
<span className="flex flex-col items-start flex-1 mt-4">
|
||||
<span className="text-md">Specific Time</span>
|
||||
{/* <TimePicker
|
||||
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">
|
||||
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>
|
||||
{MemberSelection()}
|
||||
</span>
|
||||
|
||||
@@ -225,7 +225,7 @@ export default function RoomCard(props: IRoomCardProps) {
|
||||
<span
|
||||
className={`flex flex-col ${
|
||||
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 */}
|
||||
<span className="flex flex-row justify-between items-baseline space-x-1 p-5 h-full">
|
||||
|
||||
@@ -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) {}
|
||||
@@ -18,8 +18,18 @@ export default class Room {
|
||||
status: RoomStatus = RoomStatus.empty;
|
||||
|
||||
approximateDateTime: string; // vaguely say when the meeting should be...give user pointers
|
||||
scheduledDateTime: Timestamp;
|
||||
|
||||
// scheduledJsDateTime(): Date {
|
||||
// return this.scheduledDateTime.toDate();
|
||||
// }
|
||||
|
||||
createdDate: Timestamp;
|
||||
|
||||
// createdJsDate(): Date {
|
||||
// return this.createdDate.toDate();
|
||||
// }
|
||||
|
||||
createdByUserId: string;
|
||||
|
||||
teamId: string;
|
||||
|
||||
@@ -89,7 +89,7 @@ function TeamDashboard() {
|
||||
<TeamVoiceLine />
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col space-y-5 flex-1">
|
||||
<div className="flex flex-col space-y-5 flex-1 overflow-auto">
|
||||
<Announcements />
|
||||
|
||||
<Rooms />
|
||||
|
||||
Reference in New Issue
Block a user