Files
nirvana/packages/web/components/Dashboard/Header.tsx
T
2022-01-28 14:08:04 -08:00

352 lines
9.6 KiB
TypeScript

import { useAuth } from "../../contexts/authContext";
import Image from "next/image";
import {
FaMicrophoneAlt,
FaHeadphonesAlt,
FaTh,
FaBell,
FaSearch,
FaBuilding,
FaCalendarDay,
FaClock,
FaPeopleCarry,
FaAngleDown,
FaCheck,
FaDatabase,
FaMicrophoneAltSlash,
FaVolumeMute,
FaLayerGroup,
FaUser,
} from "react-icons/fa";
import { useTeamDashboardContext } from "../../contexts/teamDashboardContext";
import router from "next/router";
import Moment from "react-moment";
import { User } from "../../models/user";
import { generateGreetings } from "../../helpers/dateTime";
import { Dropdown, Menu, Tooltip } from "antd";
import { useRouter } from "next/router";
import { TeamMemberRole, TeamMemberStatus } from "../../models/teamMember";
import { toast } from "react-hot-toast";
import SubMenu from "antd/lib/menu/SubMenu";
import { useEffect, useState } from "react";
import TeamService from "../../services/teamService";
import { Team } from "../../models/team";
import Loading from "../Loading";
import { useKeyboardContext } from "../../contexts/keyboardContext";
import UserStatusBubble from "../UserStatusBubble";
const teamService = new TeamService();
const today = new Date();
export default function Header() {
const { currUser, logOut } = useAuth();
const { team, user, userTeamMember } = useTeamDashboardContext();
const router = useRouter();
const { teamid } = router.query;
const {
hasRecPermit,
audioInputDeviceId,
audioOutputDeviceId,
selectAudioOutput,
selectAudioInput,
inputDevices,
outputDevices,
isMuted,
isSilenceMode,
muteOrUnmute,
silenceOrLivenMode,
} = useKeyboardContext();
const [usersTeams, setUserTeams] = useState<Team[]>(null);
// get team data for the team dropdown
useEffect(() => {
(async function () {
try {
// get all the teams that this user is part of
const newTeams: Team[] =
await teamService.getActiveOrInvitedTeamsbyUser(
currUser.uid,
currUser.email
);
setUserTeams(newTeams);
} catch (error) {
console.log("problem getting teams of this user");
toast.error("problem on load");
}
})();
}, []);
async function handleSignOut() {
console.log("clicked log out button");
try {
await logOut();
} catch (error) {
console.log(error);
toast.error("Unable to log out!");
}
}
async function handleAdminRoute() {
if (userTeamMember.role == TeamMemberRole.admin) {
router.push("/teams/" + teamid + "/admin");
return;
}
toast.error("You are not a team admin!");
}
const searchBar = (
<div className="pt-2 flex flex-row relative items-center">
<button type="submit" className="absolute left-0 top-0 mt-5 ml-5">
<FaSearch className="text-white" />
</button>
<input
className=" bg-white bg-opacity-40 h-10 px-5 pl-10 pr-16 rounded-lg text-white text-sm focus:outline-none"
type="search"
name="search"
placeholder="Search"
/>
<button
className="absolute right-1 rounded-lg py-1 px-2 ml-1
shadow-md text-center text-white text-sm font-bold"
>
CTRL + K
</button>
</div>
);
const TeamsMenu = (
<Menu key={2} title="teams">
<Menu.Item
onClick={() => window.open("/teams", "_self")}
key={"team hub"}
icon={<FaLayerGroup />}
>
<button>Team Hub</button>
</Menu.Item>
<Menu.Item onClick={handleAdminRoute} key={"admin"} icon={<FaDatabase />}>
<button>Admin</button>
</Menu.Item>
<Menu.Divider />
{/* all current teams that this person is a part of */}
{usersTeams &&
usersTeams.map((uteam, i) => {
return (
<Menu.Item
key={i + 5}
icon={team.id == uteam.id ? <FaCheck /> : <></>}
onClick={() => {
console.log("going to " + uteam.id);
window.location.href = "/teams/" + uteam.id;
}}
>
<button>{uteam.name}</button>
</Menu.Item>
);
})}
</Menu>
);
const UserMenu = (
<Menu title="user menu">
<Menu.Item
key={2}
onClick={() => router.push("/teams/profile")}
icon={<FaUser />}
>
<button>Profile</button>
</Menu.Item>
<Menu.Item
onClick={() => window.open("/teams", "_self")}
key={"team hub"}
icon={<FaLayerGroup />}
>
<button>Team Hub</button>
</Menu.Item>
<Menu.Divider />
<Menu.Item danger key={3} onClick={handleSignOut}>
<button>Sign Out</button>
</Menu.Item>
</Menu>
);
const handleSilenceOrLivenMode = (event) => {
event.preventDefault();
silenceOrLivenMode();
};
const handleMuteUnmute = (event) => {
event.preventDefault();
muteOrUnmute();
};
const audioInputDropMenu = (
<Menu title="audio input">
<Menu.Item danger key={"muting input"} onClick={handleMuteUnmute}>
<button>{isMuted ? "Unmute" : "Mute"}</button>
</Menu.Item>
<Menu.Divider />
{/* device */}
{inputDevices.map((device, i) => {
return (
<Menu.Item
key={device.deviceId}
icon={device.deviceId == audioInputDeviceId ? <FaCheck /> : <></>}
onClick={() => selectAudioInput(device.deviceId)}
>
<button>{device.label}</button>
</Menu.Item>
);
})}
</Menu>
);
const audioOutputDropMenu = (
<Menu title="audio ouput">
<Menu.Item
danger
key={"silence output"}
onClick={handleSilenceOrLivenMode}
>
<button>{isSilenceMode ? "Unsilence" : "Silence"}</button>
</Menu.Item>
<Menu.Divider />
{/* devices */}
{outputDevices.map((device, i) => {
return (
<Menu.Item
key={device.deviceId}
icon={device.deviceId == audioOutputDeviceId ? <FaCheck /> : <></>}
onClick={() => selectAudioOutput(device.deviceId)}
>
<button>{device.label}</button>
</Menu.Item>
);
})}
</Menu>
);
function renderAudioInput() {
if (!hasRecPermit) {
return (
<Tooltip title="enable mic permissions">
<span>
<FaMicrophoneAltSlash className="text-xl text-orange-400 ease-in-out duration-300 hover:scale-110 hover:cursor-pointer" />
</span>
</Tooltip>
);
}
if (isMuted) {
return (
<span onClick={handleMuteUnmute}>
<FaMicrophoneAltSlash className="text-xl text-orange-400 ease-in-out duration-300 hover:scale-110 hover:cursor-pointer" />
</span>
);
}
return (
<Dropdown overlay={audioInputDropMenu}>
<span onClick={handleMuteUnmute}>
<FaMicrophoneAlt className="text-xl text-gray-200 hover:text-white ease-in-out duration-300 hover:scale-110 hover:cursor-pointer" />
</span>
</Dropdown>
);
}
function renderAudioOutput() {
if (isSilenceMode) {
return (
<span onClick={handleSilenceOrLivenMode}>
<FaVolumeMute className="text-xl text-orange-400 ease-in-out duration-300 hover:scale-110 hover:cursor-pointer" />
</span>
);
}
return (
<Dropdown overlay={audioOutputDropMenu}>
<span onClick={handleSilenceOrLivenMode}>
<FaHeadphonesAlt className="text-xl text-gray-200 hover:text-white ease-in-out duration-300 hover:scale-110 hover:cursor-pointer" />
</span>
</Dropdown>
);
}
const periodOfDay = generateGreetings();
return (
<section className="flex-1 flex flex-row items-center justify-between py-5">
{/* welcome message */}
<span className="flex flex-col items-baseline">
<span className="font-bold text-xl text-white capitalize ">
👋Hey {user.firstName}, {periodOfDay}!
</span>
{/* Date and time */}
<span className="flex flex-row space-x-2">
<span className="text-sky-700 bg-sky-200 p-1 rounded-md text-xs font-bold mt-2 flex flex-row items-center space-x-1">
<FaCalendarDay />
<Moment date={today} format="ddd, MMM DD" />
</span>
<span className="text-emerald-700 bg-emerald-200 p-1 rounded-md text-xs font-bold mt-2 flex flex-row items-center space-x-1">
<FaClock />
<Moment format="h:mm a" />
</span>
</span>
</span>
{/* header control section */}
<span className="flex-row items-center space-x-5 hidden md:flex ml-auto">
{/* search bar */}
<FaBell className=" shrink-0 text-lg text-gray-200 hover:text-white ease-in-out duration-300 hover:scale-110 hover:cursor-pointer" />
{renderAudioOutput()}
{renderAudioInput()}
{/* teams menu */}
<Dropdown overlay={TeamsMenu} trigger={["click"]}>
<button
className="text-gray-200 flex flex-row items-center"
onClick={(e) => e.preventDefault()}
>
{team.name} <FaAngleDown />
</button>
</Dropdown>
</span>
{/* avatar */}
<Dropdown
overlay={UserMenu}
trigger={["click"]}
className="ml-2 shrink-0"
>
<span className="relative flex hover:cursor-pointer">
<span className="bg-gray-200 bg-opacity-30 rounded-full shadow-md absolute w-full h-full"></span>
<UserStatusBubble status={user.userStatus} />
<img src={user.avatarUrl} alt="asdf" className="rounded-full w-12" />
</span>
</Dropdown>
</section>
);
}