setIsOpen(false)}/> */}
8 |
9 |
Delete Comment?
10 |
11 | The comment will be deleted, and this cannot be undone, are you sure you want to
12 | delete this comment?
13 |
14 |
15 | Delete
16 | Cancel
17 |
18 |
19 |
20 | );
21 | }
22 |
--------------------------------------------------------------------------------
/components/Settings/modals/EditCommentModal.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import styles from './Modals.module.scss';
3 |
4 | export default function DeleteCommentModal() {
5 | return (
6 |
7 | {/*
setIsOpen(false)}/> */}
8 |
9 |
Delete Comment?
10 |
11 | The comment will be deleted, and this cannot be undone, are you sure you want to
12 | delete this comment?
13 |
14 |
15 | Cancel
16 | Delete
17 |
18 |
19 |
20 | );
21 | }
22 |
--------------------------------------------------------------------------------
/components/Explore/TrendingHash.module.scss:
--------------------------------------------------------------------------------
1 | @import '../../styles/colors/variables.scss';
2 |
3 | .trendingHashContainer{
4 | height: 70px;
5 | width: 360px;
6 | display: flex;
7 | align-items: center;
8 | padding: 0 5px;
9 | margin-bottom: 1.1rem;
10 | border-radius: 10px;
11 | transition: 0.2s;
12 | cursor: pointer;
13 | &:hover{
14 | background: $black2h;
15 | }
16 | .hash{
17 | width: 3vw;
18 | font-size: 1.8em;
19 | color: #999;
20 | }
21 | .info{
22 | p{
23 | color: #999;
24 | font-size: 0.85em;
25 | }
26 | h5{
27 | font-size: 1em;
28 | padding: 3px 0;
29 | }
30 | }
31 | }
32 |
33 | @media (max-width: 1200px){
34 | .trendingHashContainer{
35 | width: 100%;
36 | .hash{
37 | padding-right: 45px;
38 | font-size: 1.4em;
39 | }
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/components/Register/PageFour.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import Button from '../Button';
3 | import styles from '../../styles/register.module.scss';
4 | import TextArea from '../TextArea';
5 |
6 | interface Props {
7 | handleChange: () => void;
8 | values: any;
9 | register: any;
10 | errors: any;
11 | }
12 |
13 | export default function PageFour({ handleChange, values, register, errors }: Props) {
14 | return (
15 |
16 |
17 |
26 | Register
27 |
28 |
29 | );
30 | }
31 |
--------------------------------------------------------------------------------
/hooks/useGetUser.ts:
--------------------------------------------------------------------------------
1 | import axios from 'axios';
2 | import { useEffect, useState } from 'react';
3 |
4 | interface User {
5 | email: string;
6 | name: string;
7 | lastname: string;
8 | profilePic: string;
9 | username: string;
10 | bio: string;
11 | coverPic: string;
12 | verifiedBadge: boolean;
13 | }
14 |
15 | export const useGetUser = (userId: string) => {
16 | const [user, setUser] = useState
({
17 | email: '',
18 | name: '',
19 | lastname: '',
20 | profilePic: '',
21 | username: '',
22 | bio: '',
23 | coverPic: '',
24 | verifiedBadge: false
25 | });
26 |
27 | useEffect(() => {
28 | const fetchData = async () => {
29 | const data = await axios.get(`https://snow-net.herokuapp.com/api/users/${userId}`);
30 | setUser(data.data);
31 | };
32 | fetchData();
33 | }, []);
34 |
35 | return user;
36 | };
37 |
--------------------------------------------------------------------------------
/styles/donations.module.scss:
--------------------------------------------------------------------------------
1 |
2 | .donationsPage{
3 | display: flex;
4 | justify-content: center;
5 | padding: 20px 0;
6 | flex-direction: column;
7 | align-items: center;
8 | h2{
9 | font-size: 9em;
10 | letter-spacing: 10px;
11 | font-family: 'Noir', sans-serif;
12 | }
13 | .cards{
14 | display: flex;
15 | justify-content: space-between;
16 | padding-top: 7vh;
17 | width: 80%;
18 | }
19 | }
20 |
21 | @media (max-width: 1200px){
22 | .donationsPage{
23 | max-width: 100vw;
24 | overflow: hidden;
25 | h2{
26 | font-size: 3.7em;
27 | letter-spacing: 4px;
28 | }
29 | .cards{
30 | width: 100%;
31 | display: flex;
32 | justify-content: center;
33 | align-items: center;
34 | flex-direction: column;
35 | padding-top: 3vh;
36 | }
37 | }
38 | }
--------------------------------------------------------------------------------
/components/TextArea.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import styles from './TextArea.module.scss';
3 |
4 | interface Props {
5 | name: string;
6 | label: string;
7 | bg: string;
8 | value: string;
9 | handleChange: (e: React.ChangeEvent, type: string) => void;
10 | inputRef: any;
11 | error: any;
12 | }
13 |
14 | export default function TextArea({ name, label, bg, handleChange, value, error }: Props) {
15 | return (
16 |
17 |
29 | );
30 | }
31 |
--------------------------------------------------------------------------------
/components/Welcome/SnowFAQ.tsx:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react';
2 | import { BsFillQuestionCircleFill } from 'react-icons/bs';
3 | import styles from './SnowFAQ.module.scss';
4 |
5 | export default function SnowFAQ() {
6 | const [faqOpen, setFaqOpen] = useState(false);
7 | return (
8 |
9 |
(faqOpen ? setFaqOpen(false) : setFaqOpen(true))}>
10 |
11 |
12 |
13 |
14 | Snow is a social network. Here you can create and share content! You can upload
15 | posts, upload images, create polls, interact with friends, create and join
16 | groups, and even includes its own chat to talk
17 |
18 |
19 |
20 | );
21 | }
22 |
--------------------------------------------------------------------------------
/components/Posts/InputChoice.tsx:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react';
2 | import styles from './InputChoice.module.scss';
3 |
4 | interface Props {
5 | label: string;
6 | setPoll: React.Dispatch>;
7 | index: number;
8 | poll: [any];
9 | value: any;
10 | setValue: any;
11 | }
12 |
13 | export default function InputChoice({ label, setPoll, index, poll, value, setValue }: Props) {
14 | const handleChange = (e: React.ChangeEvent) => {
15 | setValue(e.target.value);
16 | };
17 |
18 | return (
19 |
20 |
27 | {label}
28 |
29 | );
30 | }
31 |
--------------------------------------------------------------------------------
/components/Settings/SettingsComponent.tsx:
--------------------------------------------------------------------------------
1 | import React, { useContext } from 'react';
2 | import AuthContext from '../../context/AuthContext';
3 | import General from './pages/General';
4 | import Language from './pages/Language';
5 | import Privacy from './pages/Privacy';
6 | import Security from './pages/Security';
7 |
8 | interface Props {
9 | setPage: React.Dispatch>;
10 | page: number;
11 | }
12 |
13 | export default function SettingsComponent({ setPage, page }: Props) {
14 | const { loggedUser } = useContext(AuthContext);
15 |
16 | return (
17 | <>
18 | {page === 1 && }
19 | {page === 2 && }
20 | {page === 3 && }
21 | {page === 4 && }
22 | >
23 | );
24 | }
25 |
--------------------------------------------------------------------------------
/components/OpenImage.tsx:
--------------------------------------------------------------------------------
1 | import React, { useEffect, useState } from 'react';
2 | import styles from './OpenImage.module.scss';
3 |
4 | interface Props {
5 | img?: string;
6 | openImage: boolean;
7 | setOpenImage: any;
8 | }
9 |
10 | export default function OpenImage({ img, openImage, setOpenImage }: Props) {
11 | const [isClose, setIsClose] = useState(false);
12 |
13 | useEffect(() => {
14 | document.body.addEventListener('keydown', (e: any) => {
15 | if (e.keyCode === 27) {
16 | setIsClose(true);
17 | }
18 | });
19 | });
20 |
21 | const handleClick = () => {
22 | setTimeout(() => setOpenImage(false), 550);
23 | setIsClose(true);
24 | };
25 |
26 | return (
27 |
30 |
31 |
32 | );
33 | }
34 |
--------------------------------------------------------------------------------
/hooks/useLocalStorage.ts:
--------------------------------------------------------------------------------
1 | import Router from 'next/router';
2 | import { useEffect, useState } from 'react';
3 |
4 | export const useLocalStorage = () => {
5 | const [loggedUser, setLoggedUser] = useState(null);
6 |
7 | useEffect(() => {
8 | try {
9 | const userLocal = localStorage.getItem('userLog');
10 | if (userLocal) {
11 | const user = JSON.parse(userLocal);
12 | setLoggedUser(user);
13 | } else if (!loggedUser && Router.pathname !== '/register') {
14 | if (Router.pathname !== '/login') Router.push('/welcome');
15 | } else if (
16 | (loggedUser && Router.pathname === '/register') ||
17 | Router.pathname === '/login' ||
18 | Router.pathname === '/welcome'
19 | ) {
20 | Router.push('/');
21 | }
22 | } catch (err) {
23 | console.log(err);
24 | }
25 | }, []);
26 |
27 | return { loggedUser, setLoggedUser };
28 | };
29 |
--------------------------------------------------------------------------------
/components/Responsive/ResponsiveNav.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { BiConversation } from 'react-icons/bi';
3 | import { RiGalleryLine, RiSearchLine } from 'react-icons/ri';
4 | import { FaIgloo } from 'react-icons/fa';
5 | import styles from './ResponsiveNav.module.scss';
6 | import NavLink from 'next/link';
7 | import { BsPeopleFill } from 'react-icons/bs';
8 |
9 | export default function ResponsiveNav() {
10 | return (
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 | );
28 | }
29 |
--------------------------------------------------------------------------------
/components/Chats/Conversation.module.scss:
--------------------------------------------------------------------------------
1 | .conversationContainer{
2 | width: 100%;
3 | height: 100%;
4 | display: flex;
5 | justify-content: center;
6 | align-items: center;
7 | flex-direction: column;
8 | z-index: 10;
9 | .conversation{
10 | display: flex;
11 | flex-direction: column;
12 | position: absolute;
13 | bottom: 120px;
14 | width: 73vw;
15 | max-height: 70vh;
16 | overflow-y: scroll;
17 | overflow-x: hidden;
18 | &::-webkit-scrollbar{
19 | width: 8px;
20 | }
21 | &::-webkit-scrollbar-thumb{
22 | background: #ffffff60;
23 | transition: .3s;
24 | border-radius: 20px;
25 | &:hover{
26 | background: #ffffff99;
27 | }
28 | }
29 | }
30 | }
31 |
32 | @media (max-width: 1200px){
33 | .conversationContainer{
34 | min-width: 100vw;
35 | .conversation{
36 | width: 100vw;
37 | height: 100%;
38 | }
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/pages/404.tsx:
--------------------------------------------------------------------------------
1 | import Router from 'next/router';
2 | import React from 'react';
3 | import { AiOutlineArrowRight } from 'react-icons/ai';
4 | import Layout from '../components/Layout';
5 | import styles from '../styles/404.module.scss';
6 |
7 | export default function Err404() {
8 | const handleClick = () => Router.push('/');
9 |
10 | return (
11 |
12 |
13 |
14 |
15 |
404
16 | Page not found
17 |
18 |
19 |
20 | Back to Home{' '}
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 | );
29 | }
30 |
--------------------------------------------------------------------------------
/validations/RegisterValidation.ts:
--------------------------------------------------------------------------------
1 | import * as yup from 'yup';
2 |
3 | export const registerSchema = yup.object().shape({
4 | username: yup.string()
5 | .required("This field is required")
6 | .min(3)
7 | .max(10)
8 | .lowercase("Please put the username in lowercase") ,
9 | name: yup.string()
10 | .required("This field is required")
11 | .min(3)
12 | .max(10) ,
13 | lastname: yup.string()
14 | .required("This field is required")
15 | .min(3)
16 | .max(14) ,
17 | email: yup.string()
18 | .email("Must comply with the email format")
19 | .required("This field is required") ,
20 | password: yup.string()
21 | .required("This field is required")
22 | .min(6)
23 | .max(30) ,
24 | reppassword: yup.string()
25 | .required("This field is required")
26 | .oneOf([yup.ref('password')], "Passwords must be equals!") ,
27 | });
--------------------------------------------------------------------------------
/public/vercel.svg:
--------------------------------------------------------------------------------
1 |
3 |
4 |
--------------------------------------------------------------------------------
/components/Explore/TrendingBar.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import styles from './TrendingBar.module.scss';
3 | import TrendingHash from './TrendingHash';
4 |
5 | export default function TrendingBar() {
6 | return (
7 |
8 |
9 |
Trending
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 | );
21 | }
22 |
--------------------------------------------------------------------------------
/components/Responsive/Posts/ResposiveToPost.tsx:
--------------------------------------------------------------------------------
1 | import React, { useContext, useState } from 'react';
2 | import { RiPencilFill, RiQuillPenFill } from 'react-icons/ri';
3 | import AuthContext from '../../../context/AuthContext';
4 | import NewPostModal from './NewPostModal';
5 | import styles from './ResponsiveToPost.module.scss';
6 |
7 | export default function ResposiveToPost() {
8 | const [isOpen, setIsOpen] = useState(false);
9 | const { loggedUser, setLoggedUser } = useContext(AuthContext);
10 |
11 | const handleClick = () => (isOpen ? setIsOpen(false) : setIsOpen(true));
12 |
13 | return (
14 |
15 |
16 |
17 |
18 | {isOpen && (
19 | {
22 | throw new Error('Function not implemented.');
23 | }}
24 | />
25 | )}
26 |
27 | );
28 | }
29 |
--------------------------------------------------------------------------------
/components/RequestPanel/Sidebar.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { MdGroup, MdOutlineSort } from 'react-icons/md';
3 | import styles from './Sidebar.module.scss';
4 |
5 | export default function Sidebar() {
6 | return (
7 |
8 |
Request Panel
9 |
10 |
11 |
12 |
13 |
14 |
15 |
Pending Posts
16 |
{0} Posts
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
Requests to join groups
25 |
{0} Groups
26 |
27 |
28 |
29 |
30 | );
31 | }
32 |
--------------------------------------------------------------------------------
/components/Hover/HoverUserProfile.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import styles from './HoverUserProfile.module.scss';
3 |
4 | interface Props {
5 | name: string;
6 | username: string;
7 | bio: string;
8 | profilePic: string;
9 | bannerPic: string;
10 | }
11 |
12 | export default function HoverUserProfile({ name, username, bio, profilePic, bannerPic }: Props) {
13 | return (
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
{name}
24 |
·
25 |
@{username}
26 |
27 |
30 |
31 |
32 | );
33 | }
34 |
--------------------------------------------------------------------------------
/components/Posts/ConfirmDelete.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import styles from './ConfirmDelete.module.scss';
3 |
4 | interface Props {
5 | deletePost: () => Promise;
6 | setModalOpen: any;
7 | }
8 |
9 | export default function ConfirmDelete({ deletePost, setModalOpen }: Props) {
10 | return (
11 |
12 |
13 |
14 |
Delete Post?
15 |
16 | The post will be deleted, and this cannot be undone, are you sure you want
17 | to delete this post?
18 |
19 |
20 | setModalOpen(false)}>
21 | Cancel
22 |
23 |
24 | Delete
25 |
26 |
27 |
28 |
29 |
30 | );
31 | }
32 |
--------------------------------------------------------------------------------
/components/Responsive/SlideFriends.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import Slider from 'react-slick';
3 | import User from './SlideContent/User';
4 | import styles from './SlideFriends.module.scss';
5 |
6 | interface Props {
7 | users: any;
8 | }
9 |
10 | let settings = {
11 | dots: true,
12 | speed: 500,
13 | slidesToShow: 2,
14 | slidesToScroll: 2
15 | };
16 |
17 | export default function SlideFriends({ users }: Props) {
18 | users;
19 | return (
20 |
21 |
Who to follow
22 |
23 |
24 | {users.map(
25 | ({ profilePic, username, name, lastname, _id }: any, index: number) => (
26 |
32 | )
33 | )}
34 |
35 |
36 |
37 | );
38 | }
39 |
--------------------------------------------------------------------------------
/components/Gallery/ImagePreview.module.scss:
--------------------------------------------------------------------------------
1 | .imagePreviewContainer{
2 | position: relative;
3 | display: flex;
4 | align-items: center;
5 | justify-content: center;
6 | max-width: 100%;
7 | max-height: 100%;
8 | position: relative;
9 | .closeContainer{
10 | width: 100%;
11 | border-radius: 15px 15px 0 0;
12 | background: #00000050;
13 | height: 50px;
14 | position: absolute;
15 | top: 0;
16 | left: 0;
17 | display: flex;
18 | align-items: center;
19 | .close{
20 | width: 30px;
21 | height: 30px;
22 | color: #fff;
23 | border-radius: 50%;
24 | font-size: 1.3em;
25 | background: transparent;
26 | border: none;
27 | display: flex;
28 | align-items: center;
29 | justify-content: center;
30 | margin-left: 10px;
31 | transition: background 0.3s;
32 | &:hover{
33 | background: #ffffff20;
34 | }
35 | }
36 | }
37 | img{
38 | max-width: 100%;
39 | max-height: 50%;
40 | height: 50%;
41 | border-radius: 15px;
42 | }
43 | }
44 |
45 |
--------------------------------------------------------------------------------
/components/Welcome/SnowFAQ.module.scss:
--------------------------------------------------------------------------------
1 | @import '../../styles/colors/variables.scss';
2 |
3 | .faqContainer {
4 | button {
5 | display: flex;
6 | align-items: center;
7 | justify-content: center;
8 | width: 50px;
9 | height: 50px;
10 | background: transparent;
11 | color: #fff;
12 | font-size: 1.7em;
13 | border: none;
14 | outline: none;
15 | }
16 | .faq {
17 | width: 430px;
18 | height: 140px;
19 | border-radius: 15px;
20 | background: $black3;
21 | display: flex;
22 | align-items: center;
23 | justify-content: center;
24 | padding: 15px;
25 | transition: 0.3s;
26 | transform-origin: top left;
27 | &.closed {
28 | opacity: 0;
29 | transform: scale(0.9);
30 | }
31 | &.open {
32 | opacity: 1;
33 | transform: scale(1);
34 | }
35 | p {
36 | font-size: 1em;
37 | }
38 | }
39 | }
40 |
41 | @keyframes appear {
42 | from {
43 | opacity: 0;
44 | transform: scale(0.9);
45 | }
46 | to {
47 | opacity: 1;
48 | transform: scale(1);
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/hooks/useFirestore.ts:
--------------------------------------------------------------------------------
1 | import { useEffect } from "react";
2 | import { useState } from "react";
3 | import { projectFirestore } from "../config/firebase.config";
4 |
5 | export const useFirestore = (collection: string)=>{
6 | const [data, setData] = useState([]);
7 | const [isLoading, setIsLoading] = useState(false)
8 |
9 | useEffect(()=>{
10 | setIsLoading(true)
11 | const unsub = projectFirestore.collection(collection)
12 | .orderBy('createdAt', 'desc')
13 | .onSnapshot((snap: any)=>{
14 | let docs: any = [];
15 | snap.forEach((el: any)=>{
16 | docs.push({
17 | id: el.id,
18 | ...el.data()
19 | });
20 | });
21 | setData(docs);
22 | setTimeout(()=>{
23 | setIsLoading(false);
24 | },2000)
25 | });
26 |
27 | return ()=> unsub();
28 | },[collection])
29 |
30 | return {data, isLoading};
31 | }
--------------------------------------------------------------------------------
/hooks/useFollow.ts:
--------------------------------------------------------------------------------
1 | import axios from 'axios';
2 | import { useEffect } from 'react';
3 | import { useState } from 'react';
4 |
5 | export const useFollow = (loggedUser: any, id: string, friendReqs: any) => {
6 | const [isFollowed, setIsFollowed] = useState(false);
7 | const [isFriend, setIsFriend] = useState(false);
8 |
9 | useEffect(() => {
10 | if (friendReqs.includes(loggedUser._id)) {
11 | setIsFollowed(true);
12 | }
13 | if (loggedUser?.friends.includes(id)) {
14 | setIsFriend(true);
15 | }
16 | }, []);
17 |
18 | const handleFollow = async () => {
19 | try {
20 | if (!isFollowed) {
21 | await axios.put(`https://snow-net.herokuapp.com/api/users/${id}/follow`, {
22 | userId: loggedUser._id
23 | });
24 | setIsFollowed(true);
25 | } else {
26 | await axios.put(`https://snow-net.herokuapp.com/api/users/${id}/unfollow`, {
27 | userId: loggedUser._id
28 | });
29 | setIsFollowed(false);
30 | }
31 | } catch (err) {
32 | console.log(err);
33 | }
34 | };
35 |
36 | return handleFollow;
37 | };
38 |
--------------------------------------------------------------------------------
/components/Register/Errors/ErrorMessage.module.scss:
--------------------------------------------------------------------------------
1 | .message {
2 | min-width: 250px;
3 | max-width: 300px;
4 | min-height: 30px;
5 | display: flex;
6 | align-items: center;
7 | border-radius: 9px;
8 | background: #ffc5c5;
9 | position: absolute;
10 | position: relative;
11 | z-index: 5;
12 | top: -10px;
13 | animation: appear 0.4s;
14 | &::after {
15 | content: '';
16 | width: 0px;
17 | height: 0px;
18 | position: absolute;
19 | top: -10px;
20 | left: 8px;
21 | border-bottom: 15px solid #ffc5c5;
22 | border-right: 7.5px solid transparent;
23 | border-left: 7.5px solid transparent;
24 | }
25 | span {
26 | width: 50px;
27 | display: flex;
28 | align-items: center;
29 | justify-content: center;
30 | height: 100%;
31 | font-size: 1.3em;
32 | color: #fe4444;
33 | }
34 | p {
35 | font-size: 1em;
36 | color: #fe4444;
37 | font-weight: 600;
38 | }
39 | }
40 |
41 | @keyframes appear {
42 | from {
43 | transform: translateY(-5px);
44 | opacity: 0;
45 | }
46 | to {
47 | transform: translateY(0);
48 | opacity: 1;
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/components/Gallery/ImagePreview.tsx:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react';
2 | import { useEffect } from 'react';
3 | import { CgClose } from 'react-icons/cg';
4 | import styles from './ImagePreview.module.scss';
5 |
6 | interface Props {
7 | file?: any;
8 | gif?: string;
9 | setFile?: any;
10 | }
11 |
12 | export default function ImagePreview({ file, gif, setFile }: Props) {
13 | const [preview, setPreview] = useState('');
14 |
15 | const handleClick = () => {
16 | setFile(null);
17 | };
18 |
19 | useEffect(() => {
20 | if (file) {
21 | const reader = new FileReader();
22 | reader.onloadend = () => {
23 | setPreview(reader.result as string);
24 | };
25 | reader.readAsDataURL(file);
26 | }
27 | }, [file]);
28 |
29 | return (
30 |
31 |
32 |
33 |
34 |
35 |
36 | {file &&
}
37 | {gif &&
}
38 |
39 | );
40 | }
41 |
--------------------------------------------------------------------------------
/components/Loader.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import styles from './Loader.module.scss';
3 | import snowLogo from '../img/snow-logo.svg';
4 |
5 | interface Props {
6 | isLoading: boolean;
7 | }
8 |
9 | export default function Loader({ isLoading }: Props) {
10 | return (
11 | <>
12 |
13 |
14 |
15 |
19 |
20 |
27 |
SNOW
28 |
29 |
30 |
31 | >
32 | );
33 | }
34 |
--------------------------------------------------------------------------------
/components/Posts/Options/RepostCounter.module.scss:
--------------------------------------------------------------------------------
1 | .repost {
2 | display: flex;
3 | align-items: center;
4 | cursor: pointer;
5 | transition: 0.1s;
6 | overflow: hidden;
7 | span {
8 | display: flex;
9 | justify-items: center;
10 | align-items: center;
11 | padding: 6px;
12 | transition: 0.2s;
13 | border-radius: 50%;
14 | margin: 0 5px;
15 | }
16 | p {
17 | font-size: 1.2em;
18 | text-align: center;
19 | padding-top: 2.5px;
20 | }
21 | .repostContainer {
22 | height: 18px;
23 | overflow: hidden;
24 | min-width: 30px;
25 | }
26 | .reposted {
27 | color: #4bff87;
28 | }
29 | span.reposted {
30 | animation: reposted 0.5s;
31 | }
32 | &:hover {
33 | color: #4bff87;
34 | span {
35 | background: #4bff8720;
36 | }
37 | }
38 | }
39 |
40 | .goUp {
41 | display: inline-flex;
42 | transform: translate3d(0, -20px, 0);
43 | transition: 0.2s ease-in-out;
44 | }
45 |
46 | .waitDown {
47 | display: inline-flex;
48 | transform: translate3d(0, 20px, 0);
49 | }
50 |
51 | .initial {
52 | display: inline-flex;
53 | transform: translate3d(0, 0px, 0);
54 | transition: 0.2s ease-in-out;
55 | }
56 |
--------------------------------------------------------------------------------
/components/Countdown/SnowWelcome.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import StaggerTextChange from '../TextReveal/StaggerChange';
3 | import StaggerTextReveal from '../TextReveal/StaggerText';
4 | import styles from './SnowWelcome.module.scss';
5 |
6 | interface Props {
7 | launch: boolean;
8 | }
9 |
10 | export default function SnowWelcome({ launch }: Props) {
11 | return (
12 |
13 | {launch && (
14 |
15 |
31 |
32 | )}
33 |
34 | );
35 | }
36 |
--------------------------------------------------------------------------------
/components/Groups/SearchGroups.tsx:
--------------------------------------------------------------------------------
1 | import Router from 'next/router';
2 | import React, { useState } from 'react';
3 | import { BiPlus, BiSearch } from 'react-icons/bi';
4 | import styles from './SearchGroups.module.scss';
5 | import SearchGroupsModal from './SearchGroupsModal';
6 |
7 | export default function SearchGroups() {
8 | const [searchModal, setSearchModal] = useState(false);
9 | return (
10 | <>
11 | {searchModal && }
12 |
13 |
14 |
setSearchModal(true)}>
15 |
16 |
17 |
18 |
Search Groups
19 |
20 |
21 |
22 | Router.push('/groups/create')}>
23 |
24 |
25 | {' '}
26 | Create
27 |
28 |
29 |
30 | >
31 | );
32 | }
33 |
--------------------------------------------------------------------------------
/components/RequestPanel/PendingRequest.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { MdOutlineWatchLater } from 'react-icons/md';
3 | import styles from './PendingRequest.module.scss';
4 |
5 | export default function PendingRequest() {
6 | return (
7 |
8 |
9 |
13 |
John Doe
14 |
10:10
15 |
16 |
17 |
18 | {' '}
19 | Pending
20 |
21 |
22 |
23 |
24 | Lorem ipsum dolor, sit amet consectetur adipisicing elit. Culpa, sint!
25 |
26 |
27 |
28 | Decline
29 | Publish
30 |
31 |
32 | );
33 | }
34 |
--------------------------------------------------------------------------------
/components/ExploreContainer.tsx:
--------------------------------------------------------------------------------
1 | import styles from '../styles/explore.module.scss';
2 | import { AiOutlineSearch } from 'react-icons/ai';
3 | import React from 'react';
4 | import News from './Explore/News';
5 |
6 | export default function ExploreContainer() {
7 | return (
8 |
9 |
17 |
18 |
23 |
28 |
29 |
30 | );
31 | }
32 |
--------------------------------------------------------------------------------
/components/Posts/Poll.module.scss:
--------------------------------------------------------------------------------
1 | @import '../../styles/colors/variables.scss';
2 |
3 | .pollContainer{
4 | width: 100%;
5 | max-height: 150px;
6 | display: flex;
7 | padding: 5px 65px;
8 | .options{
9 | width: 100%;
10 | .option{
11 | display: flex;
12 | justify-content: space-between;
13 | align-items: center;
14 | width: 100%;
15 | background: $black3;
16 | padding: 5px 25px;
17 | position: relative;
18 | overflow: hidden;
19 | height: 48px;
20 | margin-top: 15px;
21 | border-radius: 5px;
22 | color: #ccc;
23 | cursor: pointer;
24 | .percentageSize{
25 | background: #ffffff20;
26 | transform: scaleX(0);
27 | transform-origin: left;
28 | animation: appear 0.6s forwards;
29 | }
30 | transition: .3s;
31 | &:hover{
32 | color: #fff;
33 | }
34 | span{
35 | z-index: 1;
36 | }
37 | p{
38 | color: #ccc;
39 | z-index: 1;
40 | }
41 | }
42 | }
43 | }
44 |
45 | @keyframes appear {
46 | from{
47 | transform: scaleX(0);
48 | } to{
49 | transform: scaleX(1);
50 | }
51 | }
--------------------------------------------------------------------------------
/components/RequestPanel/PendingList.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { MdOutlineSort } from 'react-icons/md';
3 | import { TiThSmall } from 'react-icons/ti';
4 | import styles from './PendingList.module.scss';
5 | import PendingRequest from './PendingRequest';
6 |
7 | export default function PendingList() {
8 | return (
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
Posts
17 |
{20} Posts
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
All
26 |
{36} Posts
27 |
28 |
29 |
30 |
33 |
34 | );
35 | }
36 |
--------------------------------------------------------------------------------
/components/Posts/Options/RepostCounter.tsx:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react';
2 | import { BiRepost } from 'react-icons/bi';
3 | import styles from './RepostCounter.module.scss';
4 |
5 | interface Props {
6 | isReposted: boolean;
7 | totalReposts: number;
8 | handleRepost: () => void;
9 | }
10 |
11 | export default function RepostConter({ isReposted, totalReposts, handleRepost }: Props) {
12 | const [reposts, setReposts] = useState(totalReposts);
13 | const [animationReposts, setAnimationReposts] = useState('initial');
14 |
15 | const handleReposts = () => {
16 | setTimeout(() => setAnimationReposts('goUp'), 0);
17 | setTimeout(() => setReposts(!isReposted ? reposts + 1 : reposts - 1), 100);
18 | setTimeout(() => setAnimationReposts('waitDown'), 100);
19 | setTimeout(() => setAnimationReposts('initial'), 200);
20 |
21 | handleRepost();
22 | };
23 |
24 | return (
25 |
26 |
27 |
28 |
29 |
30 |
31 | {reposts}
32 |
33 |
34 |
35 | );
36 | }
37 |
--------------------------------------------------------------------------------
/components/Explore/TrendingBar.module.scss:
--------------------------------------------------------------------------------
1 | @import '../../styles/colors/variables.scss';
2 |
3 | .trendingBarContainer{
4 | width: 500px;
5 | height: 100vh;
6 | position: fixed;
7 | top: 30px;
8 | left: 0;
9 | display: flex;
10 | align-items: center;
11 | flex-direction: column;
12 | .trendingNow{
13 | background: $black2;
14 | border-radius: 10px;
15 | margin-top: 75px;
16 | width: 400px;
17 | padding: 20px;
18 | h4{
19 | margin-bottom: 20px;
20 | margin-left: 5px;
21 | font-weight: 700;
22 | letter-spacing: 1px;
23 | font-size: 1.5em;
24 | }
25 | }
26 | }
27 |
28 | @media (max-width: 1500px){
29 | .trendingBarContainer{
30 | width: 450px;
31 | .trendingNow{
32 | width: 350px;
33 | }
34 | }
35 | }
36 |
37 | @media (max-width: 1200px){
38 | .trendingBarContainer{
39 | width: 100%;
40 | position: relative;
41 | top: auto;
42 | left: 0;
43 | right: 0;
44 | display: flex;
45 | justify-items: center;
46 | .trendingNow{
47 | max-width: 100vw;
48 | margin: 0;
49 | border-radius: 0;
50 | h4{
51 | font-size: 1.3em;
52 | margin-left: 0;
53 | }
54 | }
55 | }
56 | }
--------------------------------------------------------------------------------
/components/Responsive/TopBar.module.scss:
--------------------------------------------------------------------------------
1 | @import '../../styles/colors/variables.scss';
2 |
3 | .topBarContainer{
4 | width: 100%;
5 | height: 50px;
6 | background: $darkblue;
7 | position: fixed;
8 | top: 0;
9 | left: 0;
10 | z-index: 15;
11 | .icons{
12 | display: flex;
13 | justify-content: space-between;
14 | align-items: center;
15 | width: 100%;
16 | padding: 30px;
17 | padding-top: 7px;
18 | .snow{
19 | display: flex;
20 | justify-content: center;
21 | align-items: center;
22 | .logo{
23 | width: 22px;
24 | background-size: cover;
25 | object-fit: cover;
26 | }
27 | }
28 | h3{
29 | font-size: 1.4em;
30 | font-weight: 800;
31 | background: linear-gradient(90deg, $primary, $secondary);
32 | background-clip: text;
33 | -webkit-text-fill-color: transparent;
34 | }
35 | .user{
36 | display: flex;
37 | justify-content: center;
38 | align-items: center;
39 | .profile{
40 | border-radius: 50%;
41 | height: 32px;
42 | width: 32px;
43 | background-size: cover;
44 | object-fit: cover;
45 | }
46 | }
47 | }
48 | }
--------------------------------------------------------------------------------
/components/Register/PageDots.module.scss:
--------------------------------------------------------------------------------
1 | @import '../../styles/colors/variables.scss';
2 |
3 | .dotsContainer{
4 | display: flex;
5 | justify-content: center;
6 | align-items: center;
7 | width: 100%;
8 | height: 15px;
9 | padding-top: 35px;
10 | .dot{
11 | height: 19px;
12 | width: 19px;
13 | border: 2px solid #fff;
14 | background: #fff;
15 | margin: 0 15px;
16 | border-radius: 50%;
17 | color: #000;
18 | display: flex;
19 | justify-content: center;
20 | align-items: center;
21 | font-size: 0.7em;
22 | z-index: 5;
23 | transition: 0.5s;
24 | &.active{
25 | border: 2px solid $primary;
26 | background: $primary;
27 | }
28 | }
29 | span{
30 | width: 44%;
31 | position: absolute;
32 | height: 3px;
33 | background: #fff;
34 | z-index: 1;
35 | &::before{
36 | content: '';
37 | width: 30%;
38 | position: absolute;
39 | transition: 0.5s;
40 | height: 3px;
41 | background: $primary;
42 | z-index: 1;
43 | }
44 | &.one::before{
45 | width: 30%;
46 | }
47 | &.two::before{
48 | width: 45%;
49 | }
50 | &.three::before{
51 | width: 70%;
52 | }
53 | }
54 | }
--------------------------------------------------------------------------------
/components/Modals/Report.tsx:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react';
2 | import styles from '../Settings/modals/Modals.module.scss';
3 |
4 | interface Props {
5 | postId: string;
6 | setModalOpen: any;
7 | }
8 |
9 | export default function Report({ postId, setModalOpen }: Props) {
10 | const [report, setReport] = useState('');
11 |
12 | const handleChange = (e: React.ChangeEvent) => {
13 | setReport(e.target.value);
14 | };
15 |
16 | return (
17 |
18 |
19 |
Report Post
20 |
21 | If you think this post may be harmful, do not hesitate to send us your report.
22 |
23 |
29 |
30 | Send
31 | setModalOpen(false)}>
32 | Cancel
33 |
34 |
35 |
36 |
37 | );
38 | }
39 |
--------------------------------------------------------------------------------
/components/Layout.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { AuthProvider } from '../context/AuthContext';
3 | import styles from './Layout.module.scss';
4 | import Head from 'next/head';
5 | import Nav from './Nav/Nav';
6 | import ResponsiveNav from './Responsive/ResponsiveNav';
7 | import { useMediaQuery } from 'react-responsive';
8 | import TopBar from './Responsive/TopBar';
9 | import { useTouch } from '../hooks/useTouch';
10 |
11 | interface Props {
12 | title?: string;
13 | children: React.ReactNode;
14 | }
15 |
16 | export default function Layout({ title, children }: Props) {
17 | const isResponsive = useMediaQuery({ query: '(min-width: 1200px)' });
18 | const { handleTouchStart, handleTouchMove, handleTouchEnd, touch } = useTouch();
19 | touch;
20 | return (
21 | <>
22 |
23 | {title}
24 |
25 |
30 |
31 | {!isResponsive && }
32 | {isResponsive && }
33 | {children}
34 | {!isResponsive && }
35 |
36 |
37 | >
38 | );
39 | }
40 |
--------------------------------------------------------------------------------
/components/Posts/Comments/CommentOptions.tsx:
--------------------------------------------------------------------------------
1 | import axios from 'axios';
2 | import React from 'react';
3 | import { HiHeart, HiOutlineHeart } from 'react-icons/hi';
4 | import styles from './CommentOptions.module.scss';
5 |
6 | interface Props {
7 | userId: string;
8 | likes: any;
9 | loggedUser: any;
10 | image: string;
11 | comments: any;
12 | }
13 |
14 | export default function CommentOptions({ loggedUser, comments, likes, userId }: Props) {
15 | const handleLike = async () => {
16 | //await axios.put(`https://snow-net.herokuapp.com/api/posts/like`, {userId: loggedUser._id});
17 | };
18 |
19 | return (
20 |
21 |
22 | {likes.includes(loggedUser._id) ? (
23 |
24 |
25 |
26 | ) : (
27 |
28 |
29 |
30 | )}
31 |
32 | {likes.length}
33 |
34 |
35 |
36 | Reply
37 |
38 |
39 | );
40 | }
41 |
--------------------------------------------------------------------------------
/components/Posts/Comments/Comments.tsx:
--------------------------------------------------------------------------------
1 | import axios from 'axios';
2 | import React, { useState } from 'react';
3 | import { useEffect } from 'react';
4 | import AddComment from './AddComment';
5 | import Comment from './Comment';
6 | import styles from './Comments.module.scss';
7 |
8 | interface Props {
9 | loggedUser: any;
10 | postId: string;
11 | getComments: () => Promise;
12 | comments: any;
13 | }
14 |
15 | export default function Comments({ loggedUser, postId, getComments, comments }: Props) {
16 | return (
17 |
18 |
19 |
20 | {comments &&
21 | comments.map(
22 | ({ image, text, userId, createdAt, likes }: any, index: number) => (
23 |
32 | )
33 | )}
34 |
35 |
36 | );
37 | }
38 |
--------------------------------------------------------------------------------
/components/Chats/Message.tsx:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react';
2 | import OpenImage from '../OpenImage';
3 | import styles from './Message.module.scss';
4 |
5 | interface Props {
6 | text: string;
7 | received: boolean;
8 | createdAt: string;
9 | image: string | '' | undefined;
10 | }
11 |
12 | export default function Message({ text, received, createdAt, image }: Props) {
13 | const [imageOpen, setImageOpen] = useState(false);
14 |
15 | const handleClick = () => (imageOpen ? setImageOpen(false) : setImageOpen(true));
16 |
17 | return (
18 | <>
19 | {imageOpen && (
20 |
21 | )}
22 |
26 | {image ? (
27 |
28 |
29 | {text &&
{text}
}
30 |
{createdAt}
31 |
32 | ) : (
33 |
34 | {text}
35 | {createdAt}
36 |
37 | )}
38 |
39 | >
40 | );
41 | }
42 |
--------------------------------------------------------------------------------
/components/Options/OptionsBar.tsx:
--------------------------------------------------------------------------------
1 | import React, { useContext } from 'react';
2 | import styles from './OptionsBar.module.scss';
3 | import { CgProfile } from 'react-icons/cg';
4 | import { BsPeopleFill } from 'react-icons/bs';
5 | import { BiMessageDetail } from 'react-icons/bi';
6 | import { RiGalleryLine, RiSearchLine } from 'react-icons/ri';
7 | import Option from './Option';
8 | import AuthContext from '../../context/AuthContext';
9 | import { FaHandsHelping } from 'react-icons/fa';
10 |
11 | export default function OptionsBar() {
12 | const { loggedUser } = useContext(AuthContext);
13 |
14 | return (
15 |
16 |
17 | {loggedUser && (
18 |
23 | )}
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 | );
32 | }
33 |
--------------------------------------------------------------------------------
/components/Responsive/TopBar.tsx:
--------------------------------------------------------------------------------
1 | import React, { useContext, useState } from 'react';
2 | import AuthContext from '../../context/AuthContext';
3 | import { useTouch } from '../../hooks/useTouch';
4 | import styles from './TopBar.module.scss';
5 | import UserProfile from './UserProfile';
6 |
7 | interface Props {
8 | touch: string;
9 | }
10 |
11 | export default function TopBar({ touch }: Props) {
12 | const [isOpen, setIsOpen] = useState(false);
13 | const { loggedUser } = useContext(AuthContext);
14 |
15 | const handleOpen = () => (isOpen ? setIsOpen(false) : setIsOpen(true));
16 |
17 | return (
18 |
19 |
20 |
21 |
22 |
23 |
SNOW
24 |
25 | {loggedUser && (
26 |
32 | )}
33 |
34 |
35 |
36 |
37 | );
38 | }
39 |
--------------------------------------------------------------------------------
/db/post_list.ts:
--------------------------------------------------------------------------------
1 | export const postList = [
2 | {
3 | id: 1,
4 | hour: {
5 | number: "12:32",
6 | type: "AM"
7 | },
8 | user: {
9 | image: 'https://images.fineartamerica.com/images/artworkimages/mediumlarge/3/red-bird-pop-on-green-bill-tiepelman.jpg',
10 | name: 'John',
11 | lastname: 'Doe'
12 | },
13 | post: {
14 | text: 'First Post!',
15 | image: 'https://images.pexels.com/photos/66284/winter-nature-season-trees-66284.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=750&w=1260'
16 | }
17 | },
18 | {
19 | id: 2,
20 | hour: {
21 | number: "3:42",
22 | type: "PM"
23 | },
24 | user: {
25 | image: 'https://images.fineartamerica.com/images/artworkimages/mediumlarge/3/red-bird-pop-on-green-bill-tiepelman.jpg',
26 | name: 'John',
27 | lastname: 'Doe'
28 | },
29 | post: {
30 | text: 'Test Post',
31 | }
32 | },
33 | {
34 | id: 3,
35 | hour: {
36 | number: "3:42",
37 | type: "PM"
38 | },
39 | user: {
40 | image: 'https://images.fineartamerica.com/images/artworkimages/mediumlarge/3/red-bird-pop-on-green-bill-tiepelman.jpg',
41 | name: 'John',
42 | lastname: 'Doe'
43 | },
44 | post: {
45 | text: 'Test Post',
46 | }
47 | }
48 | ]
--------------------------------------------------------------------------------
/pages/settings.tsx:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react';
2 | import { useEffect } from 'react';
3 | import { useMediaQuery } from 'react-responsive';
4 | import Layout from '../components/Layout';
5 | import General from '../components/Settings/pages/General';
6 | import Language from '../components/Settings/pages/Language';
7 | import Privacy from '../components/Settings/pages/Privacy';
8 | import Security from '../components/Settings/pages/Security';
9 | import SettingsBar from '../components/Settings/SettingsBar';
10 | import SettingsComponent from '../components/Settings/SettingsComponent';
11 | import { AuthProvider } from '../context/AuthContext';
12 | import styles from '../styles/settings.module.scss';
13 |
14 | export default function Settings() {
15 | const [page, setPage] = useState(1);
16 | const isResponsive = useMediaQuery({ query: '(max-width: 1200px)' });
17 |
18 | useEffect(() => {
19 | if (isResponsive) {
20 | setPage(0);
21 | }
22 | }, [isResponsive]);
23 |
24 | return (
25 |
26 |
27 | {isResponsive && page === 0 &&
}
28 | {!isResponsive &&
}
29 |
30 |
31 |
32 |
33 |
34 | );
35 | }
36 |
--------------------------------------------------------------------------------
/pages/donations.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import DonationCard from '../components/Donations/DonationCard';
3 | import Layout from '../components/Layout';
4 | import styles from '../styles/donations.module.scss';
5 |
6 | export default function Donations() {
7 | return (
8 |
9 |
10 |
Donations
11 |
12 |
18 |
24 |
30 |
31 |
32 |
33 | );
34 | }
35 |
--------------------------------------------------------------------------------
/components/RowMsg.module.scss:
--------------------------------------------------------------------------------
1 | @import '../styles/colors/variables.scss';
2 | .rowContainer{
3 | width: 100%;
4 | height: 80px;
5 | display: flex;
6 | align-items: center;
7 | padding: 0 20px;
8 | position: relative;
9 | background: $black2;
10 | transition: background 0.2s;
11 | cursor: pointer;
12 | overflow: hidden;
13 | &:hover{
14 | background: $black2h;
15 | }
16 | span{
17 | position: absolute;
18 | border-radius: 50%;
19 | transform: translate(-50%,-50%);
20 | background: $black3h;
21 | animation: ripple .7s infinite;
22 | pointer-events: none;
23 | }
24 | img{
25 | height: 60px;
26 | width: 60px;
27 | border-radius: 50%;
28 | pointer-events: none;
29 | z-index: 2;
30 | object-fit: cover;
31 | }
32 | .info{
33 | margin-left: 40px;
34 | z-index: 2;
35 | pointer-events: none;
36 | h5{
37 | font-size: 1.05em;
38 | font-weight: 500;
39 | pointer-events: none;
40 | user-select: none;
41 | }
42 | p{
43 | font-size: 0.9em;
44 | color: #999;
45 | pointer-events: none;
46 | user-select: none;
47 | }
48 | }
49 | }
50 |
51 | @keyframes ripple{
52 | from{
53 | height: 0;
54 | width: 0;
55 | opacity: .5;
56 | }
57 | to{
58 | width: 500px;
59 | height: 500px;
60 | opacity: 0;
61 | }
62 | }
--------------------------------------------------------------------------------
/components/TextArea.module.scss:
--------------------------------------------------------------------------------
1 | @import '../styles/colors/variables.scss';
2 | $primary: #8bffff;
3 | $secondary: #0099ff;
4 |
5 |
6 | .textAreaContainer{
7 | position: relative;
8 | height: 200px;
9 | width: 22vw;
10 | margin-bottom: 2.5rem;
11 | display: flex;
12 | align-items: center;
13 | .textAreaComponent{
14 | position: absolute;
15 | top: 0;
16 | left: 0;
17 | color: #fff;
18 | font-size: 1em;
19 | width: 100%;
20 | height: 100%;
21 | display: block;
22 | background: transparent;
23 | border: none;
24 | background: $black3;
25 | outline: none;
26 | border-radius: 5px;
27 | transition: 0.35s;
28 | padding: 0 10px;
29 | padding-top: 25px;
30 | &:focus{
31 | background: $black3h;
32 | }
33 | &:focus ~ label{
34 | top: 5px;
35 | font-size: 0.9em !important;
36 | left: 10px;
37 | color: $primary;
38 | }
39 | &:not(:placeholder-shown).inputComponent:not(:focus) + .labelComponent{
40 | top: 5px;
41 | font-size: 0.9em !important;
42 | left: 10px;
43 | color: #999;
44 | }
45 | }
46 | .labelComponent{
47 | position: absolute;
48 | display: block;
49 | transition: .3s;
50 | top: 10%;
51 | left: 20px;
52 | font-size: 1.2em;
53 | text-align: center;
54 | background: transparent;
55 | color: #999;
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/components/OpenImage.module.scss:
--------------------------------------------------------------------------------
1 | .openImageContainer {
2 | top: 0;
3 | left: 0;
4 | position: fixed;
5 | width: 100%;
6 | height: 100vh;
7 | background: #00000020;
8 | z-index: 100;
9 | display: flex;
10 | justify-content: center;
11 | animation: blur 0.5s forwards;
12 | align-items: center;
13 | &.close {
14 | animation: unblur 0.3s forwards;
15 | }
16 | img {
17 | max-width: 800px;
18 | max-height: 90%;
19 | transform: scale(0);
20 | background-size: cover;
21 | object-fit: cover;
22 | animation: appear 0.25s forwards;
23 | &.close {
24 | animation: disappear 0.25s forwards;
25 | }
26 | }
27 | }
28 |
29 | @keyframes blur {
30 | from {
31 | backdrop-filter: blur(0px);
32 | background: transparent;
33 | }
34 | to {
35 | backdrop-filter: blur(10px);
36 | background: #00000045;
37 | }
38 | }
39 |
40 | @keyframes unblur {
41 | from {
42 | backdrop-filter: blur(10px);
43 | background: #00000045;
44 | }
45 | to {
46 | backdrop-filter: blur(0px);
47 | background: transparent;
48 | }
49 | }
50 |
51 | @keyframes appear {
52 | from {
53 | transform: scale(0.9);
54 | opacity: 0;
55 | }
56 | to {
57 | transform: scale(1);
58 | opacity: 1;
59 | }
60 | }
61 |
62 | @keyframes disappear {
63 | from {
64 | transform: scale(1);
65 | opacity: 1;
66 | }
67 | to {
68 | transform: scale(0.9);
69 | opacity: 0;
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/components/RequestPanel/PendingList.module.scss:
--------------------------------------------------------------------------------
1 | @import '../../styles/colors/variables.scss';
2 |
3 | .pendingListContainer{
4 | height: 100vh;
5 | width: 100%;
6 | display: flex;
7 | align-items: center;
8 | flex-direction: column;
9 | padding-top: 30px;
10 |
11 | .select{
12 | display: flex;
13 | .optionSelect{
14 | cursor: pointer;
15 | display: flex;
16 | height: 70px;
17 | margin-top: 5px;
18 | align-items: center;
19 | border-radius: 15px;
20 | transition: 0.3s;
21 | padding: 0 10px;
22 | margin: 0 70px;
23 | width: 25vw;
24 | background: $black2;
25 | &:hover{
26 | background: $black2h;
27 | }
28 | &:hover .icon{
29 | background: $black3h;
30 | }
31 | }
32 | .icon{
33 | height: 55px;
34 | width: 55px;
35 | background: $black3;
36 | border-radius: 50%;
37 | display: flex;
38 | justify-content: center;
39 | align-items: center;
40 | font-size: 2em;
41 | transition: 0.3s;
42 | }
43 | .selectText{
44 | padding-left: 15px;
45 | h4{
46 | color: #fff;
47 | font-size: 1.2em;
48 | }
49 | p{
50 | color: #999;
51 | font-size: 0.9em;
52 | }
53 | }
54 | }
55 | .pendingPosts{
56 | padding-top: 40px;
57 | }
58 | }
--------------------------------------------------------------------------------
/components/Posts/InputChoice.module.scss:
--------------------------------------------------------------------------------
1 | @import '../../styles/colors/variables.scss';
2 |
3 | .inputChoice{
4 | position: relative;
5 | padding: 5px 20px;
6 | display: flex;
7 | align-items: center;
8 | margin-bottom: 1.5rem;
9 | width: 20vw;
10 | height: 6vh;
11 | .inputComponent{
12 | position: absolute;
13 | top: 0;
14 | left: 0;
15 | font-family: 'Poppins', sans-serif;
16 | color: #fff;
17 | font-size: 1em;
18 | width: 100%;
19 | height: 100%;
20 | display: block;
21 | background: transparent;
22 | border: none;
23 | background: $black3;
24 | outline: none;
25 | border-radius: 5px;
26 | transition: 0.35s;
27 | padding: 0 10px;
28 | padding-top: 15px;
29 | &:focus{
30 | background: $black3h;
31 | }
32 | &:focus ~ label{
33 | top: 5px;
34 | font-size: 0.9em !important;
35 | left: 7px;
36 | color: $primary;
37 | }
38 | &:not(:placeholder-shown).inputComponent:not(:focus) + .labelComponent{
39 | top: 5px;
40 | font-size: 0.9em !important;
41 | left: 7px;
42 | color: #999;
43 | }
44 |
45 | }
46 | .labelComponent{
47 | position: absolute;
48 | display: block;
49 | transition: .3s;
50 | top: 27%;
51 | left: 20px;
52 | font-size: 1.05em;
53 | min-width: 65px;
54 | text-align: center;
55 | background: transparent;
56 | color: #999;
57 | }
58 | }
--------------------------------------------------------------------------------
/components/Posts/Comments/CommentDots.module.scss:
--------------------------------------------------------------------------------
1 | @import '../../../styles/colors/variables.scss';
2 |
3 | .commentDotsContainer{
4 | width: 100px;
5 | height: 50px;
6 | position: absolute;
7 | right: 185px;
8 | top: 26px;
9 | z-index: 5;
10 | .dots{
11 | color: #777;
12 | font-size: 1.2em;
13 | display: flex;
14 | justify-content: center;
15 | cursor: pointer;
16 | transition: color .2s;
17 | &:hover{
18 | color: #efefef;
19 | }
20 | }
21 | .options{
22 | width: 210px;
23 | border-radius: 15px;
24 | height: auto;
25 | background: $black3;
26 | animation: appear 0.4s;
27 | overflow: hidden;
28 | transform-origin: top;
29 | z-index: 7;
30 | .option{
31 | display: flex;
32 | justify-content: center;
33 | align-items: center;
34 | height: 50px;
35 | transition: background .3s;
36 | cursor: pointer;
37 | &.delete{
38 | color: #ff3939;
39 | }
40 | span{
41 | font-size: 1.35em;
42 | display: flex;
43 | justify-content: center;
44 | align-items: center;
45 | }
46 | p{
47 | padding: 10px;
48 | }
49 | &:hover{
50 | background: $black3h;
51 | }
52 | }
53 | }
54 | }
55 |
56 | @keyframes appear {
57 | from{
58 | opacity: 0;
59 | }
60 | to{
61 | opacity: 1;
62 | }
63 | }
--------------------------------------------------------------------------------
/components/Posts/Options/LikeCounter.module.scss:
--------------------------------------------------------------------------------
1 | @import '../../../styles/colors/variables.scss';
2 |
3 | .likes {
4 | display: flex;
5 | align-items: center;
6 | cursor: pointer;
7 | transition: 0.1s;
8 | overflow: hidden;
9 | span {
10 | display: flex;
11 | justify-items: center;
12 | align-items: center;
13 | padding: 6px;
14 | transition: 0.2s;
15 | border-radius: 50%;
16 | margin: 0 5px;
17 | }
18 | p {
19 | font-size: 1.2em;
20 | text-align: center;
21 | padding-top: 2.5px;
22 | }
23 | .likesContainer {
24 | height: 18px;
25 | overflow: hidden;
26 | min-width: 30px;
27 | }
28 | .isLiked {
29 | color: #ff4141;
30 | transform: scale(0.1);
31 | animation: liked 0.5s forwards;
32 | }
33 | p.liked {
34 | color: #ff4141;
35 | }
36 | &:hover {
37 | color: #ff4141;
38 | span {
39 | background: #ff414120;
40 | }
41 | }
42 | }
43 |
44 | .goUp {
45 | display: inline-flex;
46 | transform: translate3d(0, -20px, 0);
47 | transition: 0.2s ease-in-out;
48 | }
49 |
50 | .waitDown {
51 | display: inline-flex;
52 | transform: translate3d(0, 20px, 0);
53 | }
54 |
55 | .initial {
56 | display: inline-flex;
57 | transform: translate3d(0, 0px, 0);
58 | transition: 0.2s ease-in-out;
59 | }
60 |
61 | @keyframes liked {
62 | 0% {
63 | transform: scale(1);
64 | }
65 | 50% {
66 | transform: scale(1.3);
67 | }
68 | 100% {
69 | transform: scale(1);
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/components/UserProfile/Photos.tsx:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react';
2 | import { useEffect } from 'react';
3 | import { MdOutlineNoPhotography } from 'react-icons/md';
4 | import styles from './Photos.module.scss';
5 |
6 | interface Props {
7 | userData: any;
8 | }
9 |
10 | export default function Photos({ userData }: Props) {
11 | const [dataImage, setDataImage] = useState([]);
12 |
13 | useEffect(() => {
14 | if (userData.posts) {
15 | setDataImage(
16 | userData.posts
17 | .filter((post: any) => post.image)
18 | .reverse()
19 | .slice(0, 6)
20 | );
21 | } else {
22 | setDataImage(
23 | userData
24 | .filter((post: any) => post.image)
25 | .reverse()
26 | .slice(0, 6)
27 | );
28 | }
29 | dataImage;
30 | }, [userData]);
31 |
32 | return (
33 |
34 |
Photos
35 |
36 | {dataImage.map(({ image }: any, index: number) => (
37 |
38 | ))}
39 |
40 | {dataImage.length < 1 && (
41 |
42 |
43 |
44 |
45 |
This profile has no photos yet
46 |
47 | )}
48 |
49 | );
50 | }
51 |
--------------------------------------------------------------------------------
/components/Gallery/GalleryImage.tsx:
--------------------------------------------------------------------------------
1 | import Link from 'next/link';
2 | import Router from 'next/router';
3 | import React, { useState } from 'react';
4 | import { BsDownload } from 'react-icons/bs';
5 | import { HiOutlineHeart } from 'react-icons/hi';
6 | import styles from './GalleryImage.module.scss';
7 | import ImageModal from './ImageModal';
8 |
9 | interface Props {
10 | img: string;
11 | user: any;
12 | }
13 |
14 | export default function GalleryImage({ img, user }: Props) {
15 | const [modalOpen, setModalOpen] = useState(false);
16 |
17 | const handleUserClick = () => Router.push(`/user/${user.username}`);
18 | const handleClick = () => setModalOpen(true);
19 |
20 | return (
21 | <>
22 | {modalOpen && }
23 |
24 |
25 |
26 |
27 |
28 |
{user.name}
29 |
30 |
38 |
39 |
40 | >
41 | );
42 | }
43 |
--------------------------------------------------------------------------------
/components/RequestPanel/Sidebar.module.scss:
--------------------------------------------------------------------------------
1 | @import '../../styles/colors/variables.scss';
2 |
3 | .sidebarContainer{
4 | height: 100vh;
5 | background: $black2;
6 | width: 28vw;
7 | h2{
8 | padding: 0 40px;
9 | padding-top: 50px;
10 | }
11 | .options{
12 | display: flex;
13 | align-items: center;
14 | flex-direction: column;
15 | width: 100%;
16 | height: 100%;
17 | padding: 30px 30px;
18 | .option{
19 | width: 100%;
20 | display: flex;
21 | height: 70px;
22 | margin-top: 5px;
23 | align-items: center;
24 | border-radius: 15px;
25 | transition: 0.3s;
26 | padding: 0 10px;
27 | cursor: pointer;
28 | &:hover{
29 | background: $black2h;
30 | }
31 | &:hover .icon{
32 | background: $black3h;
33 | }
34 | .icon{
35 | height: 45px;
36 | width: 45px;
37 | background: $black3;
38 | border-radius: 50%;
39 | display: flex;
40 | justify-content: center;
41 | align-items: center;
42 | font-size: 1.8em;
43 | transition: 0.3s;
44 | }
45 | .text{
46 | padding-left: 15px;
47 | h4{
48 | color: #fff;
49 | }
50 | p{
51 | color: #999;
52 | font-size: 0.9em;
53 | }
54 | }
55 | }
56 | }
57 | }
--------------------------------------------------------------------------------
/hooks/usePosts.ts:
--------------------------------------------------------------------------------
1 | import axios from 'axios';
2 | import { useEffect, useState } from 'react';
3 |
4 | interface Props {
5 | type: string;
6 | }
7 |
8 | export const usePosts = ({ type }: Props) => {
9 | const [posts, setPosts] = useState([]);
10 | const [loader, setLoader] = useState(false);
11 | const [isLimit, setIsLimit] = useState(false);
12 | const [offset, setOffset] = useState(10);
13 |
14 | let data: any;
15 |
16 | const fetchData = async () => {
17 | try {
18 | setLoader(true);
19 | data = await axios.get(`https://snow-net.herokuapp.com/api/posts/get/all/0/${offset}`);
20 | if (data.data === 'limit') {
21 | setIsLimit(true);
22 | return;
23 | }
24 | setPosts([...data.data]);
25 | setLoader(false);
26 | } catch (err) {
27 | console.log(err);
28 | }
29 | };
30 |
31 | const loadMorePosts = async () => {
32 | ('loadMore');
33 | setLoader(true);
34 | data = await axios.get(`https://snow-net.herokuapp.com/api/posts/get/all/${10}/${offset}`);
35 | if (data.data === 'limit') {
36 | setIsLimit(true);
37 | return;
38 | }
39 | setPosts((oldPosts: any) => oldPosts.concat(data.data));
40 | setLoader(false);
41 | };
42 |
43 | useEffect(() => {
44 | if (isLimit) return;
45 | loadMorePosts();
46 | }, [offset]);
47 |
48 | return {
49 | posts,
50 | fetchData,
51 | loadMorePosts,
52 | loader,
53 | setOffset,
54 | offset,
55 | isLimit
56 | };
57 | };
58 |
--------------------------------------------------------------------------------
/components/Register/PageTwo.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import Input from '../Input';
3 | import ErrorMessage from './Errors/ErrorMessage';
4 |
5 | interface Props {
6 | handleChange: () => void;
7 | values: any;
8 | register: any;
9 | errors: any;
10 | isResponsive: boolean;
11 | }
12 |
13 | export default function PageTwo({ handleChange, values, register, errors, isResponsive }: Props) {
14 | return (
15 | <>
16 |
30 | {errors.password && }
31 |
45 | {errors.reppassword && }
46 | >
47 | );
48 | }
49 |
--------------------------------------------------------------------------------
/components/Nav/Nav.tsx:
--------------------------------------------------------------------------------
1 | import NavLink from 'next/link';
2 | import Router from 'next/router';
3 | import React, { useContext } from 'react';
4 | import AuthContext from '../../context/AuthContext';
5 | import styles from './Nav.module.scss';
6 | import ProfileNav from './ProfileNav';
7 |
8 | export default function Nav() {
9 | const { loggedUser } = useContext(AuthContext);
10 |
11 | return (
12 | <>
13 |
14 |
Router.push('/')}>
15 |
16 |
SNOW
17 |
18 |
19 |
24 |
25 |
26 | Messages
27 |
28 |
29 |
30 |
31 | Groups
32 |
33 |
34 |
35 |
36 | Gallery
37 |
38 |
39 |
42 |
43 |
44 | >
45 | );
46 | }
47 |
--------------------------------------------------------------------------------
/hooks/useGiphy.ts:
--------------------------------------------------------------------------------
1 | import { ChangeEvent, FormEvent, useEffect, useState } from "react"
2 | import axios from "axios";
3 |
4 | const key = "Y5MruqgDFFiY2XLwfRGEXRpCm8RZbeCC";
5 |
6 | export const useGiphy = ()=>{
7 | const [giphy, setGiphy] = useState(null)
8 | const [search, setSearch] = useState('');
9 | const [isLoading, setIsLoading] = useState(true);
10 |
11 | useEffect(()=>{
12 | const useFetch = async ()=>{
13 | setIsLoading(true);
14 | const data = await axios('https://api.giphy.com/v1/gifs/trending', {
15 | params: {
16 | api_key: key,
17 | limit: 30
18 | }
19 | });
20 | setGiphy(data.data.data)
21 | setIsLoading(false);
22 | };
23 | useFetch()
24 | },[]);
25 |
26 | const handleChange = (e: ChangeEvent)=>{
27 | setSearch(e.target.value)
28 | }
29 | const handleSubmit = (e: FormEvent)=>{
30 | e.preventDefault()
31 | const useFetch = async ()=>{
32 | setIsLoading(true);
33 | const data = await axios(`https://api.giphy.com/v1/gifs/search`,{
34 | params:{
35 | api_key: key,
36 | q: search
37 | }
38 | })
39 | setGiphy(data.data.data);
40 | setIsLoading(false);
41 | }
42 | useFetch();
43 | }
44 |
45 | return {
46 | handleChange,
47 | handleSubmit,
48 | giphy,
49 | search,
50 | isLoading
51 | }
52 | }
--------------------------------------------------------------------------------
/components/Input.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import styles from './Input.module.scss';
3 |
4 | interface Props {
5 | type: string;
6 | label: string;
7 | name: string;
8 | bg?: string;
9 | size: {
10 | width: number | string;
11 | height: number | string;
12 | fontSize: number;
13 | };
14 | value: string;
15 | inputRef: any;
16 | handleChange: (e: React.ChangeEvent, type: string) => void;
17 | error: any;
18 | }
19 |
20 | export default function Input({
21 | type,
22 | label,
23 | name,
24 | bg,
25 | size,
26 | value,
27 | handleChange,
28 | inputRef,
29 | error
30 | }: Props) {
31 | return (
32 |
38 | handleChange(e, name)}
45 | placeholder=" "
46 | style={{
47 | fontSize: size.fontSize,
48 | background: bg
49 | }}
50 | />
51 |
56 | {!error?.message ? label : error.message}
57 |
58 |
59 | );
60 | }
61 |
--------------------------------------------------------------------------------
/components/ChatInfo.tsx:
--------------------------------------------------------------------------------
1 | import React, { useEffect, useState } from 'react';
2 | import styles from './ChatInfo.module.scss';
3 | import { BiDotsVerticalRounded } from 'react-icons/bi';
4 | import { AiOutlineArrowLeft, AiOutlineSearch } from 'react-icons/ai';
5 | import { useMediaQuery } from 'react-responsive';
6 |
7 | interface Props {
8 | img: string;
9 | name: string;
10 | lastname: string;
11 | setCurrentChat: any;
12 | }
13 |
14 | export default function ChatInfo({ img, name, lastname, setCurrentChat }: Props) {
15 | const [optionsOpen, setOptionsOpen] = useState(false);
16 | const isResponsive = useMediaQuery({ query: '(min-width: 1200px)' });
17 |
18 | const handleClick = () => (optionsOpen ? setOptionsOpen(false) : setOptionsOpen(true));
19 |
20 | return (
21 |
22 | {!isResponsive && (
23 |
setCurrentChat('')} className={styles.back}>
24 |
25 |
26 | )}
27 |
28 |
29 |
{`${name} ${lastname}`}
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 | Mute
41 | Delete Chat
42 |
43 |
44 | );
45 | }
46 |
--------------------------------------------------------------------------------
/components/Gallery/ImageModal.tsx:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react';
2 | import { useEffect } from 'react';
3 | import { BsDownload } from 'react-icons/bs';
4 | import { HiOutlineHeart } from 'react-icons/hi';
5 | import styles from './ImageModal.module.scss';
6 | import { projectStorage } from '../../config/firebase.config';
7 |
8 | interface Props {
9 | img: string;
10 | user: any;
11 | setModalOpen: React.Dispatch>;
12 | }
13 |
14 | export default function ImageModal({ img, user, setModalOpen }: Props) {
15 | const [downloadURL, setDownloadURL] = useState('');
16 | const handleClick = () => setModalOpen(false);
17 |
18 | useEffect(() => {
19 | if (img)
20 | projectStorage
21 | .refFromURL(img)
22 | .getDownloadURL()
23 | .then((url: string) => setDownloadURL(url));
24 | }, []);
25 |
26 | return (
27 |
28 |
29 |
30 |
31 |
32 |
{user.name}
33 |
@{user.username}
34 |
35 |
36 |
37 |
45 |
46 |
47 | );
48 | }
49 |
--------------------------------------------------------------------------------
/components/Register/PageOne.tsx:
--------------------------------------------------------------------------------
1 | import Link from 'next/link';
2 | import React from 'react';
3 | import Input from '../Input';
4 | import ErrorMessage from './Errors/ErrorMessage';
5 | import styles from './PageOne.module.scss';
6 |
7 | interface Props {
8 | handleChange: () => void;
9 | values: any;
10 | register: any;
11 | errors: any;
12 | isResponsive: boolean;
13 | }
14 |
15 | export default function PageOne({ handleChange, values, register, errors, isResponsive }: Props) {
16 | return (
17 | <>
18 |
32 | {errors.username && }
33 |
47 | {errors.email && }
48 |
49 |
50 | Have an account already? Log in
51 |
52 |
53 | >
54 | );
55 | }
56 |
--------------------------------------------------------------------------------
/components/Groups/GroupMembers.tsx:
--------------------------------------------------------------------------------
1 | import axios from 'axios';
2 | import Router from 'next/router';
3 | import React, { useState } from 'react';
4 | import { useEffect } from 'react';
5 | import styles from './GroupMembers.module.scss';
6 |
7 | interface Props {
8 | members: [string];
9 | }
10 |
11 | export default function GroupMembers({ members }: Props) {
12 | const [membersData, setMembersData] = useState([]);
13 |
14 | useEffect(() => {
15 | const fetchMembersData = async () => {
16 | try {
17 | const membersGroup: any = [];
18 | members.slice(0, 6).map(async (userId) => {
19 | const data = await axios.get(
20 | `https://snow-net.herokuapp.com/api/users/${userId}`
21 | );
22 | membersGroup.push(data.data);
23 | setMembersData([...membersGroup]);
24 | });
25 | } catch (err) {
26 | console.log(err);
27 | }
28 | };
29 | fetchMembersData();
30 | }, []);
31 |
32 | return (
33 |
34 |
Members
35 |
36 | {membersData.map((member: any) => (
37 |
Router.push('/user/' + member.username)}>
41 |
42 |
43 |
44 | {member.name} {member.lastname}
45 |
46 |
47 |
48 | ))}
49 |
50 |
51 | );
52 | }
53 |
--------------------------------------------------------------------------------
/components/Posts/PostDots.tsx:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react';
2 | import styles from './PostDots.module.scss';
3 | import { HiDotsHorizontal } from 'react-icons/hi';
4 | import { RiUserFollowLine, RiVolumeMuteLine, RiDeleteBin5Line, RiEditLine } from 'react-icons/ri';
5 | import { MdBlock, MdOutlineReport } from 'react-icons/md';
6 | import { AiOutlinePushpin } from 'react-icons/ai';
7 | import axios from 'axios';
8 | import ConfirmDelete from './ConfirmDelete';
9 | import { useRef } from 'react';
10 | import { MutableRefObject } from 'react';
11 |
12 | interface Props {
13 | username: string;
14 | loggedUserId: string;
15 | userId: string;
16 | postId: string;
17 | fetchData: () => Promise;
18 | handleModal: () => void;
19 | deletePost: () => Promise;
20 | handleEdit: () => void;
21 | handleReport: () => void;
22 | isOpen: boolean;
23 | setIsOpen: any;
24 | }
25 |
26 | export default function PostDots({
27 | username,
28 | userId,
29 | loggedUserId,
30 | handleModal,
31 | postId,
32 | fetchData,
33 | handleEdit,
34 | handleReport,
35 | isOpen,
36 | setIsOpen
37 | }: Props) {
38 | const handleClick = () => {
39 | isOpen ? setIsOpen(false) : setIsOpen(true);
40 | };
41 |
42 | const handlePin = async () => {
43 | try {
44 | await axios.put(`https://snow-net.herokuapp.com/api/posts/pin/${postId}`);
45 | fetchData();
46 | } catch (err) {
47 | console.log(err);
48 | }
49 | };
50 |
51 | return (
52 | <>
53 |
54 |
55 |
56 |
57 |
58 | >
59 | );
60 | }
61 | function setPickerOpen(arg0: boolean): void {
62 | throw new Error('Function not implemented.');
63 | }
64 |
--------------------------------------------------------------------------------
/hooks/useEmojiPicker.ts:
--------------------------------------------------------------------------------
1 | import React, { useEffect, useRef, useState } from 'react';
2 | import axios from 'axios';
3 | import { emojis } from '../data/emojis.data';
4 |
5 | export const useEmojiPicker = () => {
6 | const [currentCategory, setCurrentCategory] = useState('people');
7 |
8 | const emojiRef = useRef(null) as React.MutableRefObject;
9 |
10 | useEffect(() => {
11 | emojiRef.current.scrollTo(0, 0);
12 | }, [currentCategory]);
13 |
14 | const activityList = emojis.filter((emoji) => emoji.category === 'Activity'),
15 | peopleList = emojis.filter((emoji) => emoji.category === 'Smileys & People'),
16 | natureList = emojis.filter((emoji) => emoji.category === 'Animals & Nature'),
17 | symbolList = emojis.filter((emoji) => emoji.category === 'Symbols'),
18 | foodList = emojis.filter((emoji) => emoji.category === 'Food & Drink'),
19 | objectList = emojis.filter((emoji) => emoji.category === 'Objects'),
20 | travelList = emojis.filter((emoji) => emoji.category === 'Travel & Places');
21 |
22 | const handleCategory = (category: string) => {
23 | emojiRef.current.scrollTo(100, emojiRef.current.scrollHeight);
24 | if (category === 'activity') setCurrentCategory('activity');
25 | else if (category === 'people') setCurrentCategory('people');
26 | else if (category === 'symbols') setCurrentCategory('symbols');
27 | else if (category === 'animals') setCurrentCategory('animals');
28 | else if (category === 'food') setCurrentCategory('food');
29 | else if (category === 'objects') setCurrentCategory('objects');
30 | else setCurrentCategory('travel');
31 | };
32 |
33 | return {
34 | activityList,
35 | peopleList,
36 | natureList,
37 | symbolList,
38 | foodList,
39 | objectList,
40 | travelList,
41 | currentCategory,
42 | handleCategory,
43 | emojiRef
44 | };
45 | };
46 |
--------------------------------------------------------------------------------
/components/Settings/SettingsBar.module.scss:
--------------------------------------------------------------------------------
1 | @import '../../styles/colors/variables.scss';
2 |
3 | .sidebarContainer{
4 | height: 91vh;
5 | background: $black2;
6 | width: 450px;
7 | animation: appear 0.8s;
8 | h2{
9 | padding: 0 40px;
10 | padding-top: 50px;
11 | }
12 | .options{
13 | display: flex;
14 | align-items: center;
15 | flex-direction: column;
16 | width: 100%;
17 | height: 100%;
18 | padding: 30px 30px;
19 | .option{
20 | width: 100%;
21 | display: flex;
22 | height: 70px;
23 | margin-top: 5px;
24 | align-items: center;
25 | border-radius: 15px;
26 | transition: 0.3s;
27 | padding: 0 10px;
28 | cursor: pointer;
29 | &:hover{
30 | background: $black2h;
31 | }
32 | &:hover .icon{
33 | background: $black3h;
34 | }
35 | .icon{
36 | height: 45px;
37 | width: 45px;
38 | background: $black3;
39 | border-radius: 50%;
40 | display: flex;
41 | justify-content: center;
42 | align-items: center;
43 | font-size: 1.8em;
44 | transition: 0.3s;
45 | }
46 | .text{
47 | padding-left: 15px;
48 | h4{
49 | color: #fff;
50 | }
51 | p{
52 | color: #999;
53 | font-size: 0.9em;
54 | }
55 | }
56 | }
57 | }
58 | }
59 |
60 | @media (max-width: 1200px) {
61 | .sidebarContainer{
62 | position: fixed;
63 | top: 35px;
64 | left: 0;
65 | bottom: 0;
66 | right: 0;
67 | width: 100vw;
68 | }
69 | }
70 |
71 | @keyframes appear {
72 | from{
73 | opacity: 0;
74 | } to{
75 | opacity: 1;
76 | }
77 | }
--------------------------------------------------------------------------------
/components/Settings/modals/EditModal.tsx:
--------------------------------------------------------------------------------
1 | import axios from 'axios';
2 | import React, { useState } from 'react';
3 | import { CgClose } from 'react-icons/cg';
4 | import styles from './Modals.module.scss';
5 |
6 | interface Props {
7 | type?: string;
8 | value: string;
9 | setIsOpen:
10 | | React.Dispatch>
11 | | React.Dispatch>;
12 | title: string;
13 | postId: string;
14 | userId: string;
15 | setText?: any;
16 | }
17 |
18 | export default function EditModal({
19 | type,
20 | value,
21 | setIsOpen,
22 | title,
23 | userId,
24 | postId,
25 | setText
26 | }: Props) {
27 | const [inputVal, setInputVal] = useState(value);
28 |
29 | const updatePost = async () => {
30 | setText(inputVal);
31 | try {
32 | await axios.put(`https://snow-net.herokuapp.com/api/posts/${postId}`, {
33 | userId,
34 | text: inputVal
35 | });
36 | setIsOpen('');
37 | } catch (err) {
38 | console.log(err);
39 | }
40 | };
41 |
42 | const handleChange = (e: React.ChangeEvent) => {
43 | setInputVal(e.target.value);
44 | };
45 |
46 | return (
47 |
48 | {/*
setIsOpen(false)}/> */}
49 |
50 |
{title}
51 |
52 |
53 | setIsOpen('')}>
54 | Cancel
55 |
56 |
57 | Save
58 |
59 |
60 |
61 |
62 | );
63 | }
64 |
--------------------------------------------------------------------------------
/components/Settings/SettingsBar.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { IoLanguageSharp, IoSettingsOutline } from 'react-icons/io5';
3 | import { MdPrivacyTip, MdShield } from 'react-icons/md';
4 | import styles from './SettingsBar.module.scss';
5 |
6 | interface Props {
7 | setPage: React.Dispatch
>;
8 | }
9 |
10 | export default function SettingsBar({ setPage }: Props) {
11 | return (
12 |
13 |
Settings
14 |
15 |
setPage(1)}>
16 |
17 |
18 |
19 |
20 |
General
21 |
22 |
23 |
setPage(2)}>
24 |
25 |
26 |
27 |
28 |
Login & Security
29 |
30 |
31 |
setPage(3)}>
32 |
33 |
34 |
35 |
36 |
Privacy
37 |
38 |
39 |
setPage(4)}>
40 |
41 |
42 |
43 |
44 |
Language & Region
45 |
46 |
47 |
48 |
49 | );
50 | }
51 |
--------------------------------------------------------------------------------
/components/Posts/PostDots.module.scss:
--------------------------------------------------------------------------------
1 | @import '../../styles/colors/variables.scss';
2 |
3 | .postDotsContainer{
4 | width: 50px;
5 | height: 50px;
6 | right: 20px;
7 | top: 20px;
8 | position: absolute;
9 | z-index: 20 !important;
10 | .dots{
11 | color: #777;
12 | font-size: 1.45em;
13 | display: flex;
14 | justify-content: center;
15 | cursor: pointer;
16 | transition: color .2s;
17 | &:hover{
18 | color: #efefef;
19 | }
20 | }
21 | }
22 | .options{
23 | width: 210px;
24 | height: auto;
25 | background: $black4;
26 | animation: appear 0.4s;
27 | transform-origin: top;
28 | position: absolute;
29 | z-index: 20;
30 | border-radius: 15px;
31 | overflow: hidden;
32 | &.reposted{
33 | margin-top: 25px;
34 | }
35 | .option{
36 | display: flex;
37 | justify-content: center;
38 | align-items: center;
39 | height: 50px;
40 | transition: background .3s;
41 | cursor: pointer;
42 | border-radius: 15px;
43 | &.delete{
44 | color: #ff3939;
45 | }
46 | span{
47 | font-size: 1.35em;
48 | display: flex;
49 | justify-content: center;
50 | align-items: center;
51 | }
52 | p{
53 | text-align: center;
54 | display: flex;
55 | padding: 10px;
56 | }
57 | &:hover{
58 | background: $black4h;
59 | }
60 | }
61 | }
62 | @media (max-width: 1200px){
63 | .options{
64 | bottom: 54px;
65 | border-radius: 0;
66 | left: 0;
67 | right: 0;
68 | position: fixed;
69 | width: 100%;
70 | background: $black3;
71 | min-height: 130px;
72 | max-height: 200px;
73 | .option{
74 | width: 100%;
75 | height: 50px;
76 | }
77 | }
78 | }
79 |
80 | @keyframes appear {
81 | from{
82 | opacity: 0;
83 | }
84 | to{
85 | opacity: 1;
86 | }
87 | }
--------------------------------------------------------------------------------
/pages/_app.tsx:
--------------------------------------------------------------------------------
1 | import '../styles/globals.css';
2 | import 'react-loader-spinner/dist/loader/css/react-spinner-loader.css';
3 | import type { AppProps } from 'next/app';
4 | import Loader from '../components/Loader';
5 | import { DetailedHTMLProps, ImgHTMLAttributes, useEffect, useState } from 'react';
6 | import { useRouter } from 'next/router';
7 | import RouteLoader from '../components/RouteLoader';
8 | import Progress from '../components/Progress/Progress';
9 | import { useRouteLoading } from '../hooks/useRouteLoading';
10 | import 'slick-carousel/slick/slick.css';
11 | import 'slick-carousel/slick/slick-theme.css';
12 | import Head from 'next/head';
13 |
14 | declare global {
15 | namespace JSX {
16 | interface IntrinsicElements {
17 | img: DetailedHTMLProps, HTMLImageElement>;
18 | }
19 | }
20 | }
21 |
22 | function MyApp({ Component, pageProps }: AppProps) {
23 | const [isLoading, setIsLoading] = useState(true);
24 | const setIsAnimating = useRouteLoading((s) => s.setIsAnimating);
25 | const isAnimating = useRouteLoading((s) => s.isAnimating);
26 |
27 | useEffect(() => {
28 | setTimeout(() => {
29 | setIsLoading(false);
30 | }, 1200);
31 | }, []);
32 |
33 | const router = useRouter();
34 |
35 | useEffect(() => {
36 | const handleStart = () => {
37 | setIsAnimating(true);
38 | };
39 | const handleStop = () => {
40 | setIsAnimating(false);
41 | };
42 |
43 | router.events.on('routeChangeStart', handleStart);
44 | router.events.on('routeChangeComplete', handleStop);
45 |
46 | return () => {
47 | router.events.off('routeChangeStart', handleStart);
48 | router.events.off('routeChangeComplete', handleStop);
49 | };
50 | }, [router]);
51 |
52 | return (
53 | <>
54 |
55 |
56 | {isLoading || }
57 | >
58 | );
59 | }
60 |
61 | export default MyApp;
62 |
--------------------------------------------------------------------------------
/styles/404.module.scss:
--------------------------------------------------------------------------------
1 |
2 | .errContainer{
3 | display: flex;
4 | justify-content: center;
5 | align-items: center;
6 | flex-direction: column;
7 | text-align: center;
8 | position: fixed;
9 | top: 0;
10 | left: 0;
11 | width: 100%;
12 | height: 100%;
13 | .bg{
14 | position: absolute;
15 | top: 0;
16 | left: 0;
17 | width: 100%;
18 | height: 100%;
19 | background: url(https://images.pexels.com/photos/346529/pexels-photo-346529.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=750&w=1260);
20 | filter: brightness(0.5);
21 | }
22 | .errorDesign{
23 | position: relative;
24 | padding-top: 100px;
25 | h2{
26 | font-size: 300px;
27 | margin: 0;
28 | padding: 0;
29 | font-weight: 400;
30 | line-height: 305px;
31 | }
32 | h3{
33 | font-size: 2.5em;
34 | font-weight: 400;
35 | letter-spacing: 7px;
36 | }
37 | }
38 | .backButton{
39 | z-index: 1;
40 | padding-top: 120px;
41 | button{
42 | background: #fff;
43 | border-radius: 30px;
44 | height: 5vh;
45 | width: 20vw;
46 | border: none;
47 | font-family: 'Poppins', sans-serif;
48 | font-size: 1.4em;
49 | font-weight: 400;
50 | position: relative;
51 | display: flex;
52 | justify-content: center;
53 | align-items: center;
54 | padding-left: 30px;
55 | transition: 0.3s;
56 | background: #c4f3ff;
57 | &:hover{
58 | background: #b4efff;
59 | }
60 | &:hover span{
61 | transform: translateX(10px);
62 | }
63 | span{
64 | font-size: 1.6em;
65 | display: flex;
66 | justify-content: center;
67 | align-items: center;
68 | margin-left: 20px;
69 | transition: 0.3s;
70 | }
71 | }
72 | }
73 | }
--------------------------------------------------------------------------------
/img/snow-logo.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/404/snow-logo.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/snow-logo-white.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/snow-logo.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/gallery/snow-logo.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/groups/snow-logo.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/user/snow-logo.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/verified/snow-logo.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/components/Responsive/img/snow-logo.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/components/UserProfile/MutualFriends.tsx:
--------------------------------------------------------------------------------
1 | import axios from 'axios';
2 | import Router from 'next/router';
3 | import React, { useState } from 'react';
4 | import { useEffect } from 'react';
5 | import styles from './MutualFriends.module.scss';
6 |
7 | const friendTest = [
8 | {
9 | profilePic:
10 | 'https://64.media.tumblr.com/bf6d23a043cdaed72255a1b2618d6f68/5acc2aa945774f0b-0e/s540x810/df05b83f7d5a36d5b56173c1ce3fcbdb877048e3.png',
11 | name: 'Quaddom Developer'
12 | },
13 | {
14 | profilePic:
15 | 'https://64.media.tumblr.com/bf6d23a043cdaed72255a1b2618d6f68/5acc2aa945774f0b-0e/s540x810/df05b83f7d5a36d5b56173c1ce3fcbdb877048e3.png',
16 | name: 'Quaddom Developer'
17 | }
18 | ];
19 |
20 | export default function MutualFriends({ friends }: any) {
21 | const [friendsData, setFriendsData] = useState([]);
22 |
23 | useEffect(() => {
24 | const getFriendsData = async () => {
25 | const userFriends: any = [];
26 | friends.map(async (id: string) => {
27 | const fetchFriendData = async () => {
28 | const data = await axios.get(`https://snow-net.herokuapp.com/api/users/${id}`);
29 | userFriends.push(data.data);
30 | setFriendsData([...userFriends]);
31 | };
32 | fetchFriendData();
33 | });
34 | };
35 | getFriendsData();
36 | }, [friends]);
37 |
38 | return (
39 |
40 |
Friends
41 |
42 |
43 | {friendsData.map(({ profilePic, name, username, _id }: any, index: number) => (
44 |
Router.push(`${username}`, undefined, { shallow: true })}
47 | key={_id}>
48 |
49 |
{name}
50 |
51 | ))}
52 |
53 |
54 | );
55 | }
56 |
--------------------------------------------------------------------------------
/components/Groups/GroupMembers.module.scss:
--------------------------------------------------------------------------------
1 | @import '../../styles/colors/variables.scss';
2 |
3 | .members {
4 | width: 450px;
5 | min-height: 300px;
6 | border-radius: 10px;
7 | padding: 40px 31px;
8 | position: sticky;
9 | margin-top: 30px;
10 | top: 420px;
11 | left: 60px;
12 | background: $black2;
13 | h4 {
14 | font-size: 1.5em;
15 | font-weight: 500;
16 | padding-bottom: 10px;
17 | padding: 0 10px;
18 | }
19 | .grid {
20 | display: grid;
21 | grid-template-columns: repeat(3, 100px);
22 | grid-template-rows: repeat(2, 150px);
23 | width: 390px;
24 | height: 100%;
25 | padding: 0 10px;
26 | padding-top: 10px;
27 | border-radius: 15px;
28 | overflow: hidden;
29 | grid-gap: 6px;
30 | .member {
31 | display: flex;
32 | align-items: center;
33 | justify-content: center;
34 | flex-direction: column;
35 | transition: 0.3s;
36 | border-radius: 10px;
37 | cursor: pointer;
38 | img {
39 | position: relative;
40 | height: 90px;
41 | width: 90px;
42 | object-fit: cover;
43 | background-size: cover;
44 | border-radius: 50%;
45 | }
46 | .info {
47 | display: flex;
48 | align-items: center;
49 | justify-content: center;
50 | flex-direction: column;
51 | h6 {
52 | font-size: 0.9em;
53 | min-height: 40px;
54 | max-height: 40px;
55 | padding-top: 8px;
56 | text-align: center;
57 | width: 100%;
58 | }
59 | }
60 | &:hover {
61 | background: $black2h;
62 | }
63 | }
64 | }
65 | }
66 |
67 | @media (max-width: 1500px) {
68 | .members {
69 | width: 350px;
70 | min-height: 300px;
71 | position: sticky;
72 | top: 100px;
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/hooks/useLogin.ts:
--------------------------------------------------------------------------------
1 | import axios from 'axios';
2 | import Router, { useRouter } from 'next/router';
3 | import React, { useEffect, useState } from 'react';
4 |
5 | interface User {
6 | email: string;
7 | password: string;
8 | }
9 |
10 | export const useLogin = () => {
11 | const [email, setEmail] = useState('');
12 | const [password, setPassword] = useState('');
13 | const [token, setToken] = useState(null);
14 |
15 | const handleChangeLog = async (e: React.ChangeEvent, inputType: string) => {
16 | if (inputType === 'email') setEmail(e.target.value);
17 | else if (inputType === 'password') setPassword(e.target.value);
18 | };
19 |
20 | const emailValidationApi = async () => {
21 | try {
22 | const message = await axios.post('https://snow-net.herokuapp.com/api/auth/email', {
23 | email
24 | });
25 | if (message.data) return true;
26 | else return false;
27 | } catch (err) {
28 | console.log(err);
29 | }
30 | };
31 |
32 | const passwordValidationApi = async () => {
33 | try {
34 | const isValid = await axios.post('https://snow-net.herokuapp.com/api/auth/password', {
35 | email,
36 | password
37 | });
38 | return isValid.data;
39 | } catch (err) {
40 | console.log(err);
41 | }
42 | };
43 |
44 | const handleSubmitLog = async (update: boolean, loggedUser: any) => {
45 | try {
46 | const res = await axios.post('https://snow-net.herokuapp.com/api/auth/login', {
47 | email,
48 | password
49 | });
50 | setToken(res.data);
51 | } catch (err) {
52 | console.log(err);
53 | } finally {
54 | Router.push('/');
55 | }
56 | };
57 |
58 | return {
59 | handleChangeLog,
60 | handleSubmitLog,
61 | token,
62 | emailValidationApi,
63 | passwordValidationApi,
64 | valuesLog: {
65 | email,
66 | password
67 | }
68 | };
69 | };
70 |
--------------------------------------------------------------------------------
/pages/_document.tsx:
--------------------------------------------------------------------------------
1 | import { Html, Head, Main, NextScript } from 'next/document';
2 |
3 | export default function Document() {
4 | return (
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
17 |
18 |
19 |
20 |
24 |
25 |
26 |
27 |
28 |
34 |
39 |
40 |
41 |
42 |
43 |
44 |
45 | );
46 | }
47 |
--------------------------------------------------------------------------------
/components/Settings/pages/Language.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { AiOutlineArrowLeft } from 'react-icons/ai';
3 | import { BiWorld } from 'react-icons/bi';
4 | import { BsFillPeopleFill } from 'react-icons/bs';
5 | import { IoLanguage } from 'react-icons/io5';
6 | import { useMediaQuery } from 'react-responsive';
7 | import styles from './PageStyle.module.scss';
8 |
9 | interface Props {
10 | setPage: React.Dispatch>;
11 | loggedUser: any;
12 | }
13 |
14 | export default function Language({ setPage }: Props) {
15 | const isResponsive = useMediaQuery({ query: '(min-width: 1200px)' });
16 | return (
17 |
18 | {!isResponsive && (
19 |
setPage(0)} className={styles.back}>
20 |
21 |
22 | )}
23 |
Language & Region
24 |
25 |
26 |
27 |
28 |
29 |
30 | {' '}
31 | Snow Language
32 |
33 |
English
34 |
Edit
35 |
36 |
37 |
38 |
39 |
40 | {' '}
41 | Region
42 |
43 |
Argentina
44 |
Edit
45 |
46 |
47 |
48 |
49 |
50 | {' '}
51 | Auto Translate Posts
52 |
53 |
English
54 |
Edit
55 |
56 |
57 |
58 | );
59 | }
60 |
--------------------------------------------------------------------------------
/components/Groups/SearchGroups.module.scss:
--------------------------------------------------------------------------------
1 | @import '../../styles/colors/variables.scss';
2 |
3 | .searchGroups{
4 | width: 650px;
5 | position: absolute;
6 | right: 100px;
7 | display: flex;
8 | align-items: center;
9 | justify-content: center;
10 | top: 115px;
11 | .containerSearch{
12 | display: flex;
13 | align-items: center;
14 | .inputContainer{
15 | display: flex;
16 | z-index: 10;
17 | align-items: center;
18 | position: relative;
19 | width: 300px;
20 | height: 40px;
21 | background: transparent;
22 | border: 2px solid #fff;
23 | color: #fff;
24 | border-radius: 10px;
25 | cursor: pointer;
26 | transition: background .3s;
27 | &:hover{
28 | background: #ffffff20;
29 | }
30 | .icon{
31 | font-size: 1.5em;
32 | color: #e9e9e9;
33 | width: 22%;
34 | display: flex;
35 | align-items: center;
36 | justify-content: center;
37 | }
38 | p{
39 | width: 80%;
40 | color: #e9e9e9;
41 | }
42 | }
43 | }
44 | .create{
45 | width: 200px;
46 | display: flex;
47 | align-items: center;
48 | justify-content: center;
49 | z-index: 10;
50 | button{
51 | display: flex;
52 | align-items: center;
53 | justify-content: center;
54 | width: 120px;
55 | height: 40px;
56 | border-radius: 10px;
57 | border: 2px solid #fff;
58 | color: #fff;
59 | font-weight: 500;
60 | font-size: 1em;
61 | background: transparent;
62 | transition: 0.3s;
63 | padding-right: 10px;
64 | span{
65 | font-size: 1.3em;
66 | display: flex;
67 | justify-content: center;
68 | align-items: center;
69 | margin: 0 5px;
70 | }
71 | &:hover{
72 | background: #ffffff20;
73 | }
74 | }
75 | }
76 | }
--------------------------------------------------------------------------------