diff --git a/app/Dashboard/Chat/type.tsx b/app/Dashboard/Chat/type.tsx
index 6231969..93f6810 100644
--- a/app/Dashboard/Chat/type.tsx
+++ b/app/Dashboard/Chat/type.tsx
@@ -1,18 +1,45 @@
+export type banned = {
+ id: number;
+ user_id: number;
+ channel_id: number;
+ joinedAt: Date;
+}
+
export type message = {
id?: number;
- message: string;
- sender: string;
- time: Date;
+ channel_id?: number;
+ sender_id?: number;
+ sender_picture?: string;
+ conversation_id?: number;
+ content: string;
+ content_type: string;
+ createdAt: Date;
+};
+export type participants = {
+ id: number;
+ user_id: number;
+ channel_id: number;
+ role: string;
+ mute: boolean;
};
export type channel = {
+ key: string;
+ state: string;
id?: number;
+ topic: string;
name: string;
+ picture: string;
messages: message[];
+ participants: participants[];
+ ban: banned[];
+ createdAt: Date;
};
export type conversation = {
id?: number;
+ user_a_id: number;
+ user_b_id: number;
messages: message[];
};
@@ -26,7 +53,7 @@ export type user = {
id: number;
googleId: string;
fortytwoId: number;
- username: string;
+ nickname: string;
name: string;
password: string;
picture: string;
@@ -36,4 +63,5 @@ export type user = {
createdAt: Date;
twoFa: boolean;
twoFaSecret: string;
+ conversations: conversation;
};
diff --git a/app/Dashboard/Profile/page.tsx b/app/Dashboard/Profile/page.tsx
index 279b166..687a910 100644
--- a/app/Dashboard/Profile/page.tsx
+++ b/app/Dashboard/Profile/page.tsx
@@ -4,15 +4,20 @@ import { useSearchParams } from 'next/navigation'
import UserProfile from '@/app/components/Dashboard/Profile/UserProfile';
import axios from 'axios';
import { useGlobalState } from '@/app/components/Sign/GlobalState';
+import { useRouter } from 'next/navigation';
const Profile = () => {
const searchParams = useSearchParams()
const [targetUser, setTargetUser] = useState(null)
const [is , setIs] = useState(false)
const {state} = useGlobalState();
- const socket : any= state.socket;
+ const router = useRouter();
+ const {socket , user}= state;
const id = searchParams.get('id')
+
+ if (user && id == user?.id)
+ router.push('/Dashboard')
useEffect(() => {
socket?.on('ok', () => { setIs((prev) => !prev); })
@@ -27,13 +32,22 @@ const Profile = () => {
} , [id, is])
return (
-
+ <>
+ {
+ (user && id != user?.id ) ?
+
+ :
+
+ }
+ >
);
};
diff --git a/app/Dashboard/layout.tsx b/app/Dashboard/layout.tsx
index 7c397e6..10ba603 100644
--- a/app/Dashboard/layout.tsx
+++ b/app/Dashboard/layout.tsx
@@ -1,9 +1,19 @@
import type { Metadata } from "next";
import { Inter } from "next/font/google";
import ContentWrapper from "./ContentWrapper";
+import { Toaster } from "react-hot-toast";
+import {
+ useQuery,
+ useMutation,
+ useQueryClient,
+ QueryClient,
+ QueryClientProvider,
+} from "react-query";
const inter = Inter({ subsets: ["latin"] });
+// const queryClient = new QueryClient();
+
export const metadata: Metadata = {
title: "Create Next App",
description: "Generated by create next app",
@@ -15,12 +25,15 @@ export default function RootLayout({
children: React.ReactNode;
}) {
return (
-
);
}
diff --git a/app/components/Dashboard/Chat/ChatCard.tsx b/app/components/Dashboard/Chat/ChatCard.tsx
index db83f15..7c87544 100644
--- a/app/components/Dashboard/Chat/ChatCard.tsx
+++ b/app/components/Dashboard/Chat/ChatCard.tsx
@@ -2,8 +2,9 @@ import React from "react";
import { motion } from "framer-motion";
import { useEffect, useState } from "react";
import axios from "axios";
-import { message } from "@/app/Dashboard/Chat/page";
+import { message } from "@/app/Dashboard/Chat/type";
import { getTime } from "@/app/utils";
+import toast from "react-hot-toast";
export const ChatCard = (props: any) => {
const [msg, setMessage] = useState
();
@@ -15,7 +16,8 @@ export const ChatCard = (props: any) => {
)
.then((res) => {
setMessage(res.data.messages);
- });
+ })
+ .catch((err) => {});
} else {
axios
.get(
@@ -23,14 +25,20 @@ export const ChatCard = (props: any) => {
)
.then((res) => {
setMessage(res.data);
- });
+ })
+ .catch((err) => {});
}
}, [props.value.id, props.self.id, props.value.user, props.update]);
+ if (!msg) {
+ return Loading...
;
+ }
+
return (
{
+ e.preventDefault();
if (props.value.user === false) {
props.setTargetChannel(props.value);
props.setTargetUser(null);
@@ -40,24 +48,19 @@ export const ChatCard = (props: any) => {
}
props.setUpdate(true);
props.handleClick();
- e.preventDefault();
}}
initial={{ opacity: 0, y: -20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ delay: 0.25 * props.index }}
>
-
+
- {/*here we check the status of the user if he is online or not */}
{props.value.user &&
(props.value.status === "ONLINE" ? (
@@ -71,8 +74,14 @@ export const ChatCard = (props: any) => {
-
- {msg && msg.length > 0 && msg[msg.length - 1]?.content}
+
+ {msg &&
+ msg.length > 0 &&
+ msg[msg.length - 1]?.content.length >= 10
+ ? msg[msg.length - 1]?.content.slice(0, 10) + "..."
+ : msg && msg.length > 0
+ ? msg[msg.length - 1]?.content
+ : null}
@@ -84,7 +93,7 @@ export const ChatCard = (props: any) => {
{msg && msg.length > 0 && getTime(msg[msg.length - 1]?.createdAt)}
- Feb 1
+ Feb 1{/** this should change to get the date only */}
diff --git a/app/components/Dashboard/Chat/ChatComponent.tsx b/app/components/Dashboard/Chat/ChatComponent.tsx
new file mode 100644
index 0000000..868d9bb
--- /dev/null
+++ b/app/components/Dashboard/Chat/ChatComponent.tsx
@@ -0,0 +1,54 @@
+import { message } from '@/app/Dashboard/Chat/type';
+import React from 'react'
+import MiddleBubbleRight from './RightBubbles/MiddleBubbleRight';
+import MiddleBuble from './LeftBubbles/MiddleBuble';
+
+const ChatComponent = ({
+ handlers,
+ messages,
+ globalStateUserId,
+}: {
+ handlers: any;
+ messages: message[];
+ globalStateUserId: number;
+}) => {
+ return (
+
+
+
+ {messages &&
+ messages.map((value, key: any) => {
+ if (value.sender_id === globalStateUserId) {
+ return ;
+ } else {
+ return (
+
+ );
+ }
+ })}
+
+
+
+ {messages && messages.length > 0
+ ? messages[messages.length - 1].createdAt
+ .toString()
+ .substring(0, 10) +
+ " at " +
+ messages[messages.length - 1].createdAt.toString().substring(11, 16)
+ : "No messages yet"}
+
+
+ );
+};
+
+export default ChatComponent
\ No newline at end of file
diff --git a/app/components/Dashboard/Chat/JoinChannel.tsx b/app/components/Dashboard/Chat/JoinChannel.tsx
index 4730451..1ec6e55 100644
--- a/app/components/Dashboard/Chat/JoinChannel.tsx
+++ b/app/components/Dashboard/Chat/JoinChannel.tsx
@@ -1,9 +1,12 @@
-import React from "react";
+import React, { useEffect, useRef, useState } from "react";
import { Inter } from "next/font/google";
import { motion } from "framer-motion";
import JoinChannelBubble from "./JoinChannelBubble";
import { IoIosSearch } from "react-icons/io";
import { AiOutlineClose } from "react-icons/ai";
+import axios from "axios";
+import { user } from "@/app/Dashboard/Chat/type";
+import { useForm } from "react-hook-form";
const inter = Inter({ subsets: ["latin"] });
const modalVariants = {
@@ -25,9 +28,44 @@ const modalVariants = {
},
};
-const JoinChannel = ({ handleClick }: { handleClick: () => void }) => {
+const JoinChannel = ({
+ handleClick,
+ user,
+ socket,
+}: {
+ handleClick: () => void;
+ user: user;
+ socket: any;
+}) => {
+ const [channels, setChannels] = useState
([]);
+ const [filteredChannels, setFilteredChannels] = useState([]);
+ const search = useRef(null);
+ const { register } = useForm();
+ useEffect(() => {
+ const fetchChannels = async () => {
+ const res = await axios
+ .get("http://localhost:8080/channels")
+ .then((data) => {
+ setChannels(data.data);
+ setFilteredChannels(data.data);
+ });
+ };
+ fetchChannels();
+ }, []);
+
+ const filterBySearch = (e: React.ChangeEvent, value: string | null) => {
+ const res = channels.filter((channel) => {
+ return channel.name
+ .toLowerCase()
+ .includes(value?.toLowerCase() as string);
+ });
+ setFilteredChannels(res);
+ };
+
return (
-
+
void }) => {
type="text"
className="rounded-md text-black pl-8 w-full h-[45px] focus:outline-none border-none focus:ring-[2px] focus:ring-red-500/[0.5] transition duration-300 ease-in-out"
placeholder="Search"
+ {...register("search", { required: true })}
+ ref={search}
+ onChange={(e) => {
+ filterBySearch(e, search.current?.value!);
+ }}
+ />
+
-
- {Array.from({ length: 20 }, (_, index) => (
-
- ))}
+ {filteredChannels.map((channel, key) => {
+ return (
+
+ );
+ })}
handleClick()} />
diff --git a/app/components/Dashboard/Chat/JoinChannelBubble.tsx b/app/components/Dashboard/Chat/JoinChannelBubble.tsx
index cfe69ce..ed2ea5f 100644
--- a/app/components/Dashboard/Chat/JoinChannelBubble.tsx
+++ b/app/components/Dashboard/Chat/JoinChannelBubble.tsx
@@ -1,36 +1,110 @@
-import React from "react";
+import { channel, user } from "@/app/Dashboard/Chat/type";
+import Image from "next/image";
+import axios from "axios";
+import React, { useRef, useState } from "react";
import { GoLock } from "react-icons/go";
+import { Socket } from "socket.io-client";
+import { useForm } from "react-hook-form";
+import toast, { Toaster } from "react-hot-toast";
-const JoinChannelBubble = ({ lock, handleClick }: { lock: boolean, handleClick:()=>void }) => {
- const [unlock, setUnlock] = React.useState(false);
+const JoinChannelBubble = ({
+ lock,
+ channel,
+ handleClick,
+ user,
+ socket,
+}: {
+ lock: boolean;
+ channel: channel;
+ user: user;
+ handleClick: () => void;
+ socket: Socket;
+}) => {
+ const lockRef = useRef(null);
+ const { register } = useForm();
+ const [unlock, setUnlock] = useState(false);
+ const handleSubmit = async (e: any) => {
+ e.preventDefault();
+ if (lock) {
+ channel.key = lockRef.current?.value as string;
+ const obj = {
+ participant: {
+ user_id: user.id,
+ channel_id: channel.id,
+ },
+ user: user,
+ channel: channel,
+ };
+ await axios.post(`http://localhost:8080/participants`, obj).then((res) => {
+ toast.success(`you have joined ${channel.name}`)
+ socket.emit("joinRoom", { user: user, roomName: channel.name });
+ }).catch((err) => {
+ toast(err.response.data.message);
+ })
+
+ } else {
+ const obj = {
+ participant: {
+ user_id: user.id,
+ channel_id: channel.id,
+ },
+ user: user,
+ channel: channel,
+ };
+ await axios
+ .post(`http://localhost:8080/participants`, obj)
+ .then((res) => {
+ toast.success(`you have joined ${channel.name}`)
+ socket.emit("joinRoom", { user: user, roomName: channel.name });
+ })
+ .catch((err) => {
+ toast(err.response.data.message);
+ });
+ }
+ setUnlock(false);
+ };
return (
-
+
{
+ e.preventDefault();
+ if (lock) {
+ setUnlock(true);
+ } else {
+ handleSubmit(e);
+ }
+ }}
+ >
- JOIN US NOW
+ {channel.name}
- {unlock ? (
-
+ {unlock && lock ? (
+
) : (
- a fun interactive group of people
+ {channel.topic?.substring(0, 30) +
+ (channel.topic?.length > 30 ? " ..." : "")}
)}
{lock && (
-
setUnlock(!unlock)}>
+
)}
- {/* {unlock &&
} */}
);
};
diff --git a/app/components/Dashboard/Chat/MemberList.tsx b/app/components/Dashboard/Chat/MemberList.tsx
new file mode 100644
index 0000000..d2d47db
--- /dev/null
+++ b/app/components/Dashboard/Chat/MemberList.tsx
@@ -0,0 +1,216 @@
+"use client";
+import React, { FC, useContext, useEffect, useState } from "react";
+import Image from "next/image";
+import { channel, participants, user } from "@/app/Dashboard/Chat/type";
+import axios from "axios";
+import { useRouter } from "next/navigation";
+
+import { FaMicrophone } from "react-icons/fa6";
+import { FaMicrophoneSlash } from "react-icons/fa6";
+import { FaBan } from "react-icons/fa6";
+import { FaChessKing } from "react-icons/fa6";
+import { FaChessPawn } from "react-icons/fa6";
+import toast from "react-hot-toast";
+import { useGlobalState } from "../../Sign/GlobalState";
+
+const MemberList = ({
+ participant,
+ exec,
+ channel,
+}: {
+ participant: participants;
+ exec: participants;
+ channel: channel;
+}) => {
+ const [user, setUser] = useState
();
+ const router = useRouter();
+ const { state, dispatch } = useGlobalState();
+
+ useEffect(() => {
+ axios
+ .get(`http://localhost:8080/user/${participant.user_id}`)
+ .then((res) => {
+ setUser(res.data);
+ });
+ }, [participant]);
+
+ const handleClick = () => {
+ router.push(`/Dashboard/Profile?id=${user?.id}`);
+ };
+
+ const handleBan = (e: React.MouseEvent) => {
+ e.preventDefault();
+ if (!exec) {
+ toast.error("You cannot take privilage from yourself");
+ return;
+ }
+ if (participant.role === "ADMIN") {
+ toast.error("You cannot ban an admin");
+ return;
+ }
+ const obj = {
+ cid: exec.channel_id,
+ uid: participant.user_id,
+ };
+ console.log(obj);
+ axios.post(`http://localhost:8080/ban/`, obj).then((res) => {
+ console.log(res.data);
+ // state?.socket?.emit("leaveUpdate", {
+ // roomName: channel.name,
+ // user: user,
+ // });
+ // router.push("/Dashboard/");
+ })
+ // console.log("ban");
+ };
+
+ const handleKick = (e: React.MouseEvent) => {
+ e.preventDefault();
+ if (!exec) {
+ toast.error("You do not have privilage to kick");
+ return;
+ }
+ if (participant.role === "ADMIN") {
+ toast.error("You cannot kick an admin");
+ return;
+ }
+ const obj = {
+ channel: exec.channel_id,
+ executor: exec.user_id,
+ };
+ axios
+ .put(`http://localhost:8080/participants/kick/${participant.user_id}`, obj)
+ .then((res) => {
+ state?.socket?.emit("leaveUpdate", {
+ roomName: channel.name,
+ user: user,
+ });
+ router.push("/Dashboard/");
+ })
+ .catch((err) => {
+ console.log(err);
+ });
+ console.log("kick");
+ };
+
+ const handlePromoteDemote = (
+ e: React.MouseEvent
+ ) => {
+ e.preventDefault();
+ if (!exec) {
+ toast.error("you do not have privilage to promote/demote");
+ return;
+ }
+ if (participant.role === "ADMIN") {
+ toast.error("You cannot take privilage from admin");
+ return;
+ }
+ const obj = {
+ channel: exec.channel_id,
+ executor: exec.user_id,
+ participant: {
+ role: participant.role === "MEMBER" ? "MOD" : "MEMBER",
+ },
+ };
+ axios
+ .put(`http://localhost:8080/participants/${participant.user_id}`, obj)
+ .then((res) => {
+ state?.socket?.emit("channelUpdate", {
+ roomName: channel.name,
+ user: user,
+ });
+ })
+ .catch((err) => {
+ console.log(err);
+ });
+
+ console.log("promote/demote");
+ };
+
+ const handleMuteUnMute = (
+ e: React.MouseEvent
+ ) => {
+ e.preventDefault();
+ if (!exec) {
+ toast.error("You do not have privilage to mute/unmute");
+ return;
+ }
+ if (participant.role === "ADMIN") {
+ toast.error("You cannot mute an admin");
+ return;
+ }
+ const obj = {
+ channel: exec.channel_id,
+ executor: exec.user_id,
+ participant: {
+ mute: participant.mute ? false : true,
+ },
+ };
+ axios
+ .put(`http://localhost:8080/participants/${participant.user_id}`, obj)
+ .then((res) => {
+ state?.socket?.emit("channelUpdate", {
+ roomName: channel.name,
+ user: user,
+ });
+ })
+ .catch((err) => {
+ console.log(err);
+ });
+ console.log("mute/unmute");
+ };
+
+ return (
+
+
+
{
+ handleClick();
+ }}
+ className="rounded-full aspect-square"
+ />
+
+ {user?.name}
+ @{user?.nickname}
+
+
+
{participant.role.toLowerCase()}
+
+
+ {participant.mute ? (
+
+ ) : (
+
+ )}
+
+
+
+
+
+
+
+
+ {participant.role === "ADMIN" || participant.role === "MOD" ? (
+
+ ) : (
+
+ )}
+
+
+
+ );
+};
+
+export default MemberList;
+
+// need to add something to the backend so when i kick a user or ban a user, the user is removed from the channel and from the room in the socket
diff --git a/app/components/Dashboard/Chat/channelManagement.tsx b/app/components/Dashboard/Chat/channelManagement.tsx
new file mode 100644
index 0000000..40e36e6
--- /dev/null
+++ b/app/components/Dashboard/Chat/channelManagement.tsx
@@ -0,0 +1,265 @@
+"use client";
+import React, { useState, useRef } from "react";
+import { motion } from "framer-motion";
+import { Input } from "@/components/ui/newinput";
+import MemberList from "./MemberList";
+import { useForm } from "react-hook-form";
+import { channel, participants, user } from "@/app/Dashboard/Chat/type";
+import Image from "next/image";
+import { useRouter } from "next/navigation";
+import axios from "axios";
+import toast from "react-hot-toast";
+import { useGlobalState } from "../../Sign/GlobalState";
+
+
+
+// this still needs work in terms of realtime and stuff, but the basic functionality is there
+
+const ChannelManagement = ({
+ participants,
+ channel,
+ user,
+ update,
+}: {
+ participants: participants[];
+ channel: channel;
+ user: user;
+ update: (arg0: boolean) => void;
+}) => {
+ const [priviliged, setPriviliged] = useState(
+ participants.filter(
+ (participant) =>
+ (participant.role === "ADMIN" || participant.role === "MOD") &&
+ participant.user_id === user.id
+ )[0]
+ );
+ const router = useRouter();
+ const [picture, setPicture] = useState();
+ const { register } = useForm();
+ const topicInput = useRef(null);
+ const channelNameInput = useRef(null);
+ const keyInput = useRef(null);
+ const [selectedOption, setSelectedOption] = useState("");
+ const { state } = useGlobalState();
+
+ const handleOptionChange = (event: any) => {
+ setSelectedOption(event.target.value);
+ };
+
+ const handleLeave = () => {
+ axios
+ .delete(
+ `http://localhost:8080/participants/leave?channel=${channel.id}&user=${user.id}`
+ )
+ .then((res) => {
+ router.push("/Dashboard/");
+ })
+ .catch();
+ };
+
+ const validateForm = () => {
+ if (
+ channelNameInput.current?.value === ""
+ ) {
+ return false;
+ }
+ if (selectedOption === "protected" && keyInput.current?.value === "") {
+ return false;
+ }
+ return true;
+ };
+
+
+ const handleSubmit = (e: React.FormEvent) => {
+ e.preventDefault();
+ // if (!validateForm()) {
+ // toast.error("Please fill in the required fields.");
+ // return;
+ // }
+ const obj = {
+ channel: {
+ name: channelNameInput.current?.value! || channel.name,
+ key: keyInput.current?.value! || channel.key,
+ topic: topicInput.current?.value! || channel.topic,
+ state: selectedOption === "" ? channel.state : selectedOption,
+ },
+ user: { id: priviliged.user_id },
+ };
+ console.log(obj);
+ axios
+ .put(`http://localhost:8080/channels/${channel.id}`, obj)
+ .then((res) => {
+ if (picture) {
+ if (!picture.type.startsWith("image/")) {
+ alert("Please select an image picture.");
+ return;
+ }
+ const formData = new FormData();
+ formData.append("image", picture);
+ axios
+ .post(
+ `http://localhost:8080/channels/image?channel=${channel.id}&user=${user.id}`,
+ formData,
+ {
+ headers: { "Content-Type": "multipart/form-data" },
+ }
+ )
+ .then((res) => {
+ if (!res.data.success) {
+ toast.error(
+ "error in uploading image, using the default image."
+ );
+ }
+ state?.socket?.emit("channelUpdate", { roomName: channel.name, user: user });
+ })
+ .catch();
+ }
+ state?.socket?.emit("channelUpdate", { roomName: channel.name, user: user });
+ })
+ .catch((err) => {
+ console.log(err);
+ });
+ console.log(obj);
+ };
+
+ return (
+
+
+
+
handleLeave()}
+ className="py-2 px-5 bg-red-500 rounded-md mt-4"
+ >
+ leave channel
+
+
+
+
+ {participants.map((participant, index) => {
+ return (
+
+ );
+ })}
+
+
+
+ );
+};
+
+export default ChannelManagement;
+
+// still need form validation and submit logic depending on the selected option, and the participants management is to be added later
diff --git a/app/components/Dashboard/Chat/createChannel.tsx b/app/components/Dashboard/Chat/createChannel.tsx
new file mode 100644
index 0000000..21c5d60
--- /dev/null
+++ b/app/components/Dashboard/Chat/createChannel.tsx
@@ -0,0 +1,250 @@
+import React, { useEffect, useRef, useState } from "react";
+import { Inter } from "next/font/google";
+import { motion } from "framer-motion";
+import JoinChannelBubble from "./JoinChannelBubble";
+import { IoIosSearch } from "react-icons/io";
+import { AiOutlineClose } from "react-icons/ai";
+import axios from "axios";
+import { user } from "@/app/Dashboard/Chat/type";
+import { useForm } from "react-hook-form";
+import { Input } from "@/components/ui/newinput";
+import { Button } from "@/components/ui/moving-border";
+import { BottomGradient } from "@/app/register/page";
+import toast from "react-hot-toast";
+
+const inter = Inter({ subsets: ["latin"] });
+const modalVariants = {
+ open: {
+ opacity: 1,
+ scale: 1,
+ transition: {
+ ease: "easeOut",
+ duration: 0.15,
+ },
+ },
+ closed: {
+ opacity: 0,
+ scale: 0.75,
+ transition: {
+ ease: "easeIn",
+ duration: 0.15,
+ },
+ },
+};
+
+const CreateChannel = ({
+ handleClick,
+ user,
+ socket,
+}: {
+ handleClick: () => void;
+ user: user;
+ socket: any;
+}) => {
+ const password = useRef(null);
+ const [file, setFile] = useState(null);
+ const topic = useRef(null);
+ const name = useRef(null);
+ const [channelAppearence, setChannelAppearence] = useState(false);
+ const { register } = useForm();
+
+ const validateForm = () => {
+ if (name.current!.value!.trim().length < 3) {
+ toast.error("Name must be at least 3 characters long.");
+ return false;
+ }
+ if (
+ password.current!.value!.match(/(["'><])/) ||
+ name.current!.value!.match(/(['"><])/)
+ ) {
+ toast.error("you sneaky bastard");
+ return false;
+ }
+ return true;
+ };
+
+ const handleCreateChannel = async () => {
+ if (!validateForm()) return;
+ const channelObject = {
+ channel: {
+ name: name.current!.value,
+ key: password.current!.value ? password.current!.value : null,
+ state: channelAppearence
+ ? "private"
+ : password.current!.value
+ ? "protected"
+ : "public",
+ },
+ user: user,
+ };
+ axios
+ .post("http://localhost:8080/channels", channelObject)
+ .then((res) => {
+ if (!res.data.success) {
+ toast.error("error in creating channel");
+ return;
+ }
+ if (file) {
+ if (!file.type.startsWith("image/")) {
+ alert("Please select an image file.");
+ return;
+ }
+ const formData = new FormData();
+ formData.append("image", file);
+ axios
+ .post(
+ `http://localhost:8080/channels/image?channel=${res.data.id}&user=${user.id}`,
+ formData,
+ {
+ headers: { "Content-Type": "multipart/form-data" },
+ }
+ )
+ .then((res) => {
+ if (!res.data.success) {
+ toast.error(
+ "error in uploading image, using the default image."
+ );
+ }
+ socket.emit("joinRoom", { roomName: res.data.name, user: user });
+ })
+ .catch();
+ } else {
+ socket.emit("joinRoom", { roomName: res.data.name, user: user });
+ }
+ })
+ .catch();
+ handleClick();
+ };
+ return (
+
+
+ Create a channel
+
+ channels is where you and your friends can communicate as a group and
+ you can have three types of channels, Public, private, and Protected.
+
+
+
+ Upload file
+
+ {
+ if (e.target.files && e.target.files[0]) {
+ if (!e.target.files[0].type.startsWith("image/")) {
+ toast.error("Please select an image file.");
+ return;
+ }
+ setFile(e.target.files[0]);
+ }
+ }}
+ />
+
+
+
+
{
+ e.preventDefault();
+ setChannelAppearence(!channelAppearence);
+ }}
+ >
+
+
+
+ {!channelAppearence ? "Public" : "Private"}
+
+
+
+
+
+
+ );
+};
+
+export default CreateChannel;
diff --git a/app/components/Dashboard/Chat/onlinePreview.tsx b/app/components/Dashboard/Chat/onlinePreview.tsx
new file mode 100644
index 0000000..b6ac136
--- /dev/null
+++ b/app/components/Dashboard/Chat/onlinePreview.tsx
@@ -0,0 +1,6 @@
+import React from "react";
+
+export const OnlinePreview = ({ status }: { status: string }) => {
+ if (status === "ONLINE") return Online
;
+ else return Offline
;
+};
diff --git a/app/components/Dashboard/Profile/LinkedFriend.tsx b/app/components/Dashboard/Profile/LinkedFriend.tsx
new file mode 100644
index 0000000..d34ab75
--- /dev/null
+++ b/app/components/Dashboard/Profile/LinkedFriend.tsx
@@ -0,0 +1,42 @@
+import Image from 'next/image'
+import React from 'react'
+import { useRouter } from 'next/navigation'
+import { Inter } from 'next/font/google'
+import { Rubik } from 'next/font/google'
+
+const inter = Inter({
+ subsets: ['latin'],
+ weight: ['400', '500', '600', '700'],
+ })
+const rubik = Rubik({
+ subsets: ['latin'],
+ weight: ['400', '500', '600', '700'],
+})
+const LinkedFriend = (props : any) => {
+ const router = useRouter();
+ const handleClick = (id : any) => {
+ router.push(`/Dashboard/Profile?id=${id}`);
+ }
+ return (
+
+
+ {/*
*/}
+
handleClick(props.user?.id)}
+ alt='profile'
+ height={50}
+ width={50}
+ src={props.user?.picture || '/b.png'}
+ className="object-cover cursor-pointer !m-0 !p-0 object-top rounded-full h-[50px] w-[50px] border-2 group-hover:scale-105 group-hover:z-30 border-white relative transition duration-500"
+ />
+
+
{props.user?.name}
+
@{props.user?.username}
+
+
+
#{props?.index}
+
+ )
+}
+
+export default LinkedFriend
\ No newline at end of file
diff --git a/app/components/Dashboard/Profile/UserProfile.tsx b/app/components/Dashboard/Profile/UserProfile.tsx
index 5cacc5e..1214456 100644
--- a/app/components/Dashboard/Profile/UserProfile.tsx
+++ b/app/components/Dashboard/Profile/UserProfile.tsx
@@ -3,10 +3,16 @@ import React, { use, useEffect, useState } from "react";
import Image from "next/image";
import { useGlobalState } from "../../Sign/GlobalState";
import { Dropdown } from "./Dropdown";
-import Userstatus from "./Userstatus";
import { PinContainer } from "@/components/ui/3d-pin";
-
+import {motion} from "framer-motion";
import axios from "axios";
+import Userstatus from "./Userstatus";
+import { Rajdhani } from "next/font/google";
+import { Inter } from "next/font/google";
+import LinkedFriend from "./LinkedFriend";
+
+const inter = Inter({ subsets: ["latin"] });
+const rajdhani = Rajdhani({ subsets: ["latin"], weight: ["400", "500"] });
const people = [
{
@@ -165,68 +171,139 @@ const UserProfile = ({target} : any) => {
return (
-
-
-
-
-
+
+
+
+
+ {
+ target ? (
+
+ ) : (
+
+ )
+ }
blockUser("blockFriend")} handleUnblock={() => blockUser("unblockFriend")} status={status} recv={recv} />
-
+
-
+ {target ? (
+
+ ) : (
+
+ )}
-
-
- {target.name}
-
-
@{target.username}
-
400,000
+ {
+ target ? (
+
+
+ {target?.name}
+
+
+ @{target?.username}
+
+ 400,000
+
+ ) :(
+
+ )
+ }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ LVL 2
+
+
+ 250/1000
+
+
+
+
+
+
+
+
+ Linked Friends
+
+
+ {
+ linkedFriends && linkedFriends?.map((user, i) => {
+ return (
+
+ );
+ })
+ }
+
+
-
);
diff --git a/app/components/Dashboard/Profile/Userstatus.tsx b/app/components/Dashboard/Profile/Userstatus.tsx
index 1392939..8be7255 100644
--- a/app/components/Dashboard/Profile/Userstatus.tsx
+++ b/app/components/Dashboard/Profile/Userstatus.tsx
@@ -1,57 +1,20 @@
import React from 'react'
-import { Inter } from "next/font/google";
import { Button } from "@/components/ui/moving-border"
import Image from 'next/image'
import { AnimatedTooltip } from '@/components/ui/animated-tooltip'
import { getDate } from '@/app/utils'
+import { Rajdhani } from "next/font/google";
+import { Inter } from "next/font/google";
const inter = Inter({ subsets: ["latin"] });
+const rajdhani = Rajdhani({ subsets: ["latin"], weight: ["400", "500"] });
-const Userstatus = ({target, status, recv, friendReq, removeFriend, handleSender, linkedFriends} : any) => {
+const Userstatus = ({target, status, recv, friendReq, removeFriend, handleSender} : any) => {
return (
-
-
-
-
-
-
-
-
-
-
- LVL 2
-
-
- 250/1000
-
-
-
-
-
-
-
-
-
-
+
+
friendReq("acceptFriendRequest")}
- borderRadius="1.75rem"
+ borderRadius="10px"
borderClassName=" bg-[radial-gradient(var(--green-500)_40%,transparent_60%)]"
- className={`text-white border-slate-800 w-full sm:mt-0 mt-4 bg-green-500/[0.3]`}
+ className={`text-white border-slate-800 w-full sm:mt-0 mt-4 bg-green-500/[0.5]`}
>
ACCEPTE
friendReq("rejectFriendRequest")}
- borderRadius="1.75rem"
+ borderRadius="10px"
borderClassName=" bg-[radial-gradient(var(--red-500)_40%,transparent_60%)]"
- className={`text-white border-slate-800 w-full sm:mt-0 mt-4 bg-red-500/[0.3]`}
+ className={`text-white border-slate-800 w-full sm:mt-0 mt-4 bg-[#FF4654]/[0.6]`}
>
REJECTE
@@ -117,9 +80,9 @@ const Userstatus = ({target, status, recv, friendReq, removeFriend, handleSender
: recv && recv === "ACCEPTED" ?
REMOVE FRIEND
@@ -127,9 +90,9 @@ const Userstatus = ({target, status, recv, friendReq, removeFriend, handleSender
: status && status === "BLOCKED" ? null
:
{
status && status === "PENDING" ? "PENDING"
@@ -138,10 +101,8 @@ const Userstatus = ({target, status, recv, friendReq, removeFriend, handleSender
}
}
-
-
-
-
+
+
)
}
diff --git a/app/components/Dashboard/Search/UserCard.tsx b/app/components/Dashboard/Search/UserCard.tsx
index c755a86..e1e8a1a 100644
--- a/app/components/Dashboard/Search/UserCard.tsx
+++ b/app/components/Dashboard/Search/UserCard.tsx
@@ -16,7 +16,7 @@ const UserCard = ({user}: Props) => {
return (
-
+
{
@{user?.username}
@@ -48,15 +48,4 @@ const UserCard = ({user}: Props) => {
)
}
- export default UserCard
- //
- //
- //
{user.name}
- //
@{user.username}
- //
\ No newline at end of file
+ export default UserCard
\ No newline at end of file
diff --git a/app/components/Dashboard/Settings/EditProfile.tsx b/app/components/Dashboard/Settings/EditProfile.tsx
index 33a66fc..b66d5a0 100644
--- a/app/components/Dashboard/Settings/EditProfile.tsx
+++ b/app/components/Dashboard/Settings/EditProfile.tsx
@@ -3,6 +3,11 @@ import React, { useState } from 'react'
import Image from 'next/image'
import { useForm } from 'react-hook-form';
import { useGlobalState } from '../../Sign/GlobalState';
+
+import { cn } from "@/components/cn";
+import { Label } from "@/components/ui/newlabel";
+import { Input } from "@/components/ui/newinput";
+
import axios from 'axios';
const EditProfile = () => {
@@ -115,22 +120,16 @@ const EditProfile = () => {