Skip to content

Commit

Permalink
Merge pull request #13 from IndieCoderMM/channel-management
Browse files Browse the repository at this point in the history
Channel management
  • Loading branch information
IndieCoderMM authored Oct 26, 2023
2 parents daab514 + 1ac45f2 commit ca333d3
Show file tree
Hide file tree
Showing 33 changed files with 716 additions and 389 deletions.
36 changes: 35 additions & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 4 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,21 @@
"preview": "vite preview"
},
"dependencies": {
"@hookform/resolvers": "^3.3.2",
"@reduxjs/toolkit": "^1.9.5",
"clsx": "^2.0.0",
"dayjs": "^1.11.10",
"firebase": "^10.3.1",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-firebase-hooks": "^5.1.1",
"react-hook-form": "^7.47.0",
"react-hot-toast": "^2.4.1",
"react-icons": "^4.11.0",
"react-redux": "^8.1.2",
"react-router-dom": "^6.15.0",
"uuid": "^9.0.0"
"uuid": "^9.0.0",
"zod": "^3.22.4"
},
"devDependencies": {
"@types/react": "^18.2.15",
Expand Down
34 changes: 24 additions & 10 deletions src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,25 @@
import { useEffect } from 'react';
import { Toaster } from 'react-hot-toast';
import { Navigate, Route, Routes, useNavigate } from 'react-router-dom';
import { useEffect } from "react";
import { Toaster } from "react-hot-toast";
import { Navigate, Route, Routes, useNavigate } from "react-router-dom";

import ChatWindow from './features/Chat/ChatWindow';
import { clearUser, selectAuthStatus, setUser } from './features/User/userSlice';
import useAuthUser from './hooks/useAuthUser';
import { AuthStatus } from './lib/constants';
import { useAppDispatch, useAppSelector } from './lib/store';
import { Channels, Chat, Explore, LandingPage, Profile, Settings } from './pages';
import RootLayout from './RootLayout';
import ChatWindow from "./features/Chat/ChatWindow";
import {
clearUser,
selectAuthStatus,
setUser,
} from "./features/User/userSlice";
import useAuthUser from "./hooks/useAuthUser";
import { AuthStatus } from "./lib/constants";
import { useAppDispatch, useAppSelector } from "./lib/store";
import {
Channels,
Chat,
Explore,
LandingPage,
Profile,
Settings,
} from "./pages";
import RootLayout from "./RootLayout";

const GENERAL_CHANNEL_ID = import.meta.env.VITE_GENERAL_CHANNEL_ID || "general";

Expand All @@ -19,10 +30,13 @@ const App = () => {
const navigate = useNavigate();

useEffect(() => {
if (user && authStatus === AuthStatus.SignedIn) return;
if (user && data && authStatus !== AuthStatus.SignedIn) {
// * once user is authenticated and data fetched, set the user in the store
dispatch(setUser(data));
navigate("/", { replace: true });
} else if (!user && !loading) {
// * clear user from the store if logout
dispatch(clearUser());
navigate("/landing", { replace: true });
}
Expand Down
2 changes: 1 addition & 1 deletion src/RootLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ const RootLayout = () => {

const channels = channelDocs.map(mapDocToChannel);
dispatch(setChannels(channels));
// console.log("Read channels from firestore");
console.log("Read channels from firestore");
}, [authStatus, channelDocs, dispatch]);

if (loading || authStatus === AuthStatus.Idle || showLoading) {
Expand Down
5 changes: 2 additions & 3 deletions src/assets/img/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import HeaderImg from "./header_illustration.svg";
import CardBanner from "./card_banner.png";
import ShapesBanner from "./shapes_banner.png";
import Logo from "./logo.png";

export { HeaderImg, CardBanner, ShapesBanner };
export { HeaderImg, Logo };
Binary file added src/assets/img/logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed src/assets/img/shapes.png
Binary file not shown.
Binary file removed src/assets/img/shapes_banner.png
Binary file not shown.
6 changes: 3 additions & 3 deletions src/components/CustomSelect.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@ type Props = {
id: string;
options: { value: string; label: string }[];
value: string;
setValue: (value: string) => void;
onChange: (value: string) => void;
};

const CustomSelect = ({ label, id, options, value, setValue }: Props) => {
const CustomSelect = ({ label, id, options, value, onChange }: Props) => {
const [active, setActive] = useState(false);

const handleSelect = (value: string) => {
setValue(value);
onChange(value);
setActive(false);
};

Expand Down
37 changes: 37 additions & 0 deletions src/components/Modal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { FaTimes } from "react-icons/fa";

type ModalProps = {
title: string;
show: boolean;
handleClose: () => void;
children: React.ReactNode;
};

const Modal = ({ title, show, handleClose, children }: ModalProps) => {
if (!show) return null;

return (
<div
className="fixed bottom-0 left-0 right-0 top-0 bg-black/60 backdrop-blur-md"
aria-modal
aria-hidden={show}
>
<div className="relative left-1/2 top-1/2 w-full max-w-lg -translate-x-1/2 -translate-y-1/2 overflow-hidden rounded-md bg-dark-700 text-white">
<header className="my-4 p-4">
<h1 className="text-xl font-bold capitalize">{title}</h1>
<button
type="button"
className="absolute right-4 top-4"
onClick={handleClose}
aria-label="Close Modal"
>
<FaTimes className="h-6 w-6" />
</button>
</header>
{children}
</div>
</div>
);
};

export default Modal;
38 changes: 23 additions & 15 deletions src/components/Sidebar.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
import { signOut } from 'firebase/auth';
import toast from 'react-hot-toast';
import { BiLogOutCircle } from 'react-icons/bi';
import { Link, useLocation } from 'react-router-dom';
import { signOut } from "firebase/auth";
import toast from "react-hot-toast";
import { BiLogOutCircle } from "react-icons/bi";
import { Link, useLocation } from "react-router-dom";

import { selectAuthStatus } from '../features/User/userSlice';
import { AuthStatus, NavLinks } from '../lib/constants';
import { auth } from '../lib/firebase';
import { useAppSelector } from '../lib/store';
import { cn } from '../lib/tailwind-utils';
import Tooltip from './Tooltip';
import UserButton from './UserButton';
import { selectAuthStatus } from "../features/User/userSlice";
import { AuthStatus, NavLinks } from "../lib/constants";
import { auth } from "../lib/firebase";
import { useAppSelector } from "../lib/store";
import { cn } from "../lib/tailwind-utils";
import Tooltip from "./Tooltip";
import UserButton from "./UserButton";
import { Logo } from "../assets/img";

const Sidebar = () => {
const { pathname } = useLocation();
Expand All @@ -25,7 +26,17 @@ const Sidebar = () => {
toast.success("You have been signed out");
};
return (
<aside className="w-18 fixed bottom-0 left-0 top-0 z-50 flex flex-shrink-0 flex-col items-center justify-between bg-dark-900">
<aside className="fixed bottom-0 left-0 top-0 z-50 flex w-16 flex-shrink-0 flex-col items-center justify-between bg-dark-900">
<Link
to="/landing"
className="group flex w-full items-center justify-center p-1"
>
<img
src={Logo}
alt="Logo"
className="h-12 w-12 rounded-md bg-primary transition group-hover:scale-105"
/>
</Link>
<div className="flex h-screen flex-col items-center py-8 text-white">
<ul className="flex h-full w-full flex-col items-center justify-center gap-3">
{NavLinks.map(({ href, label, icon: Icon }) => (
Expand All @@ -49,9 +60,6 @@ const Sidebar = () => {
variant="light"
size="lg"
/>
{/* <span className="absolute left-full top-1/2 ml-3 -translate-y-1/2 scale-0 rounded-md bg-white px-2 py-1 font-medium text-dark-900 transition-all group-hover:scale-100">
{label}
</span> */}
<Icon size={30} />
</Link>
</li>
Expand Down
10 changes: 5 additions & 5 deletions src/components/UserButton.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { Link } from 'react-router-dom';
import { Link } from "react-router-dom";

import { selectUser } from '../features/User/userSlice';
import { avatars } from '../lib/constants';
import { useAppSelector } from '../lib/store';
import { selectUser } from "../features/User/userSlice";
import { avatars } from "../lib/constants";
import { useAppSelector } from "../lib/store";

const UserButton = () => {
const currentUser = useAppSelector(selectUser);
Expand All @@ -12,7 +12,7 @@ const UserButton = () => {
<img
src={avatars[currentUser!.avatarId]}
alt={currentUser!.name}
className="h-9 w-9 rounded-full"
className="h-10 w-10 rounded-full"
/>
<span className="sr-only">{currentUser!.name}</span>
</Link>
Expand Down
19 changes: 7 additions & 12 deletions src/features/Channels/ChannelCard.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
import { deleteDoc, doc, updateDoc } from "firebase/firestore";
import toast from "react-hot-toast";
import { HiUsers } from "react-icons/hi2";
import { useNavigate } from "react-router-dom";

import { CheckBadge } from "../../assets/icons";
import Tooltip from "../../components/Tooltip";
import { channelsRef } from "../../lib/firebase";
import { useAppSelector } from "../../lib/store";
import { selectUser } from "../User/userSlice";

import type { ChannelInterface } from "../../common.types";
import type { Channel } from "../../schema";
import { deleteChannel, joinChannel } from "./utils";

const ChannelCard = (props: ChannelInterface) => {
const ChannelCard = (props: Channel) => {
const currentUser = useAppSelector(selectUser);
const { id, name, description, type, members } = props;
const navigate = useNavigate();
Expand All @@ -22,13 +21,10 @@ const ChannelCard = (props: ChannelInterface) => {
const handleJoin = async () => {
if (!currentUser || isMember) return;

const channelRef = doc(channelsRef, id);
try {
await updateDoc(channelRef, {
members: [...members, currentUser.id],
});
await joinChannel(props, currentUser.id);
toast.success(`Welcome to #${name}`, { icon: "👋" });
navigate(`/chat/channels/${id}`);
toast.success("Joined channel successfully");
} catch (err) {
console.error(err);
toast.error("Failed to join channel");
Expand All @@ -38,10 +34,9 @@ const ChannelCard = (props: ChannelInterface) => {
const handleDelete = async () => {
if (!currentUser || !isCreator) return;

const channelRef = doc(channelsRef, id);
try {
await deleteDoc(channelRef);
toast.success("Deleted channel successfully");
await deleteChannel(id);
toast.success(`Deleted #${name}`, { icon: "🗑️" });
} catch (err) {
console.error(err);
toast.error("Failed to delete channel");
Expand Down
Loading

0 comments on commit ca333d3

Please sign in to comment.