├── .gitignore
├── .prettierrc.js
├── README.md
├── components
├── AddPostModal
│ ├── index.js
│ └── styles.module.scss
├── AppHeader
│ ├── index.js
│ └── styles.module.scss
├── AppSidebar
│ ├── index.js
│ └── styles.module.scss
├── ContactList
│ ├── index.js
│ └── styles.module.scss
├── Container.js
├── EditProfileBtn
│ ├── index.js
│ └── styles.module.scss
├── HomeLayout
│ ├── index.js
│ └── styles.module.scss
├── InboxScreen
│ ├── index.js
│ └── styles.module.scss
├── Loader
│ ├── index.js
│ └── styles.module.scss
├── MessageContent
│ ├── index.js
│ └── styles.module.scss
├── MessageFooter
│ ├── index.js
│ └── styles.module.scss
├── MessageHeader
│ ├── index.js
│ └── styles.module.scss
├── MessageListItem
│ ├── index.js
│ └── styles.module.scss
├── MessageSection
│ ├── index.js
│ └── styles.module.scss
├── NewMessageModal
│ ├── index.js
│ └── styles.module.scss
├── NoMessage
│ ├── index.js
│ └── styles.module.scss
├── NotFoundScreen
│ └── index.js
├── Profile
│ ├── index.js
│ └── styles.module.scss
├── ProfileFollowButton
│ ├── index.js
│ └── styles.module.scss
├── SearchResults
│ ├── index.js
│ └── styles.module.scss
├── SignInScreen
│ ├── index.js
│ └── styles.module.scss
├── SignUpScreen
│ ├── index.js
│ └── styles.module.scss
├── StoriesBar
│ ├── index.js
│ └── styles.module.scss
├── StoryItem
│ ├── index.js
│ └── styles.module.scss
├── SugessionUser
│ ├── index.js
│ └── styles.module.scss
├── UserImage
│ ├── index.js
│ └── styles.module.scss
├── UserInfo
│ ├── index.js
│ └── styles.module.scss
├── UserPost
│ ├── index.js
│ └── styles.module.scss
├── UserPosts
│ ├── index.js
│ └── styles.module.scss
└── UserStatistics
│ ├── index.js
│ └── styles.module.scss
├── hooks
├── usePostsFormat.js
└── useWindowSize.js
├── icons
├── AddPost.js
├── Back.js
├── Bookmark.js
├── BookmarkFill.js
├── Camera.js
├── Close.js
├── Comment.js
├── Emoji.js
├── Explore.js
├── ExploreFill.js
├── Home.js
├── HomeFill.js
├── Info.js
├── Like.js
├── LikeFill.js
├── Loader.js
├── Message.js
├── MessageFill.js
├── NewMessage.js
├── Options.js
├── Photo.js
├── Posts.js
├── Preferences.js
├── Search.js
├── Tagged.js
├── User.js
└── index.js
├── lib
├── auth.js
├── db.js
└── firebase.js
├── next.config.js
├── next.config.template.js
├── package-lock.json
├── package.json
├── pages
├── 404.js
├── [username]
│ └── [[...index]].js
├── _app.js
├── accounts
│ └── emailsignup.js
├── api
│ └── hello.js
├── direct
│ └── [[...index]].js
└── index.js
├── public
├── betul.jpg
├── bill.jpg
├── elon.jpg
├── erkan.jpg
├── erkan2.jpg
├── facebook-logo.png
├── favicon.ico
├── hasan.jpg
├── instagram-dark.png
├── instagram.png
├── ivana.jpg
├── manifest.json
├── mustafa.jpg
├── owuzan.jpg
├── owuzan
│ ├── 1.jpg
│ ├── 10.jpg
│ ├── 11.jpg
│ ├── 2.jpg
│ ├── 3.jpg
│ ├── 4.jpg
│ ├── 5.jpg
│ ├── 6.jpg
│ ├── 7.jpg
│ ├── 8.jpg
│ └── 9.jpg
├── photo-example.jpg
├── robots.txt
├── ronaldo.jpg
├── serdar.jpg
├── sign-up.png
├── suleyman-example.jpg
├── suleyman.jpg
└── user.jpg
├── styles
└── globals.scss
├── svgs
├── AddPost.svg
├── Back.svg
├── Bookmark.svg
├── BookmarkFill.svg
├── Camera.svg
├── Close.svg
├── Comment.svg
├── Emoji.svg
├── Explore.svg
├── ExploreFill.svg
├── Home.svg
├── HomeFill.svg
├── Info.svg
├── Like.svg
├── LikeFill.svg
├── Loader.svg
├── Message.svg
├── MessageFill.svg
├── NewMessage.svg
├── Options.svg
├── Photo.svg
├── Posts.svg
├── Preferences.svg
├── Search.svg
├── Tagged.svg
└── User.svg
├── utility
├── follow.js
├── isFollowing.js
├── linkedText.js
├── sendMessage.js
└── unfollow.js
└── yarn.lock
/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 | .idea
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 | # testing
8 | /coverage
9 |
10 | # next.js
11 | /.next/
12 | /out/
13 |
14 | # production
15 | /build
16 |
17 | # misc
18 | .DS_Store
19 | *.pem
20 |
21 | # debug
22 | npm-debug.log*
23 | yarn-debug.log*
24 | yarn-error.log*
25 |
26 | # local env files
27 | .env.local
28 | .env.development.local
29 | .env.test.local
30 | .env.production.local
31 | next.config.js
32 |
33 | # vercel
34 | .vercel
35 |
--------------------------------------------------------------------------------
/.prettierrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | trailingComma: 'es5',
3 | tabWidth: 4,
4 | semi: false,
5 | singleQuote: true,
6 | bracketSpacing: true,
7 | }
8 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app).
2 |
3 | ## Getting Started
4 |
5 | First, run the development server:
6 |
7 | ```bash
8 | npm run dev
9 | # or
10 | yarn dev
11 | ```
12 |
13 | Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
14 |
15 | You can start editing the page by modifying `pages/index.js`. The page auto-updates as you edit the file.
16 |
17 | [API routes](https://nextjs.org/docs/api-routes/introduction) can be accessed on [http://localhost:3000/api/hello](http://localhost:3000/api/hello). This endpoint can be edited in `pages/api/hello.js`.
18 |
19 | The `pages/api` directory is mapped to `/api/*`. Files in this directory are treated as [API routes](https://nextjs.org/docs/api-routes/introduction) instead of React pages.
20 |
21 | ## Learn More
22 |
23 | To learn more about Next.js, take a look at the following resources:
24 |
25 | - [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
26 | - [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
27 |
28 | You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome!
29 |
30 | ## Deploy on Vercel
31 |
32 | The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/import?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
33 |
34 | Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details.
35 |
--------------------------------------------------------------------------------
/components/AddPostModal/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import styles from './styles.module.scss'
3 |
4 | import UserImage from '../UserImage'
5 | import * as Icons from '../../icons'
6 |
7 | import { uploadPost } from '../../lib/db'
8 | import { useAuth } from '../../lib/auth'
9 |
10 | const AddPostModal = (props) => {
11 | const { file, setFile } = props
12 | const user = useAuth().user
13 | const [caption, setCaption] = React.useState('')
14 |
15 | const handleShare = async () => {
16 | uploadPost(user.id, {
17 | file,
18 | caption,
19 | time: new Date(),
20 | })
21 | setFile(null)
22 | setCaption('')
23 | }
24 | if (file) {
25 | return (
26 |
27 |
28 |
34 | Yeni Gönderi
35 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
51 |
52 |
53 | {file ?
})
: ''}
54 |
55 |
56 |
61 |
62 | )
63 | }
64 | return
65 | }
66 |
67 | export default AddPostModal
68 |
--------------------------------------------------------------------------------
/components/AddPostModal/styles.module.scss:
--------------------------------------------------------------------------------
1 | .newPost {
2 | position: fixed;
3 | left: 0;
4 | top: 0;
5 | bottom: 0;
6 | right: 0;
7 | background-color: var(--white);
8 | z-index: 10;
9 | }
10 | .newPostHeader {
11 | display: flex;
12 | justify-content: space-between;
13 | align-items: center;
14 | padding: 0 15px;
15 | height: 44px;
16 | width: 100%;
17 | box-shadow: var(--shadow);
18 | border-bottom: 2px solid var(--border-color);
19 | }
20 | .closeIcon {
21 | all: unset;
22 | font-size: 24px;
23 | cursor: pointer;
24 | transform: rotate(-90deg);
25 | }
26 | .title {
27 | font-weight: 500;
28 | }
29 | .shareButton {
30 | all: unset;
31 | cursor: pointer;
32 | color: var(--blue);
33 | font-style: 24px;
34 | font-weight: 500;
35 | }
36 | .postDescription {
37 | display: flex;
38 | padding: 15px;
39 | align-items: flex-start;
40 | }
41 | .user {
42 | }
43 | .caption {
44 | flex: 1;
45 | textarea {
46 | width: 100%;
47 | padding: 3px 10px;
48 | font-size: 16px;
49 | border: 0;
50 | font-family: inherit;
51 | outline: 0;
52 | height: 100px;
53 | }
54 | }
55 | .image {
56 | max-width: 50px;
57 | height: auto;
58 |
59 | img {
60 | width: 100%;
61 | height: 100%;
62 | object-fit: contain;
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/components/AppHeader/styles.module.scss:
--------------------------------------------------------------------------------
1 | header.header {
2 | background-color: var(--white);
3 | border-bottom: 1px solid var(--border-color);
4 | max-height: 54px;
5 | height: 100%;
6 | padding: 0 15px;
7 | @media (max-width: 599.98px) {
8 | // box-shadow: 0 10px 10px -10px rgba(0, 0, 0, .15);
9 | position: fixed;
10 | top: 0;
11 | left: 0;
12 | right: 0;
13 | z-index: 10;
14 | }
15 |
16 | .headerInner {
17 | padding: 9px 0;
18 | display: flex;
19 | align-items: center;
20 | justify-content: space-between;
21 | color: var(--text-color);
22 |
23 | a {
24 | color: inherit;
25 | }
26 | .brand {
27 | @media (min-width: 600px) {
28 | max-width: 360px;
29 | }
30 | width: 100%;
31 | height: inherit;
32 | display: flex;
33 | justify-content: space-between;
34 |
35 | a {
36 | padding-top: 7px;
37 | }
38 | img {
39 | object-fit: contain;
40 | height: 29px;
41 | width: auto;
42 | // transform: translateY(7px);
43 | }
44 | }
45 | .searchArea {
46 | position: relative;
47 | input {
48 | height: 28px;
49 | width: 214px;
50 | background-color: var(--input-background);
51 | border: 1px solid var(--border-color);
52 | border-radius: 3px;
53 | outline: 0;
54 | padding: 0 1rem;
55 | color: inherit;
56 |
57 | &::placeholder {
58 | color: var(--border-color);
59 | text-align: center;
60 | }
61 | }
62 |
63 | button {
64 | all: unset;
65 | cursor: pointer;
66 | position: absolute;
67 | right: 5px;
68 | top: 50%;
69 | transform: translateY(-50%);
70 | width: 1.5em;
71 | height: 1.5em;
72 | font-size: 12px;
73 | background-color: red;
74 | display: flex;
75 | border-radius: 50px;
76 | background-color: var(--border-color);
77 | justify-content: center;
78 | color: var(--white);
79 |
80 | span {
81 | --top: -2px;
82 | position: absolute;
83 | top: var(--top);
84 | &:last-child {
85 | top: calc(var(--top) + 6px);
86 | }
87 | }
88 | }
89 | @media (max-width: 999.98px) {
90 | margin-right: 40px;
91 | }
92 | @media (max-width: 599.98px) {
93 | display: none;
94 | }
95 | }
96 | .navbar {
97 | display: flex;
98 | flex: 1;
99 | justify-content: flex-end;
100 | nav {
101 | svg path {
102 | fill: var(--text);
103 | }
104 | display: flex;
105 | margin-top: -22px;
106 | margin-left: -22px;
107 |
108 | & > a,
109 | & > div {
110 | font-size: 1.5rem;
111 | margin-top: 22px;
112 | margin-left: 22px;
113 | display: flex;
114 | align-items: center;
115 | justify-content: center;
116 | position: relative;
117 | }
118 |
119 | .profileDropdown {
120 | position: absolute;
121 | top: calc(100% + 15px);
122 | right: -10px;
123 | display: none;
124 | flex-direction: column;
125 | background-color: var(--white);
126 | box-shadow: 0 0 5px 0px rgba(0, 0, 0, 0.15);
127 | width: 230px;
128 | border-radius: 5px;
129 |
130 | &.show {
131 | display: flex;
132 | }
133 |
134 | &::before {
135 | content: "";
136 | width: 15px;
137 | height: 15px;
138 | display: block;
139 | transform: rotate(45deg);
140 | background-color: var(--white);
141 | top: -7px;
142 | right: 15px;
143 | position: absolute;
144 | z-index: 0;
145 | box-shadow: 0 0 5px 0px rgba(0, 0, 0, 0.15);
146 | }
147 |
148 | a {
149 | z-index: 1;
150 | padding: 8px 16px;
151 | font-size: 14px;
152 | display: flex;
153 | text-decoration: none;
154 | align-items: center;
155 | background-color: var(--white);
156 |
157 | &:first-child {
158 | border-radius: 5px 5px 0 0;
159 | }
160 |
161 | &:last-child {
162 | border-radius: 0 0 5px 5px;
163 | }
164 |
165 | &:hover {
166 | background-color: var(--background-color);
167 | }
168 |
169 | div {
170 | margin-right: 10px;
171 | }
172 | }
173 | }
174 | }
175 |
176 | &.mobile {
177 | nav {
178 | position: fixed;
179 | left: 0;
180 | bottom: 0;
181 | right: 0;
182 | background-color: var(--white);
183 | border-top: 1px solid var(--border-color);
184 | justify-content: space-around;
185 | height: 50px;
186 | margin: 0;
187 | padding: 0;
188 | z-index: 1;
189 |
190 | a {
191 | margin: 0;
192 | flex: 1;
193 | }
194 | }
195 | }
196 | }
197 | }
198 | }
199 | .logoutLink {
200 | border-top: 2px solid var(--border-color);
201 | }
202 |
--------------------------------------------------------------------------------
/components/AppSidebar/index.js:
--------------------------------------------------------------------------------
1 | import styles from './styles.module.scss'
2 | import UserImage from '../UserImage'
3 | import SuggessionUser from '../SugessionUser'
4 | import { getUserData } from '../../lib/db'
5 | import { useAuth } from '../../lib/auth'
6 | import React from 'react'
7 |
8 | export default function AppSidebar() {
9 | const { user } = useAuth()
10 | const [userData, setUserData] = React.useState('')
11 |
12 | React.useEffect(async () => {
13 | setUserData(await getUserData(await user?.id))
14 | }, [user])
15 | return (
16 |
17 |
18 |
19 |
20 |
{userData.username}
21 |
{userData.name}
22 |
23 |
24 |
25 |
26 |
27 |
Senin İçin Öneriler
28 |
29 |
30 |
31 | -
32 |
37 |
38 | -
39 |
44 |
45 | -
46 |
51 |
52 | -
53 |
58 |
59 | -
60 |
65 |
66 |
67 |
68 |
108 |
109 | )
110 | }
111 |
--------------------------------------------------------------------------------
/components/AppSidebar/styles.module.scss:
--------------------------------------------------------------------------------
1 | .sidebarInner {
2 | position: sticky;
3 | top: 0px;
4 | }
5 |
6 | .changeBar {
7 | padding-top: 18px;
8 | display: flex;
9 | justify-content: space-between;
10 | align-items: center;
11 | font-size: 14px;
12 | color: var(--text);
13 |
14 | .userMeta {
15 | width: 141px;
16 | display: flex;
17 | flex-direction: column;
18 | p {
19 | margin: 0;
20 | font-weight: 500;
21 | }
22 | span {
23 | color: var(--muted-text);
24 | }
25 | }
26 |
27 | button {
28 | all: unset;
29 | cursor: pointer;
30 | color: var(--blue);
31 | font-weight: 500;
32 | font-size: 12px;
33 | }
34 | }
35 |
36 | .suggested {
37 | margin-top: 12px;
38 |
39 | .suggestedHeader {
40 | padding-top: 12px;
41 | font-weight: 500;
42 | font-size: 12px;
43 | display: flex;
44 | align-items: center;
45 | justify-content: space-between;
46 |
47 | p {
48 | color: var(--muted-text);
49 | font-size: 14px;
50 | }
51 |
52 | button {
53 | all: unset;
54 | color: var(--text);
55 | cursor: pointer;
56 | font-weight: 500;
57 | }
58 | }
59 |
60 | ul {
61 | margin: 0;
62 | margin-top: 8px;
63 | padding: 8px 0;
64 | list-style: none;
65 |
66 | li {
67 | display: flex;
68 | align-items: center;
69 | justify-content: space-between;
70 | margin-bottom: 10px;
71 | padding: 2px 0;
72 |
73 | &:last-child {
74 | margin-bottom: 0;
75 | }
76 |
77 | button {
78 | all: unset;
79 | cursor: pointer;
80 | color: var(--blue);
81 | font-size: 12px;
82 | font-weight: 500;
83 | }
84 | }
85 | }
86 | }
87 |
88 | .instagramFooter {
89 | margin-top: 25px;
90 | font-size: 11px;
91 | color: #c7c7c7;
92 |
93 | a {
94 | color: inherit;
95 | text-decoration: none;
96 | }
97 |
98 | ul {
99 | list-style: none;
100 | display: flex;
101 | flex-wrap: wrap;
102 | li {
103 | &::after {
104 | content: "\00B7";
105 | margin: 0 0.25em 0 0.25em;
106 | }
107 |
108 | &:last-child::after {
109 | content: unset;
110 | }
111 | }
112 | }
113 |
114 | .footerText {
115 | text-transform: uppercase;
116 | margin-top: 20px;
117 | }
118 | }
119 |
--------------------------------------------------------------------------------
/components/ContactList/index.js:
--------------------------------------------------------------------------------
1 | import styles from './styles.module.scss'
2 | import MessageListItem from '../MessageListItem'
3 |
4 | export default function ContactList(props) {
5 | const activeContact = props?.activeContact
6 | const setActiveContact = props?.setActiveContact
7 | const contacts = props?.contacts
8 | const setContacts = props?.setContacts
9 | const activeHandle = props?.activeHandle
10 |
11 | return (
12 |
13 |
14 | {contacts.map((contact, index) => {
15 | index++
16 | return (
17 |
activeHandle(e, contact.id)}
20 | className={
21 | activeContact === contact.id
22 | ? styles.contact +
23 | ' ' +
24 | styles.activeContact
25 | : styles.contact
26 | }
27 | >
28 |
29 |
30 | )
31 | })}
32 |
33 |
34 | )
35 | }
36 |
--------------------------------------------------------------------------------
/components/ContactList/styles.module.scss:
--------------------------------------------------------------------------------
1 | .contactListWrapper {
2 | flex: 1;
3 | padding: 8px 0 0 0;
4 | overflow-x: hidden;
5 | overflow-y: auto;
6 |
7 | .contactList {
8 | list-style: none;
9 | margin: 0;
10 | padding: 0;
11 |
12 | .contact {
13 | &:hover {
14 | background-color: var(--background-color);
15 | cursor: pointer;
16 | }
17 | &.activeContact {
18 | background-color: var(--border-light-color);
19 | }
20 | }
21 |
22 | a {
23 | padding: 8px 20px;
24 | display: flex;
25 | align-items: center;
26 | text-decoration: none;
27 | overflow: hidden;
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/components/Container.js:
--------------------------------------------------------------------------------
1 | export default function Container({ children, ...props }) {
2 | return (
3 |
4 | {children}
5 |
6 | )
7 | }
8 |
--------------------------------------------------------------------------------
/components/EditProfileBtn/index.js:
--------------------------------------------------------------------------------
1 | import styles from './styles.module.scss'
2 |
3 | export default function EditProfileBtn() {
4 | return (
5 |
6 | )
7 | }
8 |
--------------------------------------------------------------------------------
/components/EditProfileBtn/styles.module.scss:
--------------------------------------------------------------------------------
1 | .editProfileBtn {
2 | margin-left: 20px;
3 | font-size: 14px;
4 | border: 1px solid var(--border-color);
5 | color: inherit;
6 | border-radius: 4px;
7 | font-weight: 600;
8 | padding: 5px 9px;
9 | background-color: var(--background-color) !important;
10 | outline: 0;
11 |
12 | @media (max-width: 734.98px) {
13 | margin: 15px;
14 | display: block;
15 | width: calc(100% - 30px);
16 | background-color: var(--white) !important;
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/components/HomeLayout/index.js:
--------------------------------------------------------------------------------
1 | import Head from 'next/head'
2 | import UserPost from '../UserPost'
3 | import React, { useState, useEffect } from 'react'
4 | import AppSidebar from '../AppSidebar'
5 | import styles from './styles.module.scss'
6 | import StoriesBar from '../StoriesBar'
7 | import firebase from '../../lib/firebase'
8 | import { useAuth } from '../../lib/auth'
9 | import { getUserData } from '../../lib/db'
10 | import { ClipLoader } from 'react-spinners'
11 | import { css } from '@emotion/core'
12 |
13 | export default function Home() {
14 | const [posts, setPosts] = useState([])
15 | const [loading, setLoading] = useState(true)
16 | const firestore = firebase.firestore()
17 | const auth = useAuth()
18 |
19 | useEffect(async () => {
20 | let userPosts = []
21 | await firestore
22 | .collection(`users/${auth.user.id}/followings`)
23 | .get()
24 | .then((res) =>
25 | res.docs.forEach(async (user) => {
26 | const username = await getUserData(user.id).then(
27 | (res) => res.username
28 | )
29 | await firestore
30 | .collection(`users/${user.id}/posts`)
31 | .orderBy('time', 'desc')
32 | .limit(10)
33 | .get()
34 | .then((res) => {
35 | if (res.docs.length) {
36 | res.docs.reverse()
37 | res.docs.forEach((doc) => {
38 | userPosts = [
39 | ...userPosts,
40 | {
41 | userId: user.id,
42 | username,
43 | id: doc.id,
44 | ...doc.data(),
45 | },
46 | ]
47 | setPosts(userPosts)
48 | setLoading(false)
49 | })
50 | }
51 | })
52 | })
53 | )
54 | setLoading(false)
55 | }, [])
56 |
57 | return (
58 | <>
59 |
60 |
61 |
62 |
63 | {loading && (
64 |
65 |
70 |
71 | )}
72 | {posts.map((post, id) => {
73 | return
74 | })}
75 |
76 |
77 |
80 |
81 | >
82 | )
83 | }
84 |
--------------------------------------------------------------------------------
/components/HomeLayout/styles.module.scss:
--------------------------------------------------------------------------------
1 | .homeLayout {
2 | display: flex;
3 | flex-wrap: wrap;
4 | margin-left: -14px;
5 | margin-right: -14px;
6 | margin-top: 30px;
7 | justify-content: space-between;
8 | @media (max-width: 599.98px) {
9 | margin-top: 0;
10 | }
11 |
12 | .mainLayout {
13 | flex: 1;
14 | max-width: 642px;
15 | padding-left: 14px;
16 | padding-right: 14px;
17 | width: 100%;
18 | }
19 |
20 | .sidebar {
21 | padding-left: 14px;
22 | padding-right: 14px;
23 | width: 325px;
24 | }
25 |
26 | @media (max-width: 999.98px) {
27 | max-width: 600px;
28 | margin-left: auto;
29 | margin-right: auto;
30 | .mainLayout {
31 | flex: 1;
32 | max-width: 642px;
33 | padding: 0;
34 | }
35 |
36 | .sidebar {
37 | display: none;
38 | }
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/components/InboxScreen/index.js:
--------------------------------------------------------------------------------
1 | import { useState, useEffect } from 'react'
2 | import styles from './styles.module.scss'
3 |
4 | import NoMessage from '../../components/NoMessage'
5 | import ContactList from '../../components/ContactList'
6 | import MessageContent from '../../components/MessageContent'
7 | import MessageHeader from '../../components/MessageHeader'
8 | import MessageFooter from '../../components/MessageFooter'
9 | import NewMessageModal from '../NewMessageModal'
10 |
11 | import useWindowSize from '../../hooks/useWindowSize'
12 | import NewMessage from '../../icons/NewMessage'
13 | import firebase from '../../lib/firebase'
14 | import { useAuth } from '../../lib/auth'
15 | import { useRouter } from 'next/router'
16 |
17 | export default function Messages() {
18 | const firestore = firebase.firestore()
19 | const router = useRouter()
20 | const auth = useAuth()
21 | const ww = useWindowSize().width
22 | const [activeContact, setActiveContact] = useState(null)
23 | const [contacts, setContacts] = useState([])
24 | const [showModal, setShowModal] = useState(false)
25 | const activeHandle = (e, id) => {
26 | e.preventDefault()
27 | setActiveContact(id)
28 | }
29 | // let messageList
30 | useEffect(() => {
31 | if (router.query.contact) {
32 | setActiveContact(router.query.contact)
33 | } else {
34 | router.push('/direct/inbox')
35 | }
36 | let messageList = firestore
37 | .collection(`users/${auth.user.id}/contacts`)
38 | .orderBy('time', 'desc')
39 | .onSnapshot((res) => {
40 | let list = []
41 | res.docs.forEach((lastMessage) => {
42 | list.push({
43 | id: lastMessage.id,
44 | ...lastMessage.data(),
45 | })
46 | })
47 | setContacts(list)
48 | })
49 | return () => {
50 | messageList()
51 | }
52 | }, [])
53 |
54 | // no-screen
55 | // no-message
56 | // messages
57 | const [contentScreen, setContentScreen] = useState('no-message')
58 | useEffect(() => {
59 | if (activeContact) {
60 | if (ww >= 735) {
61 | setContentScreen('messages')
62 | } else {
63 | setContentScreen('no-message')
64 | }
65 | } else {
66 | if (ww >= 735) {
67 | setContentScreen('no-message')
68 | } else {
69 | setContentScreen('no-screen')
70 | }
71 | }
72 | })
73 |
74 | useEffect(() => {
75 | if (activeContact) {
76 | router.push(`/direct/t/${activeContact}`)
77 | }
78 | }, [activeContact, contentScreen])
79 |
80 | return (
81 |
82 |
83 |
84 |
85 |
86 |
owuzan
87 |
95 |
96 | {/* FIXME NoMessage componentinin genişlik ayarı yapılacak */}
97 |
104 |
105 |
106 | {contentScreen == 'no-message' && (
107 |
108 | )}
109 | {contentScreen == 'messages' && (
110 | <>
111 |
112 |
113 |
114 | >
115 | )}
116 |
117 |
118 | {showModal && (
119 |
123 | )}
124 |
125 | )
126 | }
127 |
--------------------------------------------------------------------------------
/components/InboxScreen/styles.module.scss:
--------------------------------------------------------------------------------
1 | .messagesPage {
2 | height: calc(100vh - 54px);
3 | padding: 20px 0;
4 | @media (max-width: 934.98px) {
5 | padding: 0;
6 | }
7 | @media (max-width: 599.98px) {
8 | height: calc(100vh - 100px);
9 | }
10 |
11 | .messagesWrapper {
12 | display: flex;
13 | border: 1px solid var(--border-color);
14 | border-radius: 3px;
15 | height: 100%;
16 | background-color: var(--white);
17 | @media (max-width: 934.98px) {
18 | border: 0;
19 | }
20 |
21 | .messagesSidebar {
22 | width: 350px;
23 | border-right: 1px solid var(--border-color);
24 | height: 100%;
25 | display: flex;
26 | flex-direction: column;
27 |
28 | @media (max-width: 599.98px) {
29 | width: 100%;
30 | }
31 |
32 | .sidebarHeader {
33 | width: 100%;
34 | height: 60px;
35 | border-bottom: 1px solid var(--border-color);
36 | display: flex;
37 | justify-content: space-between;
38 | align-items: center;
39 | padding: 0 20px;
40 |
41 | div {
42 | display: flex;
43 | }
44 |
45 | .sidebarTop {
46 | font-weight: 500;
47 | }
48 |
49 | .newMessageIcon {
50 | appearance: none;
51 | background: transparent;
52 | border: 0;
53 | outline: 0;
54 | cursor: pointer;
55 | }
56 | }
57 | }
58 |
59 | .messageContent {
60 | display: flex;
61 | flex-direction: column;
62 | flex: 1;
63 | }
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/components/Loader/index.js:
--------------------------------------------------------------------------------
1 | import styles from './styles.module.scss'
2 | import { ClipLoader } from 'react-spinners'
3 | import { css } from '@emotion/core'
4 |
5 | const Loader = () => {
6 | return (
7 |
8 |
13 |
14 | )
15 | }
16 |
17 | export default Loader
18 |
--------------------------------------------------------------------------------
/components/Loader/styles.module.scss:
--------------------------------------------------------------------------------
1 | .loader {
2 | position: fixed;
3 | z-index: 9999;
4 | left: 0;
5 | top: 0;
6 | right: 0;
7 | bottom: 0;
8 | background-color: var(--background-color);
9 | display: flex;
10 | justify-content: center;
11 | align-items: center;
12 | }
13 |
--------------------------------------------------------------------------------
/components/MessageContent/index.js:
--------------------------------------------------------------------------------
1 | import { useState, useEffect, useCallback, useRef } from 'react'
2 | import styles from './styles.module.scss'
3 | import MessageSection from '../MessageSection'
4 | import firebase from '../../lib/firebase'
5 | import { useAuth } from '../../lib/auth'
6 | import { getUserData } from '../../lib/db'
7 |
8 | export default function MessageContent({ userId }) {
9 | const auth = useAuth()
10 | const [messageGroups, setMessageGroups] = useState([])
11 | const [userData, setUserData] = useState()
12 | const messageListBottomRef = useRef()
13 |
14 | const scrollToBottom = () => {
15 | messageListBottomRef?.current?.scrollIntoView({
16 | behavior: 'smooth',
17 | block: 'end',
18 | })
19 | }
20 | let groups = [],
21 | group = [],
22 | lastMe = null,
23 | getMessages = () => {}
24 |
25 | useEffect(async () => {
26 | const firestore = firebase.firestore()
27 | setUserData(await getUserData(userId))
28 |
29 | let oldMessagesQuery = await firestore
30 | .collection(`users/${auth.user.id}/contacts/${userId}/messages`)
31 | .where('time', '<', new Date())
32 | .limit(20)
33 | .orderBy('time', 'desc')
34 | .get()
35 | let oldMessages = oldMessagesQuery.docs.reverse()
36 |
37 | // userData?.id != userId && getMessages()
38 | getMessages = firestore
39 | .collection(`users/${auth.user.id}/contacts/${userId}/messages`)
40 | .orderBy('time', 'asc')
41 | .where('time', '>', new Date())
42 | .onSnapshot((snapshot) => {
43 | // for (const doc of snapshot.docs) {
44 | // snapshot.docs.forEach((doc) => {
45 | // })
46 | groups = []
47 | let oldAndNewMessages = [...oldMessages, ...snapshot.docs]
48 | oldAndNewMessages.forEach((doc, index) => {
49 | const data = {
50 | id: doc.id,
51 | ...doc.data(),
52 | }
53 | if (data.me) {
54 | if (lastMe || lastMe == null) {
55 | group.push(data)
56 | lastMe = true
57 | } else {
58 | groups.push(group)
59 | group = []
60 | group.push(data)
61 | lastMe = true
62 | }
63 | } else {
64 | if (!lastMe || lastMe == null) {
65 | group.push(data)
66 | lastMe = false
67 | } else {
68 | groups.push(group)
69 | group = []
70 | group.push(data)
71 | lastMe = false
72 | }
73 | }
74 | })
75 | groups.push(group)
76 | group = []
77 | setMessageGroups(groups)
78 | scrollToBottom()
79 | })
80 |
81 | return () => {
82 | userData?.id != userId && getMessages()
83 | }
84 | }, [userId])
85 | return (
86 |
87 |
88 | {messageGroups.map((messageGroup, index) => {
89 | return (
90 |
96 | )
97 | })}
98 | {scrollToBottom()}
99 |
100 | {/* {scrollToBottom()} */}
101 | {/*
102 | */}
103 |
104 |
105 | )
106 | }
107 |
--------------------------------------------------------------------------------
/components/MessageContent/styles.module.scss:
--------------------------------------------------------------------------------
1 | .messageContentInner {
2 | display: flex;
3 | flex: 1;
4 | overflow-y: auto;
5 |
6 | & > ul {
7 | display: flex;
8 | flex-direction: column;
9 | flex: 1;
10 | list-style: none;
11 | margin: 0;
12 | padding: 20px 20px 0 20px;
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/components/MessageFooter/index.js:
--------------------------------------------------------------------------------
1 | import React, { useState, useRef, useEffect } from 'react'
2 | import styles from './styles.module.scss'
3 | import * as Icons from '../../icons'
4 | import sendMessage from '../../utility/sendMessage'
5 | import { useAuth } from '../../lib/auth'
6 |
7 | export default function MessageFooter({ userId }) {
8 | const [input, setInput] = useState('')
9 | const auth = useAuth()
10 | const inputRef = useRef(null)
11 | const inputKeyDownHandle = (e) => {
12 | if (e.keyCode === 13 && !e.shiftKey) {
13 | e.preventDefault()
14 | messageControlHandle(e)
15 | }
16 | }
17 | const inputHandle = (e) => {
18 | setInput(e.target.value)
19 | autoResizeHandle(e)
20 | }
21 |
22 | const messageControlHandle = (e) => {
23 | let tempInput = input.trim()
24 | if (tempInput.length > 0) {
25 | sendMessageHandle(e)
26 | } else {
27 | setInput('')
28 | e.target.setAttribute('rows', 1)
29 | }
30 | }
31 | const sendMessageHandle = (e) => {
32 | //Mesaj gönderme işlemleri
33 | sendMessage(auth.user.id, userId, input)
34 | setTimeout(() => {
35 | setInput('')
36 | e.target.setAttribute('rows', 1)
37 | }, 0)
38 | }
39 |
40 | const autoResizeHandle = (e) => {
41 | const textarea = e.target
42 | textarea.style.overflowY = 'hidden'
43 | textarea.style.resize = 'none'
44 | const rowsCount = textarea.value.split('\n').length
45 | if (rowsCount > 5) {
46 | textarea.setAttribute('rows', 5)
47 | textarea.style.overflowY = 'auto'
48 | } else {
49 | textarea.setAttribute('rows', rowsCount)
50 | }
51 | }
52 |
53 | useEffect(() => {
54 | inputRef.current.focus()
55 | })
56 | return (
57 |
58 |
59 |
60 |
63 |
64 |
73 |
74 |
77 |
80 |
81 |
82 |
83 | )
84 | }
85 |
--------------------------------------------------------------------------------
/components/MessageFooter/styles.module.scss:
--------------------------------------------------------------------------------
1 | .messageContentFooter {
2 | padding: 20px;
3 | background-color: var(--white);
4 |
5 | .messageFormInner {
6 | border: 1px solid var(--border-color);
7 | border-radius: 22px;
8 | padding: 0 8px 0 11px;
9 | display: flex;
10 | align-items: center;
11 |
12 | button {
13 | all: unset;
14 | cursor: pointer;
15 | padding: 8px;
16 | display: flex;
17 | }
18 |
19 | textarea {
20 | flex: 1;
21 | display: block;
22 | font-size: 14px;
23 | line-height: 18px;
24 | padding: 9px;
25 | display: flex;
26 | align-items: center;
27 | resize: none;
28 | font-family: inherit;
29 | border: 0;
30 | outline: 0;
31 | background-color: inherit;
32 | color: inherit;
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/components/MessageHeader/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import styles from './styles.module.scss'
3 |
4 | import UserUmage from '../UserImage'
5 | import Info from '../../icons/Info'
6 | import { getUserData } from '../../lib/db'
7 | import Link from 'next/link'
8 |
9 | export default function MessageHeader({ userId }) {
10 | const [userData, setUserData] = React.useState('')
11 |
12 | React.useEffect(async () => {
13 | setUserData(await getUserData(userId))
14 | }, [userId])
15 |
16 | return (
17 |
35 | )
36 | }
37 |
--------------------------------------------------------------------------------
/components/MessageHeader/styles.module.scss:
--------------------------------------------------------------------------------
1 | .messageContentHeader {
2 | height: 60px;
3 | border-bottom: 1px solid var(--border-color);
4 | padding: 0 20px;
5 | display: flex;
6 | align-items: center;
7 |
8 | .contactInfo {
9 | display: flex;
10 | flex: 1;
11 | align-items: center;
12 | height: 100%;
13 | a {
14 | text-decoration: none;
15 | display: inline-flex;
16 | align-items: center;
17 | color: var(--text-color);
18 | }
19 |
20 | .contactUsername {
21 | margin-left: 12px;
22 | font-weight: 600;
23 | }
24 | }
25 |
26 | .userInfoButton {
27 | all: unset;
28 | align-self: center;
29 | cursor: pointer;
30 | display: flex;
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/components/MessageListItem/index.js:
--------------------------------------------------------------------------------
1 | import { useState, useEffect } from 'react'
2 | import UserImage from '../UserImage'
3 | import styles from './styles.module.scss'
4 | import Link from 'next/link'
5 | import { getUserData } from '../../lib/db'
6 |
7 | export default function MessageListItem({ contact }) {
8 | const [user, setUser] = useState('')
9 |
10 | useEffect(async () => {
11 | const userData = await getUserData(contact.id)
12 | setUser(userData)
13 | }, [])
14 |
15 | return (
16 |
17 |
18 |
19 |
20 |
21 |
22 |
{user.username}
23 |
{contact.message}
24 |
25 |
26 |
27 | )
28 | }
29 |
--------------------------------------------------------------------------------
/components/MessageListItem/styles.module.scss:
--------------------------------------------------------------------------------
1 | .messageListUserImage {
2 | margin-right: 12px;
3 | }
4 |
5 | .messageListUserMeta {
6 | font-size: 14px;
7 | display: flex;
8 | flex: 1;
9 | flex-direction: column;
10 | justify-content: center;
11 | overflow: hidden;
12 |
13 | span {
14 | color: var(--text);
15 | }
16 | p {
17 | white-space: nowrap;
18 | overflow: hidden;
19 | text-overflow: ellipsis;
20 | color: var(--muted-text);
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/components/MessageSection/index.js:
--------------------------------------------------------------------------------
1 | import UserImage from '../UserImage'
2 | import styles from './styles.module.scss'
3 |
4 | export default function MessageSection({
5 | src = '/user.jpg',
6 | me = false,
7 | list = [],
8 | }) {
9 | if (!list.length) {
10 | return false
11 | }
12 | return (
13 |
14 |
15 |
16 |
17 |
18 |
19 | {list.map((message, index) => {
20 | return (
21 |
22 | {message.message}
23 |
24 | )
25 | })}
26 |
27 |
28 |
29 | )
30 | }
31 |
--------------------------------------------------------------------------------
/components/MessageSection/styles.module.scss:
--------------------------------------------------------------------------------
1 | .message {
2 | margin-bottom: 8px;
3 |
4 | &:last-child {
5 | margin-bottom: 0;
6 | }
7 |
8 | .messageSection {
9 | display: flex;
10 | align-items: flex-end;
11 |
12 | .userImage {
13 | margin-right: 8px;
14 | font-size: 24px;
15 | width: 1em;
16 | height: 1em;
17 | }
18 | }
19 |
20 | .sectionMessages {
21 | font-size: 14px;
22 | width: 100%;
23 | max-width: 235px;
24 | display: flex;
25 | flex-direction: column;
26 |
27 | .message {
28 | border: 1px solid var(--border-light-color);
29 | border-radius: 22px;
30 | padding: 16px;
31 | margin-bottom: 8px;
32 | align-self: flex-start;
33 | float: left;
34 | max-width: 100%;
35 | background-color: var(--other-message-background);
36 | overflow-wrap: break-word;
37 |
38 | &:last-child {
39 | margin-bottom: 0;
40 | }
41 | }
42 | }
43 |
44 | &.me {
45 | .messageSection {
46 | justify-content: flex-end;
47 |
48 | .sectionMessages {
49 | .message {
50 | align-self: flex-end;
51 | background-color: var(--border-light-color);
52 | }
53 | }
54 | }
55 | .userImage {
56 | display: none;
57 | }
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/components/NewMessageModal/index.js:
--------------------------------------------------------------------------------
1 | import { useState, useEffect } from 'react'
2 | import styles from './styles.module.scss'
3 | import * as Icons from '../../icons'
4 | import UserImage from '../UserImage'
5 | import { useAuth } from '../../lib/auth'
6 | import firebase from '../../lib/firebase'
7 | import { ClipLoader } from 'react-spinners'
8 | import { css } from '@emotion/core'
9 |
10 | const Modal = (props) => {
11 | const { setShowModal, setActiveContact } = props
12 | const auth = useAuth()
13 | const firestore = firebase.firestore()
14 | const [followings, setFollowings] = useState([])
15 | const [loading, setLoading] = useState(true)
16 | const [search, setSearch] = useState('')
17 | const [contactList, setContactList] = useState([])
18 |
19 | useEffect(async () => {
20 | const myFollowings = await firestore
21 | .collection(`users/${auth.user.id}/followings`)
22 | .get()
23 | .then((res) => {
24 | let ids = []
25 | res.docs.forEach((user) => ids.push(user.id))
26 | return ids
27 | })
28 | myFollowings.forEach(async (user) => {
29 | let data = await firestore
30 | .doc(`users/${user}`)
31 | .get()
32 | .then((res) => {
33 | return res.data()
34 | })
35 | setFollowings((users) => {
36 | return [...users, { id: user, ...data }]
37 | })
38 | })
39 | setLoading(false)
40 | return () => myFollowings()
41 | }, [])
42 |
43 | let filteredContacts = []
44 | useEffect(() => {
45 | filteredContacts = followings.filter((user) => {
46 | let username = user.username.toLowerCase()
47 | let name = user.name.toLowerCase()
48 | let input = search.toLowerCase()
49 | return (username.includes(input) || name.includes(input)) && user
50 | })
51 | if (search.trim().length) {
52 | setContactList(filteredContacts)
53 | } else {
54 | setContactList(followings)
55 | }
56 | }, [search, followings])
57 |
58 | return (
59 | {
62 | if (e.target == e.currentTarget) {
63 | setShowModal((showModal) => !showModal)
64 | }
65 | }}
66 | >
67 |
68 |
81 |
82 |
83 |
84 | setSearch(e.target.value)}
91 | />
92 |
93 |
94 |
95 |
Önerilenler
96 |
97 | {loading ? (
98 | <>
99 |
104 | >
105 | ) : (
106 | contactList.map((user) => {
107 | return (
108 | - {
112 | setActiveContact(user.id)
113 | setShowModal(false)
114 | }}
115 | >
116 |
117 |
118 |
119 | {user.username}
120 |
121 |
122 | {user.name}
123 |
124 |
125 |
126 | )
127 | })
128 | )}
129 |
130 |
131 |
132 |
133 | )
134 | }
135 |
136 | export default Modal
137 |
--------------------------------------------------------------------------------
/components/NewMessageModal/styles.module.scss:
--------------------------------------------------------------------------------
1 | .modal {
2 | position: fixed;
3 | display: flex;
4 | justify-content: center;
5 | align-items: center;
6 | left: 0;
7 | top: 0;
8 | bottom: 0;
9 | right: 0;
10 | background-color: rgba(0, 0, 0, 0.35);
11 | z-index: 10;
12 |
13 | .modalInner {
14 | max-width: 400px;
15 | width: 100%;
16 | background-color: var(--white);
17 | height: 50%;
18 | border-radius: 12px;
19 | display: flex;
20 | flex-direction: column;
21 | overflow: hidden;
22 |
23 | header {
24 | display: flex;
25 | height: 40px;
26 | justify-content: space-between;
27 | align-items: center;
28 | border-bottom: 1px solid var(--border-color);
29 |
30 | .close {
31 | height: 100%;
32 | button {
33 | appearance: none;
34 | display: flex;
35 | align-items: center;
36 | justify-content: center;
37 | border: 0;
38 | outline: 0;
39 | background: 0;
40 | height: inherit;
41 | width: 40px;
42 | cursor: pointer;
43 | font-size: 18px;
44 | }
45 | }
46 |
47 | .title {
48 | font-size: 16px;
49 | font-weight: 500;
50 | }
51 |
52 | .next {
53 | width: 40px;
54 | }
55 | }
56 |
57 | .search {
58 | font-size: 16px;
59 | height: 50px;
60 | display: flex;
61 | align-items: center;
62 | justify-content: flex-start;
63 | border-bottom: 1px solid var(--border-color);
64 |
65 | label {
66 | font-weight: 500;
67 | padding: 4px 12px;
68 | }
69 |
70 | .inputWrapper {
71 | padding: 4px 12px;
72 | flex: 1;
73 |
74 | input {
75 | display: block;
76 | width: 100%;
77 | height: 30px;
78 | outline: 0;
79 | border: 0;
80 | font-size: 14px;
81 | transform: translateY(2px);
82 |
83 | &::placeholder {
84 | color: var(--border-color);
85 | }
86 | }
87 | }
88 | }
89 |
90 | .contacts {
91 | font-size: 14px;
92 | flex: 1;
93 | align-self: stretch;
94 | display: flex;
95 | flex-direction: column;
96 | overflow-x: hidden;
97 | overflow-y: auto;
98 |
99 | .title {
100 | padding: 16px;
101 | font-weight: 500;
102 | }
103 |
104 | ul {
105 | display: flex;
106 | flex-direction: column;
107 | flex: 1;
108 | margin: 0;
109 | padding: 0;
110 | list-style: none;
111 | align-self: stretch;
112 |
113 | li {
114 | padding: 8px 16px;
115 | display: flex;
116 | align-items: center;
117 | background-color: var(--white);
118 | cursor: pointer;
119 |
120 | &:hover {
121 | background-color: var(--border-light-color);
122 | }
123 |
124 | .contactInfo {
125 | margin-left: 12px;
126 | flex: 1;
127 | display: flex;
128 | flex-direction: column;
129 |
130 | .username {
131 | font-weight: 500;
132 | }
133 | }
134 | }
135 | }
136 | }
137 | }
138 | }
139 |
--------------------------------------------------------------------------------
/components/NoMessage/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import styles from './styles.module.scss'
3 |
4 | import * as Icons from '../../icons'
5 |
6 | export default function NoMessage({ setShowModal }) {
7 | return (
8 |
9 |
10 |
11 |
12 |
13 |
Mesajların
14 |
15 | Bir arkadaşına veya gruba gizli fotoğraflar ve mesajlar
16 | gönder.
17 |
18 |
19 |
22 |
23 |
24 |
25 | )
26 | }
27 |
--------------------------------------------------------------------------------
/components/NoMessage/styles.module.scss:
--------------------------------------------------------------------------------
1 | .noMessageWrapper {
2 | display: flex;
3 | flex: 1;
4 | align-items: center;
5 | justify-content: center;
6 | padding: 20px;
7 |
8 | .noMessage {
9 | color: var(--text);
10 | display: flex;
11 | flex-direction: column;
12 |
13 | .messageIcon {
14 | margin-left: auto;
15 | margin-right: auto;
16 | border: 3px solid var(--text);
17 | font-size: 42px;
18 | display: flex;
19 | justify-content: center;
20 | align-items: center;
21 | width: 95px;
22 | height: 95px;
23 | border-radius: 50%;
24 | }
25 | .pageTitle {
26 | text-align: center;
27 | font-size: 22px;
28 | font-weight: 400;
29 | margin-top: 28px;
30 | }
31 | .pageDescription {
32 | color: var(--muted-text);
33 | font-size: 14px;
34 | margin-top: 5px;
35 | margin-bottom: 32px;
36 | text-align: center;
37 | }
38 |
39 | .noMeesageFooter {
40 | text-align: center;
41 | button {
42 | background-color: var(--blue);
43 | border: 0;
44 | outline: 0;
45 | padding: 5px 9px;
46 | border-radius: 4px;
47 | color: var(--button-text);
48 | font-weight: 600;
49 | font-size: 14px;
50 | line-height: 1.5;
51 | display: inline-block;
52 | cursor: pointer;
53 | }
54 | }
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/components/NotFoundScreen/index.js:
--------------------------------------------------------------------------------
1 | const NotFoundScreen = () => {
2 | return (
3 |
4 |
Üzgünüz, bu sayfaya ulaşılamıyor.
5 |
6 | Tıkladığın bağlantı bozuk olabilir veya sayfa kaldırılmış
7 | olabilir. Instagram'a geri dön.
8 |
9 |
10 |
19 |
20 | )
21 | }
22 | export default NotFoundScreen
23 |
--------------------------------------------------------------------------------
/components/Profile/styles.module.scss:
--------------------------------------------------------------------------------
1 | .profilePage {
2 | padding: 30px 0;
3 |
4 | header.profilePageHeader {
5 | margin-bottom: 44px;
6 | display: flex;
7 | flex-wrap: wrap;
8 |
9 | @media (max-width: 734.98px) {
10 | margin-bottom: 0;
11 | }
12 |
13 | .profileImageWrapper {
14 | display: flex;
15 | justify-content: center;
16 | flex-shrink: 0;
17 | margin-right: 30px;
18 | flex: 1;
19 |
20 | @media (max-width: 734.98px) {
21 | flex: 0;
22 | margin: 0 15px;
23 | }
24 | }
25 |
26 | .profileMetas {
27 | flex: 2;
28 | display: flex;
29 | flex-direction: column;
30 |
31 | @media (max-width: 734.98px) {
32 | justify-content: center;
33 | }
34 |
35 | .userHead {
36 | display: flex;
37 | margin-bottom: 20px;
38 | align-items: center;
39 |
40 | button {
41 | cursor: pointer;
42 | display: flex;
43 | background-color: transparent;
44 | outline: 0;
45 | }
46 |
47 | .usernameTitle {
48 | font-weight: 300;
49 | font-size: 28px;
50 | }
51 | .profileSettingsBtn {
52 | display: flex;
53 | justify-content: center;
54 | align-items: center;
55 | color: inherit;
56 | border: 0;
57 | margin-left: 5px;
58 | width: 40px;
59 | height: 40px;
60 | }
61 | }
62 | }
63 | }
64 |
65 | .userContents {
66 | .userContentTabs {
67 | display: flex;
68 | justify-content: center;
69 | align-items: center;
70 | height: 52px;
71 | border-top: 1px solid var(--border-color);
72 | margin-bottom: 2px;
73 | @media (max-width: 734.98px) {
74 | position: sticky;
75 | top: 0px;
76 | z-index: 20;
77 | background-color: var(--background-color);
78 | }
79 | @media (max-width: 599.98px) {
80 | top: 53px;
81 | background-color: var(--white);
82 | }
83 |
84 | button {
85 | display: flex;
86 | align-items: center;
87 | margin-right: 60px;
88 | text-decoration: none;
89 | text-transform: uppercase;
90 | font-weight: 600;
91 | height: 100%;
92 | color: var(--muted-text);
93 | background-color: transparent;
94 | outline: 0;
95 | border: 0;
96 | cursor: pointer;
97 |
98 | @media (max-width: 734.98px) {
99 | flex: 1;
100 | justify-content: center;
101 | }
102 |
103 | &.activeTab {
104 | color: var(--text);
105 | position: relative;
106 |
107 | &::after {
108 | content: "";
109 | position: absolute;
110 | height: 0.5px;
111 | width: 100%;
112 | top: -1px;
113 | display: block;
114 | z-index: 1;
115 | background-color: var(--black);
116 | @media (max-width: 734.98px) {
117 | top: unset;
118 | height: 1px;
119 | bottom: 0;
120 | }
121 | }
122 | }
123 |
124 | span {
125 | display: flex;
126 | font-size: 12px;
127 |
128 | &.tab {
129 | margin-left: 6px;
130 |
131 | @media (max-width: 734.98px) {
132 | display: none;
133 | }
134 | }
135 |
136 | &.icon {
137 | @media (max-width: 734.98px) {
138 | font-size: 24px;
139 | }
140 | }
141 | }
142 | &:last-child {
143 | margin-right: 0;
144 | }
145 | }
146 | }
147 | }
148 | }
149 |
--------------------------------------------------------------------------------
/components/ProfileFollowButton/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import styles from './styles.module.scss'
3 | import follow from '../../utility/follow'
4 | import unfollow from '../../utility/unfollow'
5 | import { useRouter } from 'next/router'
6 |
7 | const ProfileFollowButton = (props) => {
8 | const router = useRouter()
9 | const { auth, profileId, isUserFollowing, setIsUserFollowingHandle } = props
10 | if (isUserFollowing) {
11 | return (
12 | <>
13 |
24 |
33 | >
34 | )
35 | } else {
36 | return (
37 |
46 | )
47 | }
48 | }
49 |
50 | export default ProfileFollowButton
51 |
--------------------------------------------------------------------------------
/components/ProfileFollowButton/styles.module.scss:
--------------------------------------------------------------------------------
1 | .followButton,
2 | .alreadyFollowing,
3 | .unfollow {
4 | padding: 0 24px;
5 | height: 30px;
6 | font-weight: 500;
7 | color: var(--white);
8 | background-color: var(--blue) !important;
9 | display: inline-flex;
10 | align-self: center;
11 | align-items: center;
12 | border-radius: 3px;
13 | outline: 0;
14 | border: 0;
15 | margin-left: 20px;
16 | text-decoration: none;
17 |
18 | @media (max-width: 735px) {
19 | margin-left: 0;
20 | margin-top: 12px;
21 | align-self: flex-start;
22 | }
23 | }
24 | .alreadyFollowing {
25 | background-color: var(--background-color) !important;
26 | border: 1px solid var(--border-color);
27 | color: var(--text);
28 | padding: 0 9px;
29 | }
30 |
31 | .unfollow {
32 | background-color: var(--red) !important;
33 | border: 1px solid var(--red);
34 | color: var(--white);
35 | padding: 0 9px;
36 | }
37 |
--------------------------------------------------------------------------------
/components/SearchResults/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import UserImage from '../UserImage'
3 | import styles from './styles.module.scss'
4 | import Link from 'next/link'
5 |
6 | const SearchResults = (props) => {
7 | const { result, setSearchInput } = props
8 | const clickHandle = (e) => {
9 | setSearchInput('')
10 | }
11 |
12 | return (
13 |
38 | )
39 | }
40 |
41 | export default SearchResults
42 |
--------------------------------------------------------------------------------
/components/SearchResults/styles.module.scss:
--------------------------------------------------------------------------------
1 | .searchResults {
2 | position: absolute;
3 | top: 120%;
4 | width: 285px;
5 | background-color: var(--white);
6 | border-radius: 3px;
7 | border: 1px solid var(--border-color);
8 | z-index: 3;
9 | left: 50%;
10 | transform: translateX(-50%);
11 | &::before {
12 | content: "";
13 | font-size: 1rem;
14 | width: 1em;
15 | height: 1em;
16 | position: absolute;
17 | border-top: 1px solid var(--border-color);
18 | border-right: 1px solid var(--border-color);
19 | top: -9px;
20 | left: 50%;
21 | z-index: 0;
22 | transform: rotate(-45deg);
23 | background: linear-gradient(to left bottom, var(--white) 50%, transparent 50%);
24 | }
25 | }
26 | .list {
27 | z-index: 1;
28 | list-style: none;
29 | margin: 0;
30 | background-color: var(--white);
31 | display: flex;
32 | max-height: 360px;
33 | flex-direction: column;
34 | overflow: hidden;
35 | overflow-y: auto;
36 | }
37 | .user {
38 | border-bottom: 1px solid var(--border-color);
39 | &:last-child {
40 | border: 0;
41 | }
42 |
43 | a {
44 | display: flex;
45 | padding: 10px;
46 | text-decoration: none;
47 | align-items: center;
48 | outline: 0;
49 |
50 | &:hover,
51 | &:focus {
52 | background-color: var(--background-color);
53 | }
54 | }
55 | }
56 | .image {
57 | margin-right: 10px;
58 | display: flex;
59 | align-items: center;
60 | }
61 | .about {
62 | font-size: 14px;
63 | display: flex;
64 | flex-direction: column;
65 |
66 | .username {
67 | font-weight: 500;
68 | }
69 | .name {
70 | font-weight: 50300;
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/components/SignInScreen/index.js:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react'
2 | import styles from './styles.module.scss'
3 | import Link from 'next/link'
4 | import { useAuth } from '../../lib/auth'
5 |
6 | export default function SignInScreen() {
7 | const auth = useAuth()
8 | const refPassword = React.useRef()
9 |
10 | const [email, setEmail] = useState('')
11 | const [password, setPassword] = useState('')
12 | const [error, setError] = useState('')
13 | const handlePasswordInputType = (e) => {
14 | e.preventDefault()
15 | if (refPassword.current.type === 'password') {
16 | refPassword.current.type = 'text'
17 | e.target.innerText = 'Gizle'
18 | } else {
19 | refPassword.current.type = 'password'
20 | e.target.innerText = 'Göster'
21 | }
22 | }
23 |
24 | const handleSignIn = async (e) => {
25 | e.preventDefault()
26 | let isError = await auth.signIn(email, password)
27 | if (isError) {
28 | setError(isError.message)
29 | }
30 | }
31 |
32 | return (
33 |
34 |
35 |

36 |
37 |
38 |
100 |
101 |
102 | {'Hesabın yok mu? '}
103 |
104 | Kaydol
105 |
106 |
107 |
108 |
109 |
110 |
132 | {auth?.user?.uid}
133 |
134 |
135 | )
136 | }
137 |
--------------------------------------------------------------------------------
/components/SignInScreen/styles.module.scss:
--------------------------------------------------------------------------------
1 | .signInPage {
2 | // display: flex;
3 | padding-top: 45px;
4 | justify-content: center;
5 | align-items: center;
6 |
7 | @media (max-width: 735px) {
8 | padding-top: 30px;
9 | }
10 |
11 | .mockups {
12 | display: none;
13 | }
14 |
15 | .signUpWrapper {
16 | width: 100%;
17 | max-width: 350px;
18 | margin-left: auto;
19 | margin-right: auto;
20 | display: block;
21 |
22 | .section {
23 | border: 1px solid var(--border-color);
24 | border-radius: 3px;
25 | text-align: center;
26 | background-color: var(--white);
27 |
28 | @media (max-width: 735px) {
29 | border: none;
30 | }
31 |
32 | .brand {
33 | display: flex;
34 | justify-content: center;
35 | margin: 22px auto 12px;
36 |
37 | img {
38 | width: 100%;
39 | height: 100%;
40 | max-width: 175px;
41 | max-height: 51px;
42 | object-fit: contain;
43 | }
44 | }
45 | .field {
46 | margin: 0 40px 6px 40px;
47 | position: relative;
48 |
49 | input {
50 | border: 1px solid var(--border-color);
51 | padding: 9px 0 7px 8px;
52 | width: 100%;
53 | border-radius: 3px;
54 | font-size: 12px;
55 | background-color: var(--input-background);
56 | outline: 0;
57 | }
58 | .loginBtn {
59 | width: 100%;
60 | padding: 5px 9px;
61 | background-color: var(--blue);
62 | outline: 0;
63 | border: 1px solid var(--blue);
64 | border-radius: 3px;
65 | color: var(--white);
66 | font-weight: 500;
67 | cursor: pointer;
68 | }
69 |
70 | .showOrHide {
71 | appearance: none;
72 | background-color: transparent;
73 | border: 0;
74 | cursor: pointer;
75 | font-weight: 500;
76 | outline: 0;
77 | position: absolute;
78 | right: 10px;
79 | top: 50%;
80 | transform: translateY(-50%);
81 | font-size: 13.3333px;
82 | }
83 | }
84 |
85 | .horizantalLine {
86 | text-transform: uppercase;
87 | height: 30px;
88 | font-size: 13px;
89 | font-weight: 500;
90 | color: var(--muted-text);
91 | position: relative;
92 | margin: 10px 40px;
93 |
94 | .line {
95 | height: 1.5px;
96 | width: 100%;
97 | left: 0;
98 | position: absolute;
99 | background-color: var(--muted-text);
100 | top: 50%;
101 | opacity: 0.3;
102 | transform: translateY(-50%);
103 | z-index: 0;
104 | }
105 |
106 | .text {
107 | position: absolute;
108 | z-index: 1;
109 | background-color: white;
110 | left: 50%;
111 | top: 50%;
112 | padding: 0 15px;
113 | transform: translateY(-50%) translateX(-50%);
114 | }
115 | }
116 |
117 | .facebookLogin {
118 | margin: 15px 0;
119 | display: flex;
120 | align-items: center;
121 | justify-content: center;
122 |
123 | img {
124 | width: 15px;
125 | height: 15px;
126 | margin-right: 5px;
127 | }
128 | a {
129 | text-decoration: none;
130 | font-weight: 500;
131 | color: #385185;
132 | font-size: 14px;
133 | }
134 | }
135 | .forgotPassword {
136 | font-size: 12px;
137 | margin-bottom: 15px;
138 | a {
139 | text-decoration: none;
140 | font-size: 12px;
141 | color: var(--text-color);
142 | }
143 | }
144 | }
145 |
146 | .notHaveAccounts {
147 | width: 100%;
148 | max-width: 350px;
149 | margin-left: auto;
150 | margin-right: auto;
151 | display: block;
152 | border: 1px solid var(--border-color);
153 | border-radius: 3px;
154 | text-align: center;
155 | background-color: var(--white);
156 | margin-top: 10px;
157 | padding: 20px 0;
158 | font-size: 14px;
159 |
160 | @media (max-width: 735px) {
161 | border: none;
162 | }
163 |
164 | a {
165 | text-decoration: none;
166 | color: var(--blue);
167 | font-weight: 500;
168 | }
169 | }
170 | }
171 |
172 | .signUpFooter {
173 | margin-top: 40px;
174 | width: 80%;
175 | margin-left: auto;
176 | margin-right: auto;
177 | display: flex;
178 | flex-wrap: wrap;
179 | justify-content: center;
180 |
181 | a {
182 | color: var(--muted-text);
183 | text-decoration: none;
184 | font-size: 12px;
185 | white-space: nowrap;
186 | margin-right: 15px;
187 | margin-bottom: 10px;
188 |
189 | &:last-child {
190 | margin-right: 0;
191 | }
192 | }
193 |
194 | .footerText {
195 | width: 100%;
196 | text-align: center;
197 | font-size: 12px;
198 | color: var(--muted-text);
199 | margin-top: 20px;
200 | }
201 | }
202 | }
203 | .passwordInput {
204 | padding-right: 50px !important;
205 | }
206 | .errorMessage {
207 | margin: 40px 10px;
208 | color: var(--red);
209 | font-weight: 400;
210 | font-size: 14px;
211 | }
212 |
--------------------------------------------------------------------------------
/components/SignUpScreen/index.js:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react'
2 | import styles from './styles.module.scss'
3 | import Link from 'next/link'
4 | import { signUp } from '../../lib/db'
5 |
6 | export default function SignUpScreen() {
7 | const [email, setEmail] = useState('')
8 | const [fullName, setFullName] = useState('')
9 | const [username, setUsername] = useState('')
10 | const [password, setPassword] = useState('')
11 | const [error, setError] = useState('')
12 |
13 | const handleSubmitForm = async (e) => {
14 | e.preventDefault()
15 | signUp(email, password, username, fullName).then((res) => {
16 | if (res) {
17 | setError(res.message)
18 | }
19 | })
20 | }
21 |
22 | return (
23 |
24 |
25 |
26 |
100 |
101 |
102 | Hesabın var mı?{' '}
103 |
104 | Giriş yap
105 |
106 |
107 |
108 |
109 |
126 |
127 |
128 | )
129 | }
130 |
--------------------------------------------------------------------------------
/components/SignUpScreen/styles.module.scss:
--------------------------------------------------------------------------------
1 | .signUpPage {
2 | // display: flex;
3 | padding-top: 45px;
4 | justify-content: center;
5 | align-items: center;
6 |
7 | @media (max-width: 735px) {
8 | padding-top: 30px;
9 | }
10 |
11 | .signUpWrapper {
12 | width: 100%;
13 | max-width: 350px;
14 | margin-left: auto;
15 | margin-right: auto;
16 | display: block;
17 |
18 | form {
19 | border: 1px solid var(--border-color);
20 | border-radius: 3px;
21 | text-align: center;
22 | background-color: var(--white);
23 |
24 | @media (max-width: 735px) {
25 | border: none;
26 | }
27 |
28 | .brand {
29 | display: flex;
30 | justify-content: center;
31 | margin: 22px auto 12px;
32 |
33 | img {
34 | width: 100%;
35 | height: 100%;
36 | max-width: 175px;
37 | max-height: 51px;
38 | object-fit: contain;
39 | }
40 | }
41 |
42 | .description {
43 | margin: 15px 40px;
44 | font-weight: 500;
45 | color: var(--muted-text);
46 | }
47 |
48 | .facebookLoginBtnWrapper {
49 | margin: 0 40px;
50 | display: block;
51 |
52 | button {
53 | cursor: pointer;
54 | width: 100%;
55 | padding: 5px 9px;
56 | background-color: var(--blue);
57 | outline: 0;
58 | border: 1px solid var(--blue);
59 | border-radius: 3px;
60 | color: var(--white);
61 | font-weight: 500;
62 | }
63 | }
64 | .field {
65 | margin: 0 40px 6px 40px;
66 | position: relative;
67 |
68 | input {
69 | border: 1px solid var(--border-color);
70 | padding: 9px 0 7px 8px;
71 | width: 100%;
72 | border-radius: 3px;
73 | font-size: 12px;
74 | background-color: var(--input-background);
75 | outline: 0;
76 | line-height: 1.5;
77 | }
78 |
79 | .showOrHide {
80 | appearance: none;
81 | background-color: transparent;
82 | border: 0;
83 | cursor: pointer;
84 | font-weight: 500;
85 | outline: 0;
86 | position: absolute;
87 | right: 10px;
88 | top: 50%;
89 | transform: translateY(-50%);
90 | }
91 | .signUpBtn {
92 | width: 100%;
93 | padding: 5px 9px;
94 | background-color: var(--blue);
95 | outline: 0;
96 | border: 1px solid var(--blue);
97 | border-radius: 3px;
98 | color: var(--white);
99 | font-weight: 500;
100 | margin-top: 10px;
101 | cursor: pointer;
102 | }
103 | }
104 |
105 | .horizantalLine {
106 | text-transform: uppercase;
107 | height: 30px;
108 | font-size: 13px;
109 | font-weight: 500;
110 | color: var(--muted-text);
111 | position: relative;
112 | margin: 10px 40px;
113 |
114 | .line {
115 | height: 1.5px;
116 | width: 100%;
117 | left: 0;
118 | position: absolute;
119 | background-color: var(--muted-text);
120 | top: 50%;
121 | opacity: 0.3;
122 | transform: translateY(-50%);
123 | z-index: 0;
124 | }
125 |
126 | .text {
127 | position: absolute;
128 | z-index: 1;
129 | background-color: white;
130 | left: 50%;
131 | top: 50%;
132 | padding: 0 15px;
133 | transform: translateY(-50%) translateX(-50%);
134 | }
135 | }
136 |
137 | .terms {
138 | font-size: 12px;
139 | margin-bottom: 15px;
140 | margin-left: 40px;
141 | margin-right: 40px;
142 | margin-top: 20px;
143 | a {
144 | text-decoration: none;
145 | color: var(--text-color);
146 | font-weight: 500;
147 | }
148 | }
149 | }
150 |
151 | .doYouHaveAnAccount {
152 | width: 100%;
153 | max-width: 350px;
154 | margin-left: auto;
155 | margin-right: auto;
156 | display: block;
157 | border: 1px solid var(--border-color);
158 | border-radius: 3px;
159 | text-align: center;
160 | background-color: var(--white);
161 | margin-top: 10px;
162 | padding: 20px 0;
163 | font-size: 14px;
164 |
165 | @media (max-width: 735px) {
166 | border: none;
167 | }
168 |
169 | a {
170 | text-decoration: none;
171 | color: var(--blue);
172 | }
173 | }
174 | }
175 |
176 | .signUpFooter {
177 | margin-top: 40px;
178 | padding-bottom: 20px;
179 | width: 80%;
180 | margin-left: auto;
181 | margin-right: auto;
182 | display: flex;
183 | flex-wrap: wrap;
184 | justify-content: center;
185 |
186 | a {
187 | color: var(--muted-text);
188 | text-decoration: none;
189 | font-size: 12px;
190 | white-space: nowrap;
191 | margin-right: 15px;
192 | margin-bottom: 10px;
193 |
194 | &:last-child {
195 | margin-right: 0;
196 | }
197 | }
198 |
199 | .footerText {
200 | width: 100%;
201 | text-align: center;
202 | font-size: 12px;
203 | color: var(--muted-text);
204 | margin-top: 20px;
205 | }
206 | }
207 | }
208 | .errorMessage {
209 | margin: 40px 20px;
210 | color: var(--red);
211 | font-weight: 400;
212 | font-size: 14px;
213 | }
214 |
--------------------------------------------------------------------------------
/components/StoriesBar/index.js:
--------------------------------------------------------------------------------
1 | import styles from './styles.module.scss'
2 | import StoryItem from '../StoryItem'
3 |
4 | export default function StoriesBar() {
5 | return (
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 | )
18 | }
19 |
--------------------------------------------------------------------------------
/components/StoriesBar/styles.module.scss:
--------------------------------------------------------------------------------
1 | .storiesBar {
2 | background-color: var(--white);
3 | border: 1px solid var(--border-color);
4 | border-radius: 3px;
5 | overflow-x: auto;
6 | overflow-y: hidden;
7 | @media (max-width: 599.98px) {
8 | border: 0;
9 | border-bottom: 1px solid var(--border-color);
10 | border-radius: 0;
11 | }
12 |
13 | .storiesInner {
14 | .stories {
15 | padding: 16px 4px;
16 | list-style-type: none;
17 | display: flex;
18 | }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/components/StoryItem/index.js:
--------------------------------------------------------------------------------
1 | import UserImage from '../UserImage'
2 | import styles from './styles.module.scss'
3 |
4 | export default function StoryItem({ username = "owuzan", src = "owuzan.jpg" }) {
5 | return (
6 |
7 |
8 | {username}
9 |
10 | )
11 | }
12 |
--------------------------------------------------------------------------------
/components/StoryItem/styles.module.scss:
--------------------------------------------------------------------------------
1 | .storyItem {
2 | display: flex;
3 | flex-direction: column;
4 | margin-left: 14px;
5 | display: flex;
6 | color: var(--text);
7 | font-size: 12px;
8 | text-align: center;
9 | font-weight: 400;
10 | cursor: pointer;
11 | padding: 6px;
12 |
13 | p {
14 | margin-top: 3px;
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/components/SugessionUser/index.js:
--------------------------------------------------------------------------------
1 | import UserImage from '../UserImage'
2 | import styles from './styles.module.scss'
3 |
4 | export default function SuggessionUser({ username = "owuzan", name = "Oğuzhan Yılmaz", src = "owuzan.jpg" }) {
5 | return (
6 | <>
7 |
14 |
15 | >
16 | )
17 | }
18 |
--------------------------------------------------------------------------------
/components/SugessionUser/styles.module.scss:
--------------------------------------------------------------------------------
1 | .suggesionUser {
2 | display: flex;
3 | align-items: center;
4 | justify-content: flex-start;
5 |
6 | .userMeta {
7 | margin-left: 12px;
8 | width: 141px;
9 | display: flex;
10 | flex-direction: column;
11 | p {
12 | margin: 0;
13 | font-weight: 500;
14 | font-size: 14px;
15 |
16 | a {
17 | text-decoration: none;
18 | color: inherit;
19 |
20 | &:hover {
21 | text-decoration: underline;
22 | }
23 | }
24 | }
25 | span {
26 | font-weight: 400;
27 | font-size: 12px;
28 | color: var(--muted-text);
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/components/UserImage/index.js:
--------------------------------------------------------------------------------
1 | import classNames from 'classnames'
2 | import styles from './styles.module.scss'
3 |
4 | export default function UserImage(props) {
5 | const src = props.src ?? '/user.jpg'
6 | const classes = classNames({
7 | [styles.userImage]: true,
8 | [styles.story]: props?.type === 'story' ? true : false,
9 | [styles.active]: props?.type === 'active' ? true : false,
10 | })
11 | return (
12 |
13 |
14 |

15 |
16 |
21 |
22 | )
23 | }
24 |
--------------------------------------------------------------------------------
/components/UserImage/styles.module.scss:
--------------------------------------------------------------------------------
1 | .userImage {
2 | display: inline-flex;
3 | font-size: 24px;
4 | width: 1em;
5 | height: 1em;
6 | position: relative;
7 | cursor: pointer;
8 |
9 | .imageWrapper {
10 | display: flex;
11 | justify-content: center;
12 | align-items: center;
13 | position: absolute;
14 | top: 0;
15 | right: 0;
16 | bottom: 0;
17 | left: 0;
18 | border-radius: 50%;
19 |
20 | img {
21 | width: 100%;
22 | height: 100%;
23 | border-radius: 50%;
24 | object-fit: cover;
25 | }
26 | }
27 | }
28 |
29 | .story {
30 | .imageWrapper {
31 | border-radius: 50%;
32 | top: -4px;
33 | right: -4px;
34 | bottom: -4px;
35 | left: -4px;
36 | background: conic-gradient(
37 | from 180deg at 50% 50%,
38 | #e03571 -44.74deg,
39 | #f9793a 0.68deg,
40 | #f79c4f 46.29deg,
41 | #f97e34 90.31deg,
42 | #e3455f 138.62deg,
43 | #d72b7e 180deg,
44 | #c12f91 227.75deg,
45 | #db297d 269.6deg,
46 | #e03571 315.26deg,
47 | #f9793a 360.68deg
48 | );
49 |
50 | img {
51 | box-shadow: 0 0 0 2px var(--white);
52 | width: 1em;
53 | height: 1em;
54 | }
55 | }
56 | }
57 |
58 | .active {
59 | .imageWrapper {
60 | box-shadow: 0 0 0 3px var(--black);
61 | img {
62 | box-shadow: 0 0 0 2px var(--white);
63 | }
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/components/UserInfo/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import styles from './styles.module.scss'
3 | import linkedText from '../../utility/linkedText'
4 | import Link from 'next/link'
5 |
6 | export default function UserInfo({ userData }) {
7 | return (
8 |
9 |
{userData.name}
10 |
11 |
12 | {linkedText(userData?.biography ? userData.biography : '')}
13 |
14 |
15 |
16 |
Burası test amaçlı yazılmıştır.
17 |
{linkedText('Var olan @owuzan hesabına git.')}
18 |
{linkedText('Var olan @ssezer hesabına git.')}
19 |
20 | {linkedText(
21 | 'Var olmayan @boylebirhesapyok hesabına git.'
22 | )}
23 |
24 |
25 | {linkedText(
26 | 'Route olan @direct linkine hesap olarak gitmeye çalış.'
27 | )}
28 |
29 |
30 |
31 |
32 | )
33 | }
34 |
--------------------------------------------------------------------------------
/components/UserInfo/styles.module.scss:
--------------------------------------------------------------------------------
1 | .userProfileInfo {
2 | @media (max-width: 734.98px) {
3 | margin: 15px;
4 | }
5 | .userFullname {
6 | font-size: 16px;
7 | font-weight: 600;
8 | margin-bottom: 5px;
9 | }
10 | .userBiography {
11 | font-size: 16px;
12 | line-height: 1.5;
13 |
14 | a {
15 | color: var(--tag-blue);
16 | text-decoration: none;
17 | }
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/components/UserPost/styles.module.scss:
--------------------------------------------------------------------------------
1 | .postWrapper {
2 | border: 1px solid var(--border-color);
3 | border-radius: 3px;
4 | background-color: var(--white);
5 | margin-top: 30px;
6 | display: flex;
7 | flex-direction: column;
8 | @media (max-width: 599.98px) {
9 | margin: 0;
10 | margin-bottom: 10px;
11 | border: 0;
12 | background-color: var(--white);
13 | }
14 |
15 | svg {
16 | font-size: 24px;
17 | }
18 |
19 | &:last-child {
20 | margin-bottom: 0;
21 | }
22 |
23 | header {
24 | display: flex;
25 | justify-content: space-between;
26 | align-items: center;
27 | height: 60px;
28 | padding: 0 16px;
29 | .userInfo {
30 | display: flex;
31 | align-items: center;
32 |
33 | svg {
34 | font-size: 32px;
35 | }
36 |
37 | .userName {
38 | margin: 0;
39 | margin-left: 16px;
40 | color: var(--text);
41 | font-size: 14px;
42 | font-weight: 500;
43 | text-decoration: none;
44 |
45 | &:hover {
46 | text-decoration: underline;
47 | }
48 | }
49 | }
50 | }
51 |
52 | .postContent {
53 | .imageWrapper {
54 | position: relative;
55 |
56 | *::selection {
57 | background: transparent;
58 | }
59 |
60 | .heart {
61 | position: absolute;
62 | display: flex;
63 | justify-content: center;
64 | align-items: center;
65 | height: 100%;
66 | width: 100%;
67 | opacity: 0.3;
68 | svg {
69 | transform: scale(0);
70 | font-size: 70px;
71 | }
72 |
73 | svg path {
74 | fill: white;
75 | }
76 |
77 | &.heartAnimate {
78 | animation: likeAnimationOnImage 1s;
79 | svg {
80 | transform: scale(1);
81 | }
82 | }
83 | }
84 | img {
85 | display: block;
86 | width: 100%;
87 | max-height: 500px;
88 | object-fit: cover;
89 | }
90 | }
91 |
92 | .actionButtons {
93 | padding: 4px 6px 0;
94 | display: flex;
95 | align-items: center;
96 | justify-content: flex-start;
97 |
98 | button {
99 | appearance: none;
100 | background-color: transparent;
101 | border: 0;
102 | display: flex;
103 | justify-content: center;
104 | align-items: center;
105 | outline: 0;
106 | cursor: pointer;
107 | width: 40px;
108 | height: 40px;
109 | animation-duration: 300ms;
110 | color: inherit;
111 | }
112 | }
113 |
114 | .postInfo {
115 | padding: 0 16px;
116 | display: flex;
117 | flex-direction: column;
118 | font-size: 14px;
119 |
120 | .likeCount {
121 | font-weight: 500;
122 | padding: 1px 0;
123 | margin-bottom: 4px;
124 | &::selection {
125 | background: transparent;
126 | }
127 | }
128 |
129 | .postDescription {
130 | margin-bottom: 4px;
131 | a {
132 | font-weight: 500;
133 | text-decoration: none;
134 | color: var(--text);
135 | margin-right: 5px;
136 |
137 | &:hover {
138 | text-decoration: underline;
139 | }
140 | }
141 | span {
142 | }
143 | }
144 |
145 | ul.commentsList {
146 | list-style: none;
147 | padding: 0;
148 | margin: 0;
149 |
150 | .commentsCount,
151 | .postTime {
152 | color: var(--muted-text);
153 | }
154 |
155 | .postTime {
156 | text-transform: uppercase;
157 | font-size: 10px;
158 | }
159 |
160 | li {
161 | margin-bottom: 4px;
162 |
163 | a {
164 | color: var(--tag-blue);
165 | text-decoration: none;
166 | }
167 | span {
168 | margin-right: 5px;
169 |
170 | a {
171 | font-weight: 500;
172 | color: var(--text);
173 | text-decoration: none;
174 | }
175 | }
176 | }
177 | }
178 | }
179 | }
180 |
181 | .commentForm {
182 | padding-top: 5px;
183 |
184 | .formWrapper {
185 | border-top: 1px solid var(--border-light-color);
186 | padding: 0 16px;
187 | margin-top: 4px;
188 |
189 | form {
190 | display: flex;
191 | align-items: center;
192 | height: 56px;
193 | }
194 |
195 | input {
196 | all: unset;
197 | flex: 1;
198 | height: 100%;
199 | display: block;
200 | font-size: 14px;
201 |
202 | &::placeholder {
203 | color: var(--muted-text);
204 | }
205 | }
206 |
207 | button {
208 | all: unset;
209 | height: 100%;
210 | display: block;
211 | color: var(--blue);
212 | font-weight: 500;
213 | cursor: pointer;
214 |
215 | &:disabled {
216 | cursor: auto;
217 | opacity: 0.5;
218 | }
219 | }
220 | }
221 | }
222 | }
223 | .fillRed {
224 | animation-name: likeAnimation;
225 | }
226 | .fillRed svg path {
227 | fill: var(--red);
228 | transition: 300ms fill;
229 | }
230 | @keyframes likeAnimation {
231 | 0% {
232 | transform: scale(1);
233 | }
234 | 50% {
235 | transform: scale(1.2);
236 | }
237 | 100% {
238 | transform: scale(1);
239 | }
240 | }
241 | @keyframes likeAnimationOnImage {
242 | 0% {
243 | opacity: 1;
244 | transform: scale(0.5);
245 | }
246 | 25% {
247 | opacity: 1;
248 | transform: scale(1.1);
249 | }
250 | 50% {
251 | opacity: 1;
252 | transform: scale(1);
253 | }
254 | 75% {
255 | opacity: 1;
256 | transform: scale(1);
257 | }
258 | 100% {
259 | opacity: 0;
260 | transform: scale(0.5);
261 | }
262 | }
263 |
--------------------------------------------------------------------------------
/components/UserPosts/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import styles from './styles.module.scss'
3 | import Link from 'next/link'
4 | import { getUserPosts, getUserIdFromUsername } from '../../lib/db'
5 | import { useRouter } from 'next/router'
6 | import usePostsFormat from '../../hooks/usePostsFormat'
7 |
8 | const UserPosts = () => {
9 | const router = useRouter()
10 | const { username } = router.query
11 | const [postsList, setPostsList] = React.useState([])
12 |
13 | React.useEffect(async () => {
14 | const getPosts = (username) => {
15 | return new Promise(async (resolve, reject) => {
16 | const id = await getUserIdFromUsername(username).then(
17 | (res) => res
18 | )
19 | const userPosts = await getUserPosts(id)
20 | resolve(userPosts)
21 | })
22 | }
23 | const list = await getPosts(username).then((res) => res)
24 |
25 | setPostsList(usePostsFormat(list))
26 | }, [username])
27 |
28 | return (
29 |
30 | {postsList.map((row, index) => {
31 | return (
32 |
33 | {row.map((column, index) => {
34 | return (
35 |
39 |
40 | {Object.entries(column).length ? (
41 |
42 |
43 |
48 |

52 |
53 |
54 |
55 | ) : (
56 | ''
57 | )}
58 |
59 |
60 | )
61 | })}
62 |
63 | )
64 | })}
65 |
66 | )
67 | }
68 | export default UserPosts
69 |
--------------------------------------------------------------------------------
/components/UserPosts/styles.module.scss:
--------------------------------------------------------------------------------
1 | .userPosts {
2 | --gap: 28px;
3 | display: flex;
4 | flex-direction: column;
5 | align-items: stretch;
6 | z-index: 10;
7 | width: 100%;
8 | height: 100%;
9 |
10 | img {
11 | object-fit: cover;
12 | width: 100%;
13 | height: 100%;
14 | }
15 |
16 | @media (max-width: 734.98px) {
17 | --gap: 2px;
18 | }
19 |
20 | .userPostsRow {
21 | display: flex;
22 | margin-bottom: var(--gap);
23 |
24 | .userPostWrapper {
25 | width: 100%;
26 | margin-right: var(--gap);
27 |
28 | &:last-child {
29 | margin-right: 0;
30 | }
31 | }
32 |
33 | .userPostColumn {
34 | position: relative;
35 | width: 100%;
36 | padding-bottom: 100%;
37 | overflow: hidden;
38 |
39 | a {
40 | position: absolute;
41 | top: 0;
42 | left: 0;
43 | bottom: 0;
44 | right: 0;
45 | }
46 |
47 | .userPost {
48 | height: 100%;
49 | }
50 | }
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/components/UserStatistics/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import styles from './styles.module.scss'
3 |
4 | export default function UserStatistics(props) {
5 | const { postsCount, followersCount, followingsCount } = props.statistics
6 | return (
7 |
8 | -
9 | {postsCount}
10 | gönderi
11 |
12 | -
13 | {followersCount}
14 | takipçi
15 |
16 | -
17 | {followingsCount}
18 | takip
19 |
20 |
21 | )
22 | }
23 |
--------------------------------------------------------------------------------
/components/UserStatistics/styles.module.scss:
--------------------------------------------------------------------------------
1 | .userStatistics {
2 | margin-bottom: 20px;
3 | list-style: none;
4 | display: flex;
5 | align-items: center;
6 | flex-wrap: nowrap;
7 |
8 | @media (max-width: 734.98px) {
9 | margin: 0;
10 | justify-content: space-between;
11 | max-width: 400px;
12 | margin: 0 40px 0 0px;
13 | }
14 |
15 | li {
16 | margin-right: 40px;
17 | display: flex;
18 |
19 | @media (max-width: 734.98px) {
20 | flex-direction: column;
21 | align-items: center;
22 | margin-right: 0;
23 | }
24 |
25 | &:last-child {
26 | margin-right: 0;
27 | }
28 |
29 | span {
30 | @media (max-width: 734.98px) {
31 | text-transform: capitalize;
32 | font-size: 14px;
33 | }
34 |
35 | &.count {
36 | font-weight: 500;
37 | margin-right: 5px;
38 | font-size: 16px;
39 |
40 | @media (max-width: 734.98px) {
41 | margin-right: 0;
42 | }
43 | }
44 | }
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/hooks/usePostsFormat.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 |
3 | const usePostsFormat = (list) => {
4 | let rows = [],
5 | columns = []
6 | list.map((post, index) => {
7 | index++
8 | if (index % 3 == 0) {
9 | columns.push(post)
10 | rows.push(columns)
11 | columns = []
12 | } else {
13 | columns.push(post)
14 | }
15 | })
16 | const remaining = list.length % 3
17 | if (remaining) {
18 | let add = 3 - remaining
19 | for (let index = 0; index < add; index++) {
20 | columns.push({})
21 | }
22 | rows.push(columns)
23 | }
24 |
25 | return rows
26 | }
27 |
28 | export default usePostsFormat
29 |
--------------------------------------------------------------------------------
/hooks/useWindowSize.js:
--------------------------------------------------------------------------------
1 | import { useState, useEffect } from 'react';
2 |
3 | export default function useWindowSize() {
4 | const [windowSize, setWindowSize] = useState({
5 | width: undefined,
6 | height: undefined,
7 | });
8 | useEffect(() => {
9 | const handleResize = () => {
10 | setWindowSize({
11 | width: window.innerWidth,
12 | height: window.innerHeight,
13 | });
14 | }
15 | window.addEventListener("resize", handleResize);
16 | handleResize();
17 | return () => window.removeEventListener("resize", handleResize);
18 | }, []);
19 | return windowSize;
20 | }
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/icons/AddPost.js:
--------------------------------------------------------------------------------
1 | import * as React from 'react'
2 |
3 | function SvgAddPost(props) {
4 | return (
5 |
26 | )
27 | }
28 |
29 | export default SvgAddPost
30 |
--------------------------------------------------------------------------------
/icons/Back.js:
--------------------------------------------------------------------------------
1 | import * as React from 'react'
2 |
3 | function SvgBack(props) {
4 | return (
5 |
18 | )
19 | }
20 |
21 | export default SvgBack
22 |
--------------------------------------------------------------------------------
/icons/Bookmark.js:
--------------------------------------------------------------------------------
1 | import * as React from 'react'
2 |
3 | function SvgBookmark(props) {
4 | return (
5 |
25 | )
26 | }
27 |
28 | export default SvgBookmark
29 |
--------------------------------------------------------------------------------
/icons/BookmarkFill.js:
--------------------------------------------------------------------------------
1 | import * as React from 'react'
2 |
3 | function SvgBookmarkFill(props) {
4 | return (
5 |
25 | )
26 | }
27 |
28 | export default SvgBookmarkFill
29 |
--------------------------------------------------------------------------------
/icons/Camera.js:
--------------------------------------------------------------------------------
1 | import * as React from 'react'
2 |
3 | function SvgCamera(props) {
4 | return (
5 |
20 | )
21 | }
22 |
23 | export default SvgCamera
24 |
--------------------------------------------------------------------------------
/icons/Close.js:
--------------------------------------------------------------------------------
1 | import * as React from 'react'
2 |
3 | function SvgClose(props) {
4 | return (
5 |
20 | )
21 | }
22 |
23 | export default SvgClose
24 |
--------------------------------------------------------------------------------
/icons/Comment.js:
--------------------------------------------------------------------------------
1 | import * as React from 'react'
2 |
3 | function SvgComment(props) {
4 | return (
5 |
20 | )
21 | }
22 |
23 | export default SvgComment
24 |
--------------------------------------------------------------------------------
/icons/Emoji.js:
--------------------------------------------------------------------------------
1 | import * as React from 'react'
2 |
3 | function SvgEmoji(props) {
4 | return (
5 |
22 | )
23 | }
24 |
25 | export default SvgEmoji
26 |
--------------------------------------------------------------------------------
/icons/Explore.js:
--------------------------------------------------------------------------------
1 | import * as React from 'react'
2 |
3 | function SvgExplore(props) {
4 | return (
5 |
20 | )
21 | }
22 |
23 | export default SvgExplore
24 |
--------------------------------------------------------------------------------
/icons/ExploreFill.js:
--------------------------------------------------------------------------------
1 | import * as React from 'react'
2 |
3 | function SvgExploreFill(props) {
4 | return (
5 |
20 | )
21 | }
22 |
23 | export default SvgExploreFill
24 |
--------------------------------------------------------------------------------
/icons/Home.js:
--------------------------------------------------------------------------------
1 | import * as React from 'react'
2 |
3 | function SvgHome(props) {
4 | return (
5 |
25 | )
26 | }
27 |
28 | export default SvgHome
29 |
--------------------------------------------------------------------------------
/icons/HomeFill.js:
--------------------------------------------------------------------------------
1 | import * as React from 'react'
2 |
3 | function SvgHomeFill(props) {
4 | return (
5 |
25 | )
26 | }
27 |
28 | export default SvgHomeFill
29 |
--------------------------------------------------------------------------------
/icons/Info.js:
--------------------------------------------------------------------------------
1 | import * as React from 'react'
2 |
3 | function SvgInfo(props) {
4 | return (
5 |
26 | )
27 | }
28 |
29 | export default SvgInfo
30 |
--------------------------------------------------------------------------------
/icons/Like.js:
--------------------------------------------------------------------------------
1 | import * as React from 'react'
2 |
3 | function SvgLike(props) {
4 | return (
5 |
25 | )
26 | }
27 |
28 | export default SvgLike
29 |
--------------------------------------------------------------------------------
/icons/LikeFill.js:
--------------------------------------------------------------------------------
1 | import * as React from 'react'
2 |
3 | function SvgLikeFill(props) {
4 | return (
5 |
18 | )
19 | }
20 |
21 | export default SvgLikeFill
22 |
--------------------------------------------------------------------------------
/icons/Loader.js:
--------------------------------------------------------------------------------
1 | import * as React from 'react'
2 |
3 | function SvgLoader(props) {
4 | return (
5 |
57 | )
58 | }
59 |
60 | export default SvgLoader
61 |
--------------------------------------------------------------------------------
/icons/Message.js:
--------------------------------------------------------------------------------
1 | import * as React from 'react'
2 |
3 | function SvgMessage(props) {
4 | return (
5 |
25 | )
26 | }
27 |
28 | export default SvgMessage
29 |
--------------------------------------------------------------------------------
/icons/MessageFill.js:
--------------------------------------------------------------------------------
1 | import * as React from 'react'
2 |
3 | function SvgMessageFill(props) {
4 | return (
5 |
25 | )
26 | }
27 |
28 | export default SvgMessageFill
29 |
--------------------------------------------------------------------------------
/icons/NewMessage.js:
--------------------------------------------------------------------------------
1 | import * as React from 'react'
2 |
3 | function SvgNewMessage(props) {
4 | return (
5 |
24 | )
25 | }
26 |
27 | export default SvgNewMessage
28 |
--------------------------------------------------------------------------------
/icons/Options.js:
--------------------------------------------------------------------------------
1 | import * as React from 'react'
2 |
3 | function SvgOptions(props) {
4 | return (
5 |
20 | )
21 | }
22 |
23 | export default SvgOptions
24 |
--------------------------------------------------------------------------------
/icons/Photo.js:
--------------------------------------------------------------------------------
1 | import * as React from 'react'
2 |
3 | function SvgPhoto(props) {
4 | return (
5 |
18 | )
19 | }
20 |
21 | export default SvgPhoto
22 |
--------------------------------------------------------------------------------
/icons/Posts.js:
--------------------------------------------------------------------------------
1 | import * as React from 'react'
2 |
3 | function SvgPosts(props) {
4 | return (
5 |
20 | )
21 | }
22 |
23 | export default SvgPosts
24 |
--------------------------------------------------------------------------------
/icons/Preferences.js:
--------------------------------------------------------------------------------
1 | import * as React from 'react'
2 |
3 | function SvgPreferences(props) {
4 | return (
5 |
18 | )
19 | }
20 |
21 | export default SvgPreferences
22 |
--------------------------------------------------------------------------------
/icons/Search.js:
--------------------------------------------------------------------------------
1 | import * as React from 'react'
2 |
3 | function SvgSearch(props) {
4 | return (
5 |
23 | )
24 | }
25 |
26 | export default SvgSearch
27 |
--------------------------------------------------------------------------------
/icons/Tagged.js:
--------------------------------------------------------------------------------
1 | import * as React from 'react'
2 |
3 | function SvgTagged(props) {
4 | return (
5 |
18 | )
19 | }
20 |
21 | export default SvgTagged
22 |
--------------------------------------------------------------------------------
/icons/User.js:
--------------------------------------------------------------------------------
1 | import * as React from 'react'
2 |
3 | function SvgUser(props) {
4 | return (
5 |
18 | )
19 | }
20 |
21 | export default SvgUser
22 |
--------------------------------------------------------------------------------
/icons/index.js:
--------------------------------------------------------------------------------
1 | export { default as AddPost } from './AddPost'
2 | export { default as Back } from './Back'
3 | export { default as Bookmark } from './Bookmark'
4 | export { default as BookmarkFill } from './BookmarkFill'
5 | export { default as Camera } from './Camera'
6 | export { default as Close } from './Close'
7 | export { default as Comment } from './Comment'
8 | export { default as Emoji } from './Emoji'
9 | export { default as Explore } from './Explore'
10 | export { default as ExploreFill } from './ExploreFill'
11 | export { default as Home } from './Home'
12 | export { default as HomeFill } from './HomeFill'
13 | export { default as Info } from './Info'
14 | export { default as Like } from './Like'
15 | export { default as LikeFill } from './LikeFill'
16 | export { default as Loader } from './Loader'
17 | export { default as Message } from './Message'
18 | export { default as MessageFill } from './MessageFill'
19 | export { default as NewMessage } from './NewMessage'
20 | export { default as Options } from './Options'
21 | export { default as Photo } from './Photo'
22 | export { default as Posts } from './Posts'
23 | export { default as Preferences } from './Preferences'
24 | export { default as Search } from './Search'
25 | export { default as Tagged } from './Tagged'
26 | export { default as User } from './User'
--------------------------------------------------------------------------------
/lib/auth.js:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect, useContext, createContext } from 'react'
2 | import Router from 'next/router'
3 | import cookie from 'js-cookie'
4 | import firebase from './firebase'
5 | const authContext = createContext()
6 | export function AuthProvider({ children }) {
7 | const auth = useProvideAuth()
8 | return {children}
9 | }
10 | export const useAuth = () => {
11 | return useContext(authContext)
12 | }
13 | function useProvideAuth() {
14 | const [user, setUser] = useState(null)
15 | const [loading, setLoading] = useState(true)
16 | const handleUser = async (rawUser) => {
17 | if (rawUser) {
18 | const user = await formatUser(rawUser)
19 | const { token, ...userWithoutToken } = user
20 | setUser(user)
21 | cookie.set('instagram-clone-auth', true, {
22 | expires: 1,
23 | })
24 | setLoading(false)
25 | return user
26 | } else {
27 | setUser(false)
28 | cookie.remove('instagram-clone-auth')
29 | setLoading(false)
30 | return false
31 | }
32 | }
33 | const signIn = (email, password) => {
34 | setLoading(true)
35 | return firebase
36 | .auth()
37 | .signInWithEmailAndPassword(email, password)
38 | .then((response) => {
39 | handleUser(response.user)
40 | Router.push('/')
41 | })
42 | .catch((error) => {
43 | setLoading(false)
44 | return error
45 | })
46 | }
47 | const signout = () => {
48 | Router.push('/')
49 | return firebase
50 | .auth()
51 | .signOut()
52 | .then(() => handleUser(false))
53 | }
54 | useEffect(() => {
55 | const unsubscribe = firebase.auth().onIdTokenChanged(handleUser)
56 | return () => unsubscribe()
57 | }, [])
58 | return {
59 | user,
60 | loading,
61 | signIn,
62 | signout,
63 | }
64 | }
65 | const formatUser = async (user) => {
66 | return {
67 | id: user.uid,
68 | email: user.email,
69 | token: user.xa,
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/lib/db.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import firebase from './firebase'
3 | import { useAuth } from './auth'
4 | const app = firebase.app()
5 | const firestore = firebase.firestore()
6 | const storageRef = firebase.storage().ref()
7 |
8 | /* -------------------------------------------------------------------------- */
9 | /* Control Functions */
10 | /* -------------------------------------------------------------------------- */
11 |
12 | export const usernameExist = async (username) => {
13 | const query = firestore
14 | .collection('users')
15 | .where('username', '==', username)
16 |
17 | return await query.get().then((users) => {
18 | return users.docs.length ? true : false
19 | })
20 | }
21 |
22 | export const searchUser = async (searchText) => {
23 | const query = firestore.collection('users')
24 |
25 | return await query.get().then((users) => {
26 | let result = []
27 | users.docs.forEach((user) => {
28 | const data = user.data()
29 | if (
30 | searchText.length > 0 &&
31 | (data.username
32 | .toLowerCase()
33 | .includes(searchText.toLowerCase()) ||
34 | data.name.toLowerCase().includes(searchText.toLowerCase()))
35 | ) {
36 | result.push(data)
37 | }
38 | })
39 | return result
40 | })
41 | }
42 |
43 | /* -------------------------------------------------------------------------- */
44 | /* Insert Functions */
45 | /* -------------------------------------------------------------------------- */
46 |
47 | export const signUp = async (email, password, username, name) => {
48 | const isExistUsername = await usernameExist(username.trim())
49 | if (!isExistUsername) {
50 | return firebase
51 | .auth()
52 | .createUserWithEmailAndPassword(email, password)
53 | .then((res) => {
54 | const user = res.user
55 | const id = user.uid
56 | return firestore.collection('users').doc(id).set({
57 | username,
58 | email,
59 | name,
60 | createdAt: new Date(),
61 | })
62 | })
63 | .catch((error) => {
64 | return error
65 | })
66 | } else {
67 | return {
68 | message:
69 | 'Bu kullanıcı adı alınamıyor. Lütfen başka bir kullanıcı adı dene.',
70 | }
71 | }
72 |
73 | // return firestore
74 | // .collection('users')
75 | // .doc(uid)
76 | // .set({ uid, ...data }, { merge: true })
77 | }
78 |
79 | /* -------------------------------------------------------------------------- */
80 | /* Select Functions */
81 | /* -------------------------------------------------------------------------- */
82 |
83 | export const getUserData = async (id) => {
84 | if (!id) {
85 | return false
86 | }
87 | const userData = await firestore
88 | .collection('users')
89 | .doc(id)
90 | .get()
91 | .then((user) => {
92 | return {
93 | id,
94 | ...user.data(),
95 | }
96 | })
97 | .catch((error) => {
98 | console.log(error.message)
99 | })
100 | return userData
101 | }
102 |
103 | export const getUserIdFromUsername = (username) => {
104 | return new Promise(async (resolve, reject) => {
105 | if (!username) {
106 | reject(false)
107 | }
108 | const userData = await firestore
109 | .collection('users')
110 | .where('username', '==', username)
111 | .get()
112 | if (userData.docs.length) {
113 | resolve(userData.docs[0].id)
114 | }
115 | reject(false)
116 | })
117 | }
118 |
119 | /* -------------------------------------------------------------------------- */
120 | /* Storage Functions */
121 | /* -------------------------------------------------------------------------- */
122 |
123 | export const uploadPost = (id, post) => {
124 | storageRef
125 | .child(`posts/${id}/${Date.now()}/${post.file.name}`)
126 | .put(post.file)
127 | .then(async (snapshot) => {
128 | const downloadURL = await snapshot.ref.getDownloadURL()
129 | const filePath = snapshot.ref.fullPath
130 | firestore.collection(`users/${id}/posts`).doc().set({
131 | caption: post.caption,
132 | image: downloadURL,
133 | imageRef: filePath,
134 | time: post.time,
135 | })
136 | return true
137 | })
138 | }
139 |
140 | export const getUserPosts = async (id) => {
141 | const query = firestore
142 | .collection(`users/${id}/posts`)
143 | .orderBy('time', 'desc')
144 | .get()
145 | const posts = await query
146 |
147 | if (!posts.docs.length) {
148 | return []
149 | }
150 |
151 | let userPosts = []
152 | for (const post of posts.docs) {
153 | const postData = post.data()
154 | userPosts.push({
155 | ...postData,
156 | id: post.id,
157 | })
158 | }
159 | return userPosts
160 | }
161 |
162 | // export function createSite(data) {
163 | // const site = firestore.collection('sites').doc()
164 | // site.set(data)
165 |
166 | // return site
167 | // }
168 |
169 | // export async function deleteSite(id) {
170 | // firestore.collection('sites').doc(id).delete()
171 | // const snapshot = await firestore
172 | // .collection('feedback')
173 | // .where('siteId', '==', id)
174 | // .get()
175 |
176 | // const batch = firestore.batch()
177 |
178 | // snapshot.forEach((doc) => {
179 | // batch.delete(doc.ref)
180 | // })
181 |
182 | // return batch.commit()
183 | // }
184 |
185 | // export async function updateSite(id, newValues) {
186 | // return firestore.collection('sites').doc(id).update(newValues)
187 | // }
188 |
189 | // export function createFeedback(data) {
190 | // return firestore.collection('feedback').add(data)
191 | // }
192 |
193 | // export function deleteFeedback(id) {
194 | // return firestore.collection('feedback').doc(id).delete()
195 | // }
196 |
197 | // export function updateFeedback(id, newValues) {
198 | // return firestore.collection('feedback').doc(id).update(newValues)
199 | // }
200 |
201 | // export async function createCheckoutSession(uid) {
202 | // const checkoutSessionRef = await firestore
203 | // .collection('users')
204 | // .doc(uid)
205 | // .collection('checkout_sessions')
206 | // .add({
207 | // price: process.env.NEXT_PUBLIC_PRICE_ID,
208 | // allow_promotion_codes: true,
209 | // success_url: window.location.origin,
210 | // cancel_url: window.location.origin,
211 | // })
212 |
213 | // checkoutSessionRef.onSnapshot(async (snap) => {
214 | // const { sessionId } = snap.data()
215 |
216 | // if (sessionId) {
217 | // const stripe = await getStripe()
218 |
219 | // stripe.redirectToCheckout({ sessionId })
220 | // }
221 | // })
222 | // }
223 |
--------------------------------------------------------------------------------
/lib/firebase.js:
--------------------------------------------------------------------------------
1 | import firebase from 'firebase'
2 | import 'firebase/auth'
3 | import 'firebase/functions'
4 | import 'firebase/firestore'
5 | import 'firebase/storage'
6 |
7 | if (!firebase.apps.length) {
8 | firebase.initializeApp({
9 | apiKey: process.env.FIREBASE_API_KEY,
10 | authDomain: process.env.FIREBASE_AUTH_DOMAIN,
11 | databaseURL: process.env.FIREBASE_DATABASE_URL,
12 | projectId: process.env.FIREBASE_PROJECT_ID,
13 | storageBucket: process.env.FIREBASE_STORAGE_BUCKET,
14 | messagingSenderId: process.env.FIREBASE_MESSAGING_SENDER_ID,
15 | appId: process.env.FIREBASE_APP_ID,
16 | })
17 | }
18 |
19 | export default firebase
20 |
--------------------------------------------------------------------------------
/next.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | env: {
3 | FIREBASE_API_KEY: 'AIzaSyD7pqsPi5LLq121Y5e4FbkI5RkPFW03bH4',
4 | FIREBASE_AUTH_DOMAIN: 'instagram-clone-45093.firebaseapp.com',
5 | FIREBASE_DATABASE_URL:
6 | 'https://instagram-clone-45093-default-rtdb.firebaseio.com',
7 | FIREBASE_PROJECT_ID: 'instagram-clone-45093',
8 | FIREBASE_STORAGE_BUCKET: 'instagram-clone-45093.appspot.com',
9 | FIREBASE_MESSAGING_SENDER_ID: '820550670430',
10 | FIREBASE_APP_ID: '1:820550670430:web:8aa8ca9925e5ca405bbccf',
11 | },
12 | }
13 |
--------------------------------------------------------------------------------
/next.config.template.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | env: {
3 | FIREBASE_API_KEY: 'FIREBASE_API_KEY',
4 | FIREBASE_AUTH_DOMAIN: 'FIREBASE_AUTH_DOMAIN',
5 | FIREBASE_DATABASE_URL: 'FIREBASE_DATABASE_URL',
6 | FIREBASE_PROJECT_ID: 'FIREBASE_PROJECT_ID',
7 | FIREBASE_STORAGE_BUCKET: 'FIREBASE_STORAGE_BUCKET',
8 | FIREBASE_MESSAGING_SENDER_ID: 'FIREBASE_MESSAGING_SENDER_ID',
9 | FIREBASE_APP_ID: 'FIREBASE_APP_ID',
10 | },
11 | }
12 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "next-instragram-clone-test",
3 | "version": "0.1.0",
4 | "private": true,
5 | "scripts": {
6 | "dev": "next dev",
7 | "build": "next build",
8 | "start": "next start",
9 | "svgtocomponent": "npx @svgr/cli -d icons svgs --icon --replace-attr-values #262626=currentColor"
10 | },
11 | "dependencies": {
12 | "classnames": "^2.2.6",
13 | "firebase": "^8.2.1",
14 | "js-cookie": "^2.2.1",
15 | "next": "10.0.4",
16 | "react": "17.0.1",
17 | "react-dom": "17.0.1",
18 | "react-spinners": "^0.10.4",
19 | "react-timeago": "^5.2.0"
20 | },
21 | "devDependencies": {
22 | "sass": "^1.32.0"
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/pages/404.js:
--------------------------------------------------------------------------------
1 | import NotFoundScreen from '../components/NotFoundScreen'
2 |
3 | export default function NotFoundPage() {
4 | return
5 | }
6 |
--------------------------------------------------------------------------------
/pages/[username]/[[...index]].js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import Profile from '../../components/Profile'
3 | import NotFoundScreen from '../../components/NotFoundScreen'
4 | import { useAuth } from '../../lib/auth'
5 | import { useRouter } from 'next/router'
6 | import Loader from '../../components/Loader'
7 | import { usernameExist } from '../../lib/db'
8 |
9 | const ProfilePage = () => {
10 | const router = useRouter()
11 | const { user, loading } = useAuth()
12 | const [isUserExist, setIsUserExist] = React.useState(false)
13 |
14 | const [userExistLoad, setUserExistLoad] = React.useState(true)
15 |
16 | React.useEffect(async () => {
17 | if (typeof router.query.username != 'undefined') {
18 | const query = await usernameExist(router.query.username)
19 | query ? setIsUserExist(true) : setIsUserExist(false)
20 | setUserExistLoad(false)
21 | }
22 | }, [router.query.username])
23 |
24 | if (loading || userExistLoad) {
25 | return
26 | } else {
27 | if (!isUserExist || !user) {
28 | return
29 | } else {
30 | return
31 | }
32 | }
33 | }
34 | export default ProfilePage
35 |
--------------------------------------------------------------------------------
/pages/_app.js:
--------------------------------------------------------------------------------
1 | import '../styles/globals.scss'
2 | import AppHeader from '../components/AppHeader'
3 | import Head from 'next/head'
4 | import Container from '../components/Container'
5 | import { AuthProvider } from '../lib/auth'
6 | export default function Instagram({ Component, pageProps }) {
7 | return (
8 |
9 |
10 |
11 |
15 | Instagram Clone App
16 |
17 |
18 |
19 |
20 |
21 | )
22 | }
23 |
--------------------------------------------------------------------------------
/pages/accounts/emailsignup.js:
--------------------------------------------------------------------------------
1 | import SignUpScreen from '../../components/SignUpScreen'
2 | import { useAuth } from '../../lib/auth'
3 | import Router from 'next/router'
4 |
5 | export default function SignUp() {
6 | const { user } = useAuth()
7 | if (user) {
8 | Router.push('/')
9 | }
10 | return
11 | }
12 |
--------------------------------------------------------------------------------
/pages/api/hello.js:
--------------------------------------------------------------------------------
1 | // Next.js API route support: https://nextjs.org/docs/api-routes/introduction
2 |
3 | export default (req, res) => {
4 | res.statusCode = 200
5 | res.json({ name: 'John Doe' })
6 | }
7 |
--------------------------------------------------------------------------------
/pages/direct/[[...index]].js:
--------------------------------------------------------------------------------
1 | import InboxScreen from '../../components/InboxScreen'
2 | import Loader from '../../components/Loader'
3 | import { useAuth } from '../../lib/auth'
4 | import { useRouter } from 'next/router'
5 |
6 | export default function direct() {
7 | const router = useRouter()
8 | const { user, loading } = useAuth()
9 |
10 | if (loading) {
11 | return
12 | } else {
13 | if (!user) {
14 | router.push('/')
15 | return <>>
16 | } else {
17 | return
18 | }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/pages/index.js:
--------------------------------------------------------------------------------
1 | import HomeLayout from '../components/HomeLayout'
2 | import SignInScreen from '../components/SignInScreen'
3 | import { useAuth } from '../lib/auth'
4 | import Loader from '../components/Loader'
5 |
6 | const Home = () => {
7 | const { user, loading } = useAuth()
8 |
9 | return (
10 | <>
11 | {user ? : }
12 | {loading ? : ''}
13 | >
14 | )
15 | }
16 | export default Home
17 |
--------------------------------------------------------------------------------
/public/betul.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owuzan/next-instagram-clone/bfe0eee5c9d737a4bffff4ed9aef8dbbd3952434/public/betul.jpg
--------------------------------------------------------------------------------
/public/bill.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owuzan/next-instagram-clone/bfe0eee5c9d737a4bffff4ed9aef8dbbd3952434/public/bill.jpg
--------------------------------------------------------------------------------
/public/elon.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owuzan/next-instagram-clone/bfe0eee5c9d737a4bffff4ed9aef8dbbd3952434/public/elon.jpg
--------------------------------------------------------------------------------
/public/erkan.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owuzan/next-instagram-clone/bfe0eee5c9d737a4bffff4ed9aef8dbbd3952434/public/erkan.jpg
--------------------------------------------------------------------------------
/public/erkan2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owuzan/next-instagram-clone/bfe0eee5c9d737a4bffff4ed9aef8dbbd3952434/public/erkan2.jpg
--------------------------------------------------------------------------------
/public/facebook-logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owuzan/next-instagram-clone/bfe0eee5c9d737a4bffff4ed9aef8dbbd3952434/public/facebook-logo.png
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owuzan/next-instagram-clone/bfe0eee5c9d737a4bffff4ed9aef8dbbd3952434/public/favicon.ico
--------------------------------------------------------------------------------
/public/hasan.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owuzan/next-instagram-clone/bfe0eee5c9d737a4bffff4ed9aef8dbbd3952434/public/hasan.jpg
--------------------------------------------------------------------------------
/public/instagram-dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owuzan/next-instagram-clone/bfe0eee5c9d737a4bffff4ed9aef8dbbd3952434/public/instagram-dark.png
--------------------------------------------------------------------------------
/public/instagram.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owuzan/next-instagram-clone/bfe0eee5c9d737a4bffff4ed9aef8dbbd3952434/public/instagram.png
--------------------------------------------------------------------------------
/public/ivana.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owuzan/next-instagram-clone/bfe0eee5c9d737a4bffff4ed9aef8dbbd3952434/public/ivana.jpg
--------------------------------------------------------------------------------
/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "React App",
3 | "name": "Instagram",
4 | // "icons": [
5 | // {
6 | // "src": "favicon.ico",
7 | // "sizes": "64x64 32x32 24x24 16x16",
8 | // "type": "image/x-icon"
9 | // },
10 | // {
11 | // "src": "logo192.png",
12 | // "type": "image/png",
13 | // "sizes": "192x192"
14 | // },
15 | // {
16 | // "src": "logo512.png",
17 | // "type": "image/png",
18 | // "sizes": "512x512"
19 | // }
20 | // ],
21 | "start_url": ".",
22 | "display": "standalone",
23 | "theme_color": "#000000",
24 | "background_color": "#ffffff"
25 | }
26 |
--------------------------------------------------------------------------------
/public/mustafa.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owuzan/next-instagram-clone/bfe0eee5c9d737a4bffff4ed9aef8dbbd3952434/public/mustafa.jpg
--------------------------------------------------------------------------------
/public/owuzan.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owuzan/next-instagram-clone/bfe0eee5c9d737a4bffff4ed9aef8dbbd3952434/public/owuzan.jpg
--------------------------------------------------------------------------------
/public/owuzan/1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owuzan/next-instagram-clone/bfe0eee5c9d737a4bffff4ed9aef8dbbd3952434/public/owuzan/1.jpg
--------------------------------------------------------------------------------
/public/owuzan/10.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owuzan/next-instagram-clone/bfe0eee5c9d737a4bffff4ed9aef8dbbd3952434/public/owuzan/10.jpg
--------------------------------------------------------------------------------
/public/owuzan/11.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owuzan/next-instagram-clone/bfe0eee5c9d737a4bffff4ed9aef8dbbd3952434/public/owuzan/11.jpg
--------------------------------------------------------------------------------
/public/owuzan/2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owuzan/next-instagram-clone/bfe0eee5c9d737a4bffff4ed9aef8dbbd3952434/public/owuzan/2.jpg
--------------------------------------------------------------------------------
/public/owuzan/3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owuzan/next-instagram-clone/bfe0eee5c9d737a4bffff4ed9aef8dbbd3952434/public/owuzan/3.jpg
--------------------------------------------------------------------------------
/public/owuzan/4.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owuzan/next-instagram-clone/bfe0eee5c9d737a4bffff4ed9aef8dbbd3952434/public/owuzan/4.jpg
--------------------------------------------------------------------------------
/public/owuzan/5.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owuzan/next-instagram-clone/bfe0eee5c9d737a4bffff4ed9aef8dbbd3952434/public/owuzan/5.jpg
--------------------------------------------------------------------------------
/public/owuzan/6.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owuzan/next-instagram-clone/bfe0eee5c9d737a4bffff4ed9aef8dbbd3952434/public/owuzan/6.jpg
--------------------------------------------------------------------------------
/public/owuzan/7.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owuzan/next-instagram-clone/bfe0eee5c9d737a4bffff4ed9aef8dbbd3952434/public/owuzan/7.jpg
--------------------------------------------------------------------------------
/public/owuzan/8.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owuzan/next-instagram-clone/bfe0eee5c9d737a4bffff4ed9aef8dbbd3952434/public/owuzan/8.jpg
--------------------------------------------------------------------------------
/public/owuzan/9.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owuzan/next-instagram-clone/bfe0eee5c9d737a4bffff4ed9aef8dbbd3952434/public/owuzan/9.jpg
--------------------------------------------------------------------------------
/public/photo-example.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owuzan/next-instagram-clone/bfe0eee5c9d737a4bffff4ed9aef8dbbd3952434/public/photo-example.jpg
--------------------------------------------------------------------------------
/public/robots.txt:
--------------------------------------------------------------------------------
1 | # https://www.robotstxt.org/robotstxt.html
2 | User-agent: *
3 | Disallow:
4 |
--------------------------------------------------------------------------------
/public/ronaldo.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owuzan/next-instagram-clone/bfe0eee5c9d737a4bffff4ed9aef8dbbd3952434/public/ronaldo.jpg
--------------------------------------------------------------------------------
/public/serdar.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owuzan/next-instagram-clone/bfe0eee5c9d737a4bffff4ed9aef8dbbd3952434/public/serdar.jpg
--------------------------------------------------------------------------------
/public/sign-up.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owuzan/next-instagram-clone/bfe0eee5c9d737a4bffff4ed9aef8dbbd3952434/public/sign-up.png
--------------------------------------------------------------------------------
/public/suleyman-example.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owuzan/next-instagram-clone/bfe0eee5c9d737a4bffff4ed9aef8dbbd3952434/public/suleyman-example.jpg
--------------------------------------------------------------------------------
/public/suleyman.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owuzan/next-instagram-clone/bfe0eee5c9d737a4bffff4ed9aef8dbbd3952434/public/suleyman.jpg
--------------------------------------------------------------------------------
/public/user.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owuzan/next-instagram-clone/bfe0eee5c9d737a4bffff4ed9aef8dbbd3952434/public/user.jpg
--------------------------------------------------------------------------------
/styles/globals.scss:
--------------------------------------------------------------------------------
1 | *,
2 | *::before,
3 | *::after {
4 | box-sizing: border-box;
5 | margin: 0;
6 | padding: 0;
7 | -webkit-font-smoothing: antialiased;
8 | -moz-osx-font-smoothing: grayscale;
9 | }
10 | :root {
11 | --white: #ffffff;
12 | --background-color: #fafafa;
13 | --input-background: #fafafa;
14 | --border-color: #dbdbdb;
15 | --border-light-color: #efefef;
16 | --muted-text: #8e8e8e;
17 | --text: #262626;
18 | --blue: #0095f6;
19 | --tag-blue: #00376b;
20 | --black: #000000;
21 | --red: #ed4956;
22 | --button-text: var(--white);
23 | --other-message-background: var(--white);
24 | }
25 | html,
26 | body {
27 | height: 100%;
28 | background-color: var(--background-color);
29 | }
30 | body {
31 | #__next {
32 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
33 | color: var(--text);
34 | min-height: 100vh;
35 | @media (max-width: 599.98px) {
36 | padding-bottom: 50px;
37 | padding-top: 50px;
38 | background-color: var(--white);
39 | }
40 | }
41 | #__next.dark {
42 | --white: #0c0c0c;
43 | --red: #ed4956;
44 | --background-color: #000000;
45 | --text: #fafafa;
46 | --muted-text: #989898;
47 | --other-message-background: #262626;
48 | --blue: #0095f6;
49 | --tag-blue: var(--blue);
50 |
51 | --border-color: #1d1d1d;
52 | --border-light-color: #131313;
53 | --input-background: #080808;
54 |
55 | --black: #ffffff;
56 |
57 | .contact-list .contact:hover:not(.active-contact) {
58 | background-color: #101010 !important;
59 | }
60 | }
61 | }
62 | .container {
63 | max-width: 940px;
64 | width: 100%;
65 | display: block;
66 | margin-left: auto;
67 | margin-right: auto;
68 | }
69 | button {
70 | font-family: inherit;
71 | white-space: nowrap;
72 | }
73 | .overflow-auto {
74 | overflow: auto !important;
75 | }
76 |
--------------------------------------------------------------------------------
/svgs/AddPost.svg:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/svgs/Back.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/svgs/Bookmark.svg:
--------------------------------------------------------------------------------
1 |
11 |
--------------------------------------------------------------------------------
/svgs/BookmarkFill.svg:
--------------------------------------------------------------------------------
1 |
11 |
--------------------------------------------------------------------------------
/svgs/Camera.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/svgs/Close.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/svgs/Comment.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/svgs/Emoji.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/svgs/Explore.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/svgs/ExploreFill.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/svgs/Home.svg:
--------------------------------------------------------------------------------
1 |
11 |
--------------------------------------------------------------------------------
/svgs/HomeFill.svg:
--------------------------------------------------------------------------------
1 |
11 |
--------------------------------------------------------------------------------
/svgs/Info.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/svgs/Like.svg:
--------------------------------------------------------------------------------
1 |
11 |
--------------------------------------------------------------------------------
/svgs/LikeFill.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/svgs/Loader.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/svgs/Message.svg:
--------------------------------------------------------------------------------
1 |
11 |
--------------------------------------------------------------------------------
/svgs/MessageFill.svg:
--------------------------------------------------------------------------------
1 |
11 |
--------------------------------------------------------------------------------
/svgs/NewMessage.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/svgs/Options.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/svgs/Photo.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/svgs/Posts.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/svgs/Preferences.svg:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/svgs/Search.svg:
--------------------------------------------------------------------------------
1 |
12 |
--------------------------------------------------------------------------------
/svgs/Tagged.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/svgs/User.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/utility/follow.js:
--------------------------------------------------------------------------------
1 | import firebase from '../lib/firebase'
2 |
3 | const follow = (authId, userId) => {
4 | const firestore = firebase.firestore()
5 | firestore.collection(`users/${authId}/followings`).doc(userId).set({
6 | time: new Date(),
7 | })
8 | firestore.collection(`users/${userId}/followers`).doc(authId).set({
9 | time: new Date(),
10 | })
11 | }
12 |
13 | export default follow
14 |
--------------------------------------------------------------------------------
/utility/isFollowing.js:
--------------------------------------------------------------------------------
1 | import firebase from '../lib/firebase'
2 |
3 | const isFollowing = async (authId, userId) => {
4 | const firestore = firebase.firestore()
5 | return await firestore
6 | .doc(`users/${authId}/followings/${userId}`)
7 | .get()
8 | .then((res) => res.exists)
9 | }
10 |
11 | export default isFollowing
12 |
--------------------------------------------------------------------------------
/utility/linkedText.js:
--------------------------------------------------------------------------------
1 | import Link from 'next/link'
2 |
3 | export default function linkedText(text) {
4 | // FIXME En sona link eklendiği zaman başka karakter olmazsa çalışmıyor.
5 |
6 | const words = text.split(' ')
7 | let list = words.map((word, index) => {
8 | if (word.slice(0, 1) === '@') {
9 | return (
10 |
11 | {word}
12 |
13 | )
14 | }
15 | if (word.slice(0, 1) === '#') {
16 | return (
17 |
18 | {word}
19 |
20 | )
21 | }
22 | return word
23 | })
24 | let temp = []
25 | let final = []
26 | let itemType = null
27 | const content = list.map((item, index) => {
28 | if (typeof item === 'object') {
29 | temp.length > 0 ? final.push(temp.join(' ') + ' ') : ''
30 | final.push(item)
31 | temp = []
32 | itemType = 'object'
33 | } else {
34 | if (index == 0) {
35 | temp.push(item)
36 | } else {
37 | temp.push(' ' + item)
38 | }
39 | itemType = 'string'
40 | }
41 | if (list.length - 1 === index && itemType === 'string') {
42 | final.push(' ' + temp.join(' '))
43 | return final
44 | }
45 | })
46 | return content
47 | }
48 |
--------------------------------------------------------------------------------
/utility/sendMessage.js:
--------------------------------------------------------------------------------
1 | import firebase from '../lib/firebase'
2 |
3 | const sendMessage = (authId, userId, message) => {
4 | const firestore = firebase.firestore()
5 |
6 | const time = new Date()
7 | // From
8 | firestore
9 | .collection(`users/${authId}/contacts/${userId}/messages`)
10 | .doc()
11 | .set({
12 | me: true,
13 | message,
14 | seen: false,
15 | time,
16 | liked: false,
17 | })
18 | .catch((error) => {
19 | console.log(error.message)
20 | return false
21 | })
22 | firestore
23 | .collection(`users/${authId}/contacts`)
24 | .doc(userId)
25 | .set({
26 | me: true,
27 | message,
28 | seen: false,
29 | time,
30 | liked: false,
31 | })
32 | .catch((error) => {
33 | console.log(error.message)
34 | return false
35 | })
36 |
37 | // To
38 | firestore
39 | .collection(`users/${userId}/contacts/${authId}/messages`)
40 | .doc()
41 | .set({
42 | me: false,
43 | message,
44 | seen: false,
45 | time,
46 | liked: false,
47 | })
48 | .catch((error) => {
49 | console.log(error.message)
50 | return false
51 | })
52 | firestore
53 | .collection(`users/${userId}/contacts`)
54 | .doc(authId)
55 | .set({
56 | me: false,
57 | message,
58 | seen: false,
59 | time,
60 | liked: false,
61 | })
62 | .catch((error) => {
63 | console.log(error.message)
64 | return false
65 | })
66 |
67 | return true
68 | }
69 |
70 | export default sendMessage
71 |
--------------------------------------------------------------------------------
/utility/unfollow.js:
--------------------------------------------------------------------------------
1 | import firebase from '../lib/firebase'
2 |
3 | const unfollow = (authId, userId) => {
4 | const firestore = firebase.firestore()
5 | firestore.collection(`users/${authId}/followings`).doc(userId).delete()
6 | firestore.collection(`users/${userId}/followers`).doc(authId).delete()
7 | }
8 |
9 | export default unfollow
10 |
--------------------------------------------------------------------------------