Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@
"private": true,
"dependencies": {
"draft-js": "^0.11.0",
"firebase": "^6.6.0",
"react": "^16.9.0",
"react-dom": "^16.9.0",
"react-firebaseui": "^4.0.0",
"react-ga": "^2.6.0",
"react-icons": "^3.7.0",
"react-scripts": "3.1.1"
Expand Down
19 changes: 11 additions & 8 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { Header } from './components/Header'
import { NoteEditor } from './components/NoteEditor'
import { WorkspaceContextProvider } from './context/WorkspaceContext'
import { DarkModeContextProvider } from './context/DarkModeContext'
import { AuthContextProvider } from './context/AuthContext'
import { initAnalytics, trackPage } from './utils/tracking.js'

export const App = () => {
Expand All @@ -15,13 +16,15 @@ export const App = () => {
}, [])

return (
<DarkModeContextProvider>
<WorkspaceContextProvider>
<div className="app">
<Header />
<NoteEditor />
</div>
</WorkspaceContextProvider>
</DarkModeContextProvider>
<AuthContextProvider>
<DarkModeContextProvider>
<WorkspaceContextProvider>
<div className="app">
<Header />
<NoteEditor />
</div>
</WorkspaceContextProvider>
</DarkModeContextProvider>
</AuthContextProvider>
)
}
12 changes: 8 additions & 4 deletions src/components/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,21 @@ import React from 'react'
import { IoIosMoon } from 'react-icons/io'
import { useDarkModeContext } from '../context/DarkModeContext'
import { WorkspaceSelector } from '../components/WorkspaceSelector'
import { UserAccount } from './UserAccount'

export const Header = () => {
const { darkMode, toggleDarkMode } = useDarkModeContext()

return (
<div className={`app-header ${darkMode ? 'dark-mode' : ''}`}>
<WorkspaceSelector />
<IoIosMoon
className={`dark-mode-toggle ${darkMode ? 'dark-mode' : ''}`}
onClick={() => toggleDarkMode()}
/>
<div className="app-header__actions">
<IoIosMoon
className={`dark-mode-toggle ${darkMode ? 'dark-mode' : ''}`}
onClick={() => toggleDarkMode()}
/>
<UserAccount darkMode={darkMode} />
</div>
</div>
)
}
133 changes: 133 additions & 0 deletions src/components/UserAccount.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
import React, { useState } from 'react'
import { IoIosLogIn, IoIosLogOut, IoIosSettings } from 'react-icons/io'
import { GiEuropeanFlag } from 'react-icons/gi'
import { GoCheck, GoX } from 'react-icons/go'
import StyledFirebaseAuth from 'react-firebaseui/StyledFirebaseAuth'
import { useAuthContext } from '../context/AuthContext'
import { uiConfig, firebase, logout } from '../utils/firebase'

const LogoutAction = ({ darkMode }) => {
const [confirmLogout, setConfirmLogout] = useState(false)

const logoutOnClick = () => {
logout()
}

const toggleConfirmLogout = () => setConfirmLogout(!confirmLogout)

return (
<div className="workspace-select__list-item-inner">
<p>Logout</p>
<div className="workspace-select__list-item-actions">
{confirmLogout ? (
<div className="workspace-select__list-item-actions-confirm">
<GoCheck
className={`workspace-select__list-item-actions-icon ${
darkMode ? 'dark-mode' : ''
} delete-action`}
onClick={logoutOnClick}
/>
<GoX
className={`workspace-select__list-item-actions-icon ${
darkMode ? 'dark-mode' : ''
}`}
onClick={() => toggleConfirmLogout()}
/>
</div>
) : (
<IoIosLogOut
className={`workspace-select__list-item-actions-icon ${
darkMode ? 'dark-mode' : ''
}`}
onClick={() => toggleConfirmLogout()}
/>
)}
</div>
</div>
)
}

const UserAccountOptions = ({ darkMode }) => {
const [showOptions, setShowOptions] = useState(false)

const onClick = () => setShowOptions(!showOptions)

return (
<div className="user-account__login">
<IoIosSettings
className={`user-account__login-toggle ${darkMode ? 'dark-mode' : ''} ${
showOptions ? 'active' : ''
}`}
onClick={onClick}
/>
{showOptions && (
<div
className={`user-account__login-options ${
darkMode ? 'dark-mode' : ''
}`}>
<div
className={`user-account__login-options-item ${
darkMode ? 'dark-mode' : ''
}`}>
<LogoutAction darkMode={darkMode} />
</div>
</div>
)}
</div>
)
}

const LoginAction = ({ darkMode }) => {
const [showOptions, setShowOptions] = useState(false)

const onClick = () => setShowOptions(!showOptions)

return (
<div className="user-account__login">
<IoIosLogIn
className={`user-account__login-toggle ${darkMode ? 'dark-mode' : ''} ${
showOptions ? 'active' : ''
}`}
onClick={onClick}
/>
{showOptions && (
<div
className={`user-account__login-options auto-width ${
darkMode ? 'dark-mode' : ''
}`}>
<div
className={`user-account__login-options-item zero-padding ${
darkMode ? 'dark-mode' : ''
}`}>
<StyledFirebaseAuth
uiConfig={uiConfig}
firebaseAuth={firebase.auth()}
/>
</div>
</div>
)}
</div>
)
}

export const UserAccount = ({ darkMode }) => {
const { authenticating, isLoggedIn } = useAuthContext()

return (
<>
{authenticating ? (
<div className="user-account">
<GiEuropeanFlag className="loading-icon" />
</div>
) : (
<div className="user-account">
{isLoggedIn ? (
<UserAccountOptions darkMode={darkMode} />
) : (
<LoginAction darkMode={darkMode} />
)}
</div>
)}
</>
)
}
30 changes: 30 additions & 0 deletions src/context/AuthContext.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import React, { createContext, useContext, useState, useEffect } from 'react'
import { firebase } from '../utils/firebase'

const AuthContext = createContext(null)

export const AuthContextProvider = ({ children }) => {
const [phone, setPhone] = useState('')
const [authenticating, setAuthenticating] = useState(true)
const [isLoggedIn, setIsLoggedIn] = useState(false)

useEffect(() => {
const unregister = firebase.auth().onAuthStateChanged(user => {
// Used only on App startup while Firebase checks for persisted Auth state
setAuthenticating(false)
setIsLoggedIn(!!user)
setPhone(!!user ? user.phoneNumber : '')
})
return () => {
unregister()
}
}, [])

return (
<AuthContext.Provider value={{ authenticating, isLoggedIn, phone }}>
{children}
</AuthContext.Provider>
)
}

export const useAuthContext = () => useContext(AuthContext)
105 changes: 96 additions & 9 deletions src/css/App.scss
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,20 @@ p.text-input-error {
display: none;
}

@keyframes spin {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}

.loading-icon {
@include loading-icon(4px);
animation: spin 2.4s linear infinite;
}

/* Header
======================================= */
$header-height: 72px;
Expand All @@ -73,7 +87,7 @@ $header-height: 72px;
position: relative;
width: 100%;
height: $header-height;
padding: 0 20%;
padding: 0 15%;
background-color: $white;
box-shadow: $generic-box-shadow;

Expand All @@ -86,17 +100,90 @@ $header-height: 72px;
box-shadow: $generic-box-shadow-dark;
}

.dark-mode-toggle {
&__actions {
@include va();
position: absolute;
right: 20%;
@include generic-icon();
right: 15%;

@include mq(900px) {
right: 16px;
}

&.dark-mode {
@include dark-mode-styles(true);
.dark-mode-toggle {
@include generic-icon(4px);

&.dark-mode {
@include dark-mode-styles(true);
}
}

/* User Account
======================================= */
.user-account {
&__login {
@include va(center);
position: relative;

&-options {
position: absolute;
width: 200px;
max-height: 450px;
overflow-y: scroll;
top: calc(100% + 14px);
right: 0;
background-color: $white;
box-shadow: rgba(#000000, 0.24) 0px 4px 4px 0px;
border-top: $generic-border;
z-index: 200;

&.auto-width {
width: 352px;

@include mq(900px) {
width: 100vw;
}
}

@include mq(900px) {
width: 100vw;
right: -16px;
}

&.dark-mode {
@include dark-mode-styles();
border-color: rgba(#000000, 0.24);
}

&-item {
padding: 8px 16px;

&.zero-padding {
padding: 0;
}

&.dark-mode {
border-color: rgba(#000000, 0.24);
}
}
}

&-toggle {
@include generic-icon(4px);

&.dark-mode {
@include dark-mode-styles(true);
}

&.active {
color: $white;
background-color: darken($green, 16);

&:hover {
background-color: $green;
}
}
}
}
}
}
}
Expand Down Expand Up @@ -165,7 +252,7 @@ $header-height: 72px;
&__list {
position: absolute;
width: 100%;
max-height: 300px;
max-height: 450px;
overflow-y: scroll;
top: 100%;
left: 50%;
Expand Down Expand Up @@ -209,10 +296,10 @@ $header-height: 72px;

&.delete-action {
color: $white;
background-color: $red;
background-color: darken($red, 16);

&:hover {
background-color: darken($red, 16);
background-color: $red;
}
}
}
Expand Down
1 change: 1 addition & 0 deletions src/css/Palette.scss
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,4 @@ $white: #ffffff;
/* Colors
======================================= */
$red: #d96668;
$green: #65da65;
Loading