viewing works but playing stuff is buggy
This commit is contained in:
@@ -0,0 +1,108 @@
|
||||
import moment from "moment";
|
||||
import Image from "next/image";
|
||||
import { useState } from "react";
|
||||
import toast from "react-hot-toast";
|
||||
import { FaCheck, FaPlay } from "react-icons/fa";
|
||||
import { useAuth } from "../contexts/authContext";
|
||||
import { useKeyboardContext } from "../contexts/keyboardContext";
|
||||
import { useTeamDashboardContext } from "../contexts/teamDashboardContext";
|
||||
import Announcement, { AnnouncementState } from "../models/announcement";
|
||||
import { User } from "../models/user";
|
||||
import { AnnouncementService } from "../services/announcementService";
|
||||
import SkeletonLoader from "./Loading/skeletonLoader";
|
||||
|
||||
interface IAnnouncementCardProps {
|
||||
announcement: Announcement;
|
||||
}
|
||||
|
||||
const announcementService = new AnnouncementService();
|
||||
|
||||
export default function AnnouncementCard(props: IAnnouncementCardProps) {
|
||||
const { currUser } = useAuth();
|
||||
const { teamUsersMap, user } = useTeamDashboardContext();
|
||||
const { handleAddAudioToQueue } = useKeyboardContext();
|
||||
const [loading, setLoading] = useState<boolean>(false);
|
||||
|
||||
function playAnnouncement() {
|
||||
handleAddAudioToQueue([props.announcement.audioDataUrl]);
|
||||
}
|
||||
|
||||
async function resolveAnnouncement() {
|
||||
setLoading(true);
|
||||
|
||||
try {
|
||||
await announcementService.updateAnnouncementState(
|
||||
props.announcement.id,
|
||||
AnnouncementState.resolved
|
||||
);
|
||||
} catch (error) {
|
||||
toast.error("unable to resolve announcement");
|
||||
}
|
||||
|
||||
setLoading(false);
|
||||
}
|
||||
|
||||
async function deleteAnnouncement() {
|
||||
try {
|
||||
await announcementService.updateAnnouncementState(
|
||||
props.announcement.id,
|
||||
AnnouncementState.deleted
|
||||
);
|
||||
} catch (error) {
|
||||
toast.error("unable to resolve announcement");
|
||||
}
|
||||
}
|
||||
|
||||
var announcementUser: User = null;
|
||||
if (props.announcement.createdByUserId in teamUsersMap) {
|
||||
announcementUser = teamUsersMap[props.announcement.createdByUserId];
|
||||
} else if (currUser.uid == props.announcement.createdByUserId) {
|
||||
announcementUser = user;
|
||||
}
|
||||
|
||||
const relativeCreatedDate = moment(
|
||||
props.announcement.createdDate.toDate()
|
||||
).fromNow();
|
||||
|
||||
if (loading) {
|
||||
return <SkeletonLoader />;
|
||||
}
|
||||
|
||||
return (
|
||||
<span className="flex flex-row p-3 bg-gray-300 bg-opacity-25 rounded-lg items-center">
|
||||
<span className="relative mr-2 grid items-center justify-items-center">
|
||||
<span className="bg-gray-200 bg-opacity-20 rounded-full shadow-md absolute w-full h-full"></span>
|
||||
|
||||
<Image
|
||||
src={"/avatars/svg/Artboards_Diversity_Avatars_by_Netguru-22.svg"}
|
||||
alt="profile"
|
||||
width={50}
|
||||
height={50}
|
||||
/>
|
||||
</span>
|
||||
|
||||
<span className="flex flex-col items-baseline mr-5">
|
||||
<span className="text-md font-bold text-white">
|
||||
{announcementUser?.nickName}
|
||||
</span>
|
||||
<span className="text-xs text-gray-200">{relativeCreatedDate}</span>
|
||||
</span>
|
||||
|
||||
{props.announcement.state == AnnouncementState.active && (
|
||||
<button
|
||||
onClick={resolveAnnouncement}
|
||||
className="bg-gray-300 bg-opacity-25 p-2 ml-2 rounded hover:bg-opacity-40"
|
||||
>
|
||||
<FaCheck className="text-lg text-white" />
|
||||
</button>
|
||||
)}
|
||||
|
||||
<button
|
||||
onClick={playAnnouncement}
|
||||
className="bg-gray-300 bg-opacity-25 p-2 ml-2 rounded hover:bg-opacity-40"
|
||||
>
|
||||
<FaPlay className="text-lg text-white" />
|
||||
</button>
|
||||
</span>
|
||||
);
|
||||
}
|
||||
@@ -2,20 +2,135 @@ import { FaAngleDown, FaCheck, FaMicrophoneAlt, FaPlay } from "react-icons/fa";
|
||||
import { UserStatus } from "../../models/user";
|
||||
|
||||
import Image from "next/image";
|
||||
import { useEffect, useState } from "react";
|
||||
import {
|
||||
collection,
|
||||
getFirestore,
|
||||
onSnapshot,
|
||||
query,
|
||||
where,
|
||||
} from "firebase/firestore";
|
||||
import { Collections } from "../../services/collections";
|
||||
import { useTeamDashboardContext } from "../../contexts/teamDashboardContext";
|
||||
import { useAuth } from "../../contexts/authContext";
|
||||
import Announcement, { AnnouncementState } from "../../models/announcement";
|
||||
import { getTime } from "../../helpers/dateTime";
|
||||
import AnnouncementCard from "../AnnouncementCard";
|
||||
import { Dropdown, Menu, Radio, Tooltip } from "antd";
|
||||
|
||||
// for query
|
||||
const yesterday = new Date();
|
||||
yesterday.setDate(yesterday.getDate() - 1);
|
||||
|
||||
const db = getFirestore();
|
||||
|
||||
export default function Announcements() {
|
||||
const { currUser } = useAuth();
|
||||
const { team } = useTeamDashboardContext();
|
||||
|
||||
const [annMap, setAnnMap] = useState<Map<string, Announcement>>(
|
||||
new Map<string, Announcement>()
|
||||
);
|
||||
|
||||
// SECTION: LISTENER for Announcements
|
||||
useEffect(() => {
|
||||
/**
|
||||
* QUERY:
|
||||
* all announcements for the team in the past 24 hours for now
|
||||
* order createdDate desc
|
||||
*
|
||||
*/
|
||||
const q = query(
|
||||
collection(db, Collections.announcements),
|
||||
where("teamId", "==", team.id),
|
||||
where("createdDate", ">", yesterday)
|
||||
);
|
||||
|
||||
// return unsubscribe
|
||||
return onSnapshot(q, (snapshot) => {
|
||||
snapshot.docChanges().forEach((change) => {
|
||||
let updatedOrNewAnn = change.doc.data() as Announcement;
|
||||
updatedOrNewAnn.id = change.doc.id;
|
||||
|
||||
if (change.type === "added" || change.type === "modified") {
|
||||
console.log("New or updated announcement: ", updatedOrNewAnn);
|
||||
|
||||
// update rooms map
|
||||
setAnnMap((prevMap) => {
|
||||
return new Map(prevMap.set(updatedOrNewAnn.id, updatedOrNewAnn));
|
||||
});
|
||||
}
|
||||
if (change.type === "removed") {
|
||||
// going to more so be resolved or deleted
|
||||
console.log("Removed annoncement: ", updatedOrNewAnn);
|
||||
}
|
||||
});
|
||||
});
|
||||
}, []);
|
||||
|
||||
const allAnn = Array.from(annMap.values());
|
||||
// sort the announcements
|
||||
allAnn.sort(function (a, b) {
|
||||
return getTime(b.createdDate.toDate()) - getTime(a.createdDate.toDate());
|
||||
});
|
||||
|
||||
const activeAnn = allAnn.filter(
|
||||
(ann) => ann.state == AnnouncementState.active
|
||||
);
|
||||
const resolvedAnn = allAnn.filter(
|
||||
(ann) => ann.state == AnnouncementState.resolved
|
||||
);
|
||||
|
||||
const [selectedTabPane, setSelectedTabPane] = useState<string>(
|
||||
AnnouncementState.active
|
||||
);
|
||||
|
||||
function getTabContent() {
|
||||
switch (selectedTabPane) {
|
||||
case AnnouncementState.active:
|
||||
return (
|
||||
<>
|
||||
{activeAnn.map((ann) => {
|
||||
return <AnnouncementCard key={ann.id} announcement={ann} />;
|
||||
})}
|
||||
</>
|
||||
);
|
||||
case AnnouncementState.resolved:
|
||||
return (
|
||||
<>
|
||||
{resolvedAnn.map((ann) => {
|
||||
return <AnnouncementCard key={ann.id} announcement={ann} />;
|
||||
})}
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const TimePeriodFilterMenu = (
|
||||
<Menu>
|
||||
<Menu.Item key={1} disabled>
|
||||
Past Week (Coming Soon)
|
||||
</Menu.Item>
|
||||
<Menu.Item key={2} disabled>
|
||||
This Month (Coming Soon)
|
||||
</Menu.Item>
|
||||
</Menu>
|
||||
);
|
||||
|
||||
return (
|
||||
<section className="p-5 flex flex-col bg-gray-100 bg-opacity-25 rounded-lg shadow-md">
|
||||
<span className="flex flex-row justify-start items-center pb-5">
|
||||
<span className="flex flex-col mr-20">
|
||||
<span className="flex flex-col mr-auto">
|
||||
<span className="text-white mr-auto">
|
||||
ANNOUNCEMENTS
|
||||
<button
|
||||
className="right-1 rounded-lg py-1 px-2 ml-1
|
||||
<Tooltip title={"Press and hold A to send an announcement."}>
|
||||
<button
|
||||
className="right-1 rounded-lg py-1 px-2 ml-1
|
||||
shadow-md text-center text-white text-sm font-bold"
|
||||
>
|
||||
CTRL + A
|
||||
</button>
|
||||
>
|
||||
A
|
||||
</button>
|
||||
</Tooltip>
|
||||
</span>
|
||||
<span className="text-gray-300 text-xs">
|
||||
updates, pep talks, blockers, reminders
|
||||
@@ -23,76 +138,41 @@ export default function Announcements() {
|
||||
</span>
|
||||
|
||||
{/* tab pane */}
|
||||
<span className="ml-auto flex flex-row space-x-5 uppercase mr-5">
|
||||
<span className="underline underline-offset-8 decoration-white text-white hover:text-white hover:cursor-pointer">
|
||||
Active
|
||||
|
||||
<Radio.Group
|
||||
value={selectedTabPane}
|
||||
onChange={(e) => setSelectedTabPane(e.target.value)}
|
||||
>
|
||||
<Radio.Button value={AnnouncementState.active}>
|
||||
{AnnouncementState.active}{" "}
|
||||
<span className="text-xs text-orange-500">
|
||||
{activeAnn.length > 0 ? activeAnn.length : ""}
|
||||
</span>
|
||||
</Radio.Button>
|
||||
<Radio.Button value={AnnouncementState.resolved}>
|
||||
{AnnouncementState.resolved}{" "}
|
||||
<span className="text-xs text-orange-500">
|
||||
{activeAnn.length > 0 ? activeAnn.length : ""}
|
||||
</span>
|
||||
</Radio.Button>
|
||||
</Radio.Group>
|
||||
|
||||
<Dropdown overlay={TimePeriodFilterMenu}>
|
||||
<span className="ml-2 text-sm text-gray-300 flex flex-row items-center uppercase hover:cursor-pointer">
|
||||
24 HRS <FaAngleDown />
|
||||
</span>
|
||||
</Dropdown>
|
||||
|
||||
<span className="text-gray-300 hover:text-white hover:cursor-pointer">
|
||||
Resolved
|
||||
</span>
|
||||
</span>
|
||||
|
||||
<span className="text-sm text-gray-300 flex flex-row items-center">
|
||||
TODAY <FaAngleDown />
|
||||
</span>
|
||||
|
||||
<button className="bg-gray-300 bg-opacity-25 p-2 ml-2 rounded hover:bg-opacity-40">
|
||||
{/* <button className="bg-gray-300 bg-opacity-25 p-2 ml-2 rounded hover:bg-opacity-40">
|
||||
<FaMicrophoneAlt className="text-lg text-white" />
|
||||
</button>
|
||||
<button className="bg-gray-300 bg-opacity-25 p-2 ml-2 rounded hover:bg-opacity-40">
|
||||
<FaPlay className="text-lg text-white" />
|
||||
</button>
|
||||
</button> */}
|
||||
</span>
|
||||
|
||||
<div className="flex flex-row overflow-auto whitespace-nowrap space-x-5 items-center">
|
||||
{/* adriana's announcement */}
|
||||
<span className="flex flex-row p-3 bg-gray-300 bg-opacity-25 rounded-lg items-center">
|
||||
<span className="relative mr-2 grid items-center justify-items-center">
|
||||
<span className="bg-gray-200 bg-opacity-20 rounded-full shadow-md absolute w-full h-full"></span>
|
||||
|
||||
<Image
|
||||
src={"/avatars/svg/Artboards_Diversity_Avatars_by_Netguru-06.svg"}
|
||||
alt="profile"
|
||||
width={50}
|
||||
height={50}
|
||||
/>
|
||||
</span>
|
||||
|
||||
<span className="flex flex-col items-baseline">
|
||||
<span className="text-md font-bold text-white">Adriana</span>
|
||||
<span className="text-xs text-gray-200">5 minutes ago</span>
|
||||
<span className="text-xs text-white bg-red-400 p-1 rounded-md font-semibold flex flex-row items-center">
|
||||
<span>blockers</span>
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
|
||||
{/* arjun's announcement */}
|
||||
<span className="flex flex-row p-3 bg-gray-300 bg-opacity-25 rounded-lg items-center">
|
||||
<span className="relative mr-2 grid items-center justify-items-center">
|
||||
<span className="bg-gray-200 bg-opacity-20 rounded-full shadow-md absolute w-full h-full"></span>
|
||||
|
||||
<Image
|
||||
src={"/avatars/svg/Artboards_Diversity_Avatars_by_Netguru-22.svg"}
|
||||
alt="profile"
|
||||
width={50}
|
||||
height={50}
|
||||
/>
|
||||
</span>
|
||||
|
||||
<span className="flex flex-col items-baseline mr-5">
|
||||
<span className="text-md font-bold text-white">Arjun</span>
|
||||
<span className="text-xs text-gray-200">30 minutes ago</span>
|
||||
<span className="text-xs text-white bg-indigo-400 p-1 rounded-md font-semibold flex flex-row items-center">
|
||||
<span>engineering</span>
|
||||
</span>
|
||||
</span>
|
||||
|
||||
<button className="bg-gray-300 bg-opacity-25 p-2 ml-2 rounded hover:bg-opacity-40">
|
||||
<FaCheck className="text-lg text-white" />
|
||||
</button>
|
||||
</span>
|
||||
{getTabContent()}
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
|
||||
@@ -60,15 +60,11 @@ export default function Links() {
|
||||
updatedOrNewLink.id = change.doc.id;
|
||||
|
||||
if (change.type === "added" || change.type === "modified") {
|
||||
console.log("New or updated link: ", updatedOrNewLink);
|
||||
|
||||
// update rooms map
|
||||
setLinksMap((prevMap) => {
|
||||
return new Map(prevMap.set(updatedOrNewLink.id, updatedOrNewLink));
|
||||
});
|
||||
}
|
||||
if (change.type === "removed") {
|
||||
// not really going to happen, more so will be archived
|
||||
console.log("Removed link: ", updatedOrNewLink);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -538,7 +538,6 @@ export default function KeyboardContextProvider({ children }) {
|
||||
}
|
||||
|
||||
async function sendAnnouncement() {
|
||||
toast.success("announcement sent to team");
|
||||
setIsRecordingAnnouncement(false);
|
||||
|
||||
try {
|
||||
|
||||
Reference in New Issue
Block a user