<h1 align="center">👻 Snapchat Clone</h1>
<div align="center">
<img src="./public/readme/tech-logos/react.svg" width="55" alt="React" />
<img src="./public/readme/tech-logos/redux.svg" width="55" alt="Redux" />
<img
src="./public/readme/tech-logos/typescript.svg"
width="55"
alt="TypeScript"
/>
<img
src="./public/readme/tech-logos/javascript.svg"
width="55"
alt="JavaScript"
/>
<img src="./public/readme/tech-logos/sass.svg" width="55" alt="Sass" />
<img src="./public/readme/tech-logos/webpack.svg" width="55" alt="Webpack" />
<img src="./public/readme/tech-logos/gulp.svg" width="35" alt="gulp" />
<img src="./public/readme/tech-logos/cypress.svg" width="55" alt="Cypress" />
<img src="./public/readme/tech-logos/jest.svg" width="55" alt="Jest" />
<img src="./public/readme/tech-logos/eslint.svg" width="55" alt="Eslint" />
<img
src="./public/readme/tech-logos/prettier.svg"
width="55"
alt="Prettier"
/>
<img
src="./public/readme/tech-logos/storybook.svg"
width="50"
alt="Storybook"
/>
</div>
<h2 align="center">
<a href="https://towhidkashem.github.io/snapchat-clone/">[LIVE APP]</a>
</h2>
<img src="public/readme/filters.gif" alt="Preview" />
<h3 align="center">
<a href="https://towhidkashem.github.io/snapchat-clone/">[Live App]</a>
•
<a href="https://www.youtube.com/embed/aRS88v-duKg?autoplay=1">[Video Demo]</a>
</h3>
<h2>⚡️Breakdown</h2>
<ul>
<li>
Built with <code>React</code>
<ul>
<li>Only functional components using hooks</li>
<li>
Folder structure:
<ul>
<li>Flat - no greater than one level deep</li>
<li>
Modular - each folder contains all the relevant files needed to make
up a particular feature (components, styles, tests, actions, etc).
Having everything close at hand reduces cognitive load and deleting
a folder removes the feature entirely from the code base without
having to worry about left over code
</li>
<li>
Organized semantically by Feature (not by the traditional
"components/containers" model), this way of reasoning is more human
friendly
</li>
<li><code>components</code> directory houses all shared components</li>
</ul>
</li>
<li>Custom component library showcased in <code>Storybook</code></li>
<li>Relatively few prod dependencies</li>
</ul>
</li>
<li>
Global state management via <code>Redux</code>
<ul>
<li>
Uses <code>Redux Toolkit</code> - the official recommended
approach to using Redux which drastically cuts the need to write
boilerplate code
</li>
<li>
A single <code>store.ts</code> file for each feature contains all actions and
reducers (the creators are auto generated by RTK)
</li>
<li>Flat state tree avoids deeply nested properties</li>
<li>
RTK has built-in support for <code>ImmerJS</code> which allows state to
be safely mutated removing the need for messy object copying via spread
operators
</li>
<li>
Uses the <code>useDispatch</code> and <code>useSelector</code> hooks
provided by <code>react-redux</code> for accessing state values and
dispatching actions over the more verbose <code>connect</code> method
</li>
<li>Uses <code>thunk</code> for async operations</li>
<li>
Integrates the powerful
<code>Redux Devtools Extension</code> for ease of development
</li>
</ul>
</li>
<li>
Styled with <code>SASS</code>
<ul>
<li>
Each view's set of rules are scoped to a single parent element via
nesting to avoid style clashes
</li>
<li>
Use of variables, extendables and mixins to keep things DRY and uniform
</li>
</ul>
</li>
<li>
Written in <code>Typescript</code>
<ul>
<li>
To let the compiler catch bugs at build time instead of letting users
catch them at runtime!
</li>
</ul>
</li>
<li>Unit tested with <code>Jest</code> and <code>Enzyme</code></li>
<li>
End-to-end tested with <code>Cypress</code>
<ul>
<li>
Selectors use <code>data</code> attributes instead of classes or ids as
these can change often causing tests to break
</li>
<li>
Integration suite covers all essential feature happy paths
</li>
</ul>
</li>
<li>Linted using <code>Eslint</code></li>
<li>
Code is auto formatted using <code>Prettier</code> (ran as a pre-commit git
hook) before it gets pushed to the repo
</li>
<li>
Feels close to a native app if you "add to homescreen" on mobile
</li>
</ul>
<h2>💿 Installation</h2>
<p>Run these commands in the terminal:</p>
<ol>
<li>
<code>$ git clone git@github.com:TowhidKashem/snapchat-clone.git</code>
</li>
<li><code>$ cd snapchat-clone</code></li>
<li>
<code>$ npm install</code>
<ul>
<li>
This will:
<ul>
<li>Install the dependencies in package.json</li>
<li>
Checkout
<a href="https://github.com/jeeliz/jeelizFaceFilter">jeelizFaceFilter</a>
package (used for the filters) and set it to the last version this
project was tested and confirmed to work with
</li>
<li>
Run <code>gulp</code> to concatenate, minify and transpile the files
located in <code>public/filters/source/*.js</code> into a single
file called <code>filters.min.js</code>
</li>
</ul>
</li>
</ul>
</li>
<li>
This part is optional but strongly recommended, without it you won't be able
to view any of the snap map features:
<ul>
<li>
Make a Mapbox account and
<a
href="https://docs.mapbox.com/help/glossary/access-token/"
target="_blank"
>get a free API key</a
>
</li>
<li>
In the <code>.env</code> file enter your new API key, for example:
<ul>
<li>
Before:
<code>REACT_APP_MAP_BOX_API_KEY=REPLACE_WITH_API_KEY</code>
</li>
<li>After: <code>REACT_APP_MAP_BOX_API_KEY=xy.abc123</code></li>
</ul>
</li>
</ul>
</li>
<li>
<code>$ npm start</code>
<ul>
<li>
The app should open automatically in your browser usually at
<code>https://localhost:3000/</code>
<ul>
<li>
In Chrome you will receive a "Your connection is not private"
warning
<ul>
<li>
Click "Advanced" > "Proceed to localhost (unsafe)"
<ul>
<li>
You'll get this warning because the app uses a self signed
<code>https</code> certificate. The
<code>getUserMedia</code> API used by the camera requires
the <code>https</code> protocol so we run the dev server in
https mode.
</li>
</ul>
</li>
</ul>
</li>
<li>
After this you will be prompted to give access to your webcam, click
"Allow"
</li>
</ul>
</li>
</ul>
<br />
<table>
<tbody>
<tr>
<th align="center">
Step 1
</th>
<th align="center">
Step 2
</th>
<th align="center">
Step 3
</th>
</tr>
<tr>
<td align="center" valign="middle">
<img src="public/readme/step1.png" />
</td>
<td align="center" valign="middle">
<img src="public/readme/step2.png" />
</td>
<td align="center" valign="middle">
<img src="public/readme/camera.png" />
</td>
</tr>
</tbody>
</table>
</li>
<li>You're all set! 🎉</li>
</ol>
<table>
<tbody>
<tr>
<th colspan="2" align="left">
<h2>🦮 Guides</h2>
</th>
</tr>
<tr>
<td align="center" valign="top">
<img src="public/readme/guide.png" />
</td>
<td valign="top">
Not all the buttons are actionable, many of them are there just for show
since this is a minimal demo. This
<a
href="https://www.youtube.com/embed/aRS88v-duKg?autoplay=1"
target="_blank"
>video</a
>
shows all the things you can currently do. Where it's not obvious which
buttons actually work I added red box-shadows as guides.
</td>
</tr>
</tbody>
</table>
<table>
<tbody>
<tr>
<th colspan="2" align="left">
<h2>🛠 Tooling</h2>
</th>
</tr>
<tr>
<td valign="top">
<img src="public/readme/storybook.png" />
<p>
<strong>Storybook</strong> is used to showcase the app's custom
component library. You can run Storybook using the command
<code>npm run storybook</code>
</p>
</td>
<td valign="top">
<img src="public/readme/redux-ext.png" />
<p>
<strong>Redux Devtools Extension</strong> is implemented in the app,
it makes things like viewing the state tree, state flow and debugging
much easier, to use it you need to install the browser extension
<a
href="https://chrome.google.com/webstore/detail/redux-devtools/lmhkpmbekcpmknklioeibfkpmmfibljd?hl=en"
>here</a
>
or
<a
href="https://addons.mozilla.org/en-US/firefox/addon/reduxdevtools/"
>here</a
>
</p>
</td>
</tr>
</tbody>
</table>
<h2>🧪 Testing</h2>
<ta