mirror of
https://github.com/FranP-code/Pomodoro-Timer-with-Clockify-integration.git
synced 2025-10-12 23:52:30 +00:00
Refactored the whole app 🔧
This commit is contained in:
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
@@ -1,15 +1,10 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<!-- CSS -->
|
||||
<link rel="stylesheet" href="./css_styles/styles.css">
|
||||
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Raleway:wght@400;700&display=swap" rel="stylesheet">
|
||||
|
||||
<link href="https://fonts.googleapis.com/css2?family=Rambla:wght@400;700&display=swap" rel="stylesheet">
|
||||
<!-- CSS -->
|
||||
<meta charset="utf-8" />
|
||||
<link rel="icon" href="./img/favicon.ico" id="favicon" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
|
||||
@@ -1,104 +0,0 @@
|
||||
.banner-login {
|
||||
background-color: #D17262;
|
||||
color: white;
|
||||
|
||||
@include bodyFont();
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
|
||||
padding: 0px 5vw;
|
||||
|
||||
height: 8vh;
|
||||
|
||||
|
||||
p {
|
||||
@include normalizeBody();
|
||||
}
|
||||
|
||||
.button-container {
|
||||
|
||||
width: 20vw;
|
||||
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
|
||||
button {
|
||||
@include normalizeButton();
|
||||
|
||||
font-size: 12pt;
|
||||
font-weight: bold;
|
||||
color: #ffffff;
|
||||
|
||||
height: 6vh;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.register {
|
||||
border: solid 1px #ffffff;
|
||||
border-radius: 24px;
|
||||
}
|
||||
|
||||
.login {
|
||||
background-color: #00000057;
|
||||
border-radius: 24px;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.banner-login.blank {
|
||||
opacity: 0%;
|
||||
|
||||
}
|
||||
|
||||
@media (max-width: 918px) {
|
||||
.banner-login {
|
||||
justify-content: initial;
|
||||
|
||||
height: auto;
|
||||
|
||||
padding: 2vh 2vw;
|
||||
|
||||
p {
|
||||
width: 33.3%;
|
||||
}
|
||||
|
||||
.button-container {
|
||||
width: 66.6%;
|
||||
|
||||
justify-content: space-around;
|
||||
|
||||
button {
|
||||
width: 30%;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 576px) {
|
||||
.banner-login {
|
||||
|
||||
p {
|
||||
width: 50%;
|
||||
}
|
||||
|
||||
.button-container {
|
||||
width: 50%;
|
||||
|
||||
flex-direction: column;
|
||||
|
||||
button {
|
||||
width: 75%;
|
||||
margin: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.banner-login.blank.dark-mode-component {
|
||||
opacity: 100%;
|
||||
background-color: $main-color-dark;
|
||||
}
|
||||
@@ -1,104 +0,0 @@
|
||||
.go-to-account {
|
||||
|
||||
width: 3vw;
|
||||
height: 3vw;
|
||||
|
||||
position: absolute;
|
||||
|
||||
top: 10.5vh;
|
||||
left: 87vw;
|
||||
|
||||
background-color: $second-color;
|
||||
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
border-radius: 100%;
|
||||
|
||||
.go-to-account-text {
|
||||
|
||||
@include titleFont();
|
||||
|
||||
font-size: 1vw;
|
||||
text-decoration: none;
|
||||
user-select: none;
|
||||
|
||||
color: #ffffff;
|
||||
}
|
||||
}
|
||||
|
||||
.close-session {
|
||||
width: 7vw;
|
||||
height: 3vw;
|
||||
|
||||
position: absolute;
|
||||
|
||||
top: 10.5vh;
|
||||
left: 91vw;
|
||||
|
||||
background-color: $second-color;
|
||||
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
border-radius: 5%;
|
||||
|
||||
.close-session-text {
|
||||
|
||||
@include titleFont();
|
||||
font-size: 1vw;
|
||||
|
||||
text-decoration: none;
|
||||
|
||||
user-select: none;
|
||||
|
||||
color: #ffffff;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@media (max-width: 991.98px) {
|
||||
//! I fucking hate make the responsive design
|
||||
.go-to-account, .close-session {
|
||||
position: initial;
|
||||
padding: 1vw;
|
||||
|
||||
}
|
||||
|
||||
.go-to-account {
|
||||
|
||||
.go-to-account-text {
|
||||
font-size: 9pt;
|
||||
|
||||
}
|
||||
|
||||
margin-top: 10px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.close-session {
|
||||
|
||||
.close-session-text {
|
||||
font-size: 9pt;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 576px) {
|
||||
.go-to-account, .close-session {
|
||||
width: auto;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.go-to-account-text, .close-session-text {
|
||||
position: initial;
|
||||
margin:10px 10px;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
.go-to-account.dark-mode-component, .close-session.dark-mode-component {
|
||||
background-color: $second-color-dark;
|
||||
}
|
||||
@@ -1,134 +0,0 @@
|
||||
|
||||
.header-main-page {
|
||||
background-color: $main-color;
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
// align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
height: 14vh;
|
||||
padding: 0vh 1vw;
|
||||
|
||||
box-sizing: border-box;
|
||||
|
||||
a {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.title-link {
|
||||
width: fit-content;
|
||||
}
|
||||
|
||||
h1 {
|
||||
color: #ffffff;
|
||||
|
||||
font-size: 3vw;
|
||||
|
||||
display: inline;
|
||||
|
||||
@include titleFont();
|
||||
@include normalizeTitle();
|
||||
}
|
||||
|
||||
.konami-code {
|
||||
@include titleFont();
|
||||
|
||||
color: $lightest-color-dark;
|
||||
}
|
||||
}
|
||||
.notification-select {
|
||||
|
||||
background-color: $second-color;
|
||||
height: 3vh;
|
||||
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
|
||||
padding-left: 1vw;
|
||||
|
||||
box-sizing: border-box;
|
||||
|
||||
color: #fff;
|
||||
|
||||
@include bodyFont();
|
||||
|
||||
p {
|
||||
display: inline-block;
|
||||
|
||||
align-self: center;
|
||||
|
||||
padding: 0;
|
||||
|
||||
margin: 0;
|
||||
margin-right: 1vw;
|
||||
}
|
||||
|
||||
button {
|
||||
height: 80%;
|
||||
width: 5%;
|
||||
|
||||
margin-right: 0.5vw;
|
||||
|
||||
border: none;
|
||||
border-radius: 2px;
|
||||
|
||||
align-self: center;
|
||||
|
||||
color: #fff;
|
||||
font-weight: bold;
|
||||
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
button.yes {
|
||||
background-color: rgb(76, 175, 80);
|
||||
}
|
||||
|
||||
button.no {
|
||||
background-color: rgb(211, 47, 47);
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 991.98px) {
|
||||
.header-main-page {
|
||||
height: auto;
|
||||
padding: 3vw 0px;
|
||||
|
||||
align-items: center;
|
||||
|
||||
h1 {
|
||||
font-size: 26pt;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 13pt;
|
||||
}
|
||||
}
|
||||
|
||||
.notification-select {
|
||||
height: auto;
|
||||
flex-wrap: wrap;
|
||||
|
||||
p {
|
||||
width: 100%;
|
||||
margin-top: 1vh;
|
||||
margin-bottom: 1vh;
|
||||
}
|
||||
|
||||
button {
|
||||
height: 30px;
|
||||
width: 20%;
|
||||
margin-bottom: 1vh;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.header-main-page.dark-mode-component {
|
||||
background-color: $main-color-dark;
|
||||
border-bottom: 1px solid #ffffff72;
|
||||
}
|
||||
|
||||
.notification-select.dark-mode-component {
|
||||
background-color: $second-color-dark;
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
.history-button {
|
||||
@include normalizeButton;
|
||||
|
||||
height: 9vh;
|
||||
width: 9vh;
|
||||
|
||||
padding: 0;
|
||||
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
position: absolute;
|
||||
left: 6vh;
|
||||
|
||||
border-radius: 100%;
|
||||
|
||||
background-color: $light-color;
|
||||
|
||||
svg {
|
||||
@include svgStyle;
|
||||
|
||||
path {
|
||||
fill: rgba(80, 80, 80, 0.556);
|
||||
}
|
||||
|
||||
width: 6vh;
|
||||
height: 6vh;
|
||||
|
||||
}
|
||||
|
||||
&:hover {
|
||||
animation: spin 0.4s ease-in-out;
|
||||
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
0% {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
|
||||
|
||||
100% {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
.made-with-love a {
|
||||
color: #ff8787
|
||||
}
|
||||
|
||||
.made-with-love {
|
||||
color:rgb(185, 185, 185);
|
||||
margin-top: auto;
|
||||
width: 100%;
|
||||
|
||||
padding-top: 5vh;
|
||||
padding-bottom: 5vh;
|
||||
padding-left: 3vw;
|
||||
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.made-with-love.dark-mode-component {
|
||||
|
||||
background-color: $main-color-dark;
|
||||
}
|
||||
@@ -1,109 +0,0 @@
|
||||
.main-pomodoro {
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
height: 68vh;
|
||||
|
||||
.timer {
|
||||
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
|
||||
@include bodyFont;
|
||||
font-weight: bold;
|
||||
font-size: 130pt;
|
||||
|
||||
color: $second-color;
|
||||
}
|
||||
|
||||
.style-display {
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
|
||||
@include bodyFont;
|
||||
|
||||
h4 {
|
||||
font-size: 24pt;
|
||||
|
||||
@include normalizeBody;
|
||||
|
||||
color: $second-color;
|
||||
user-select: none;
|
||||
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 30pt;
|
||||
|
||||
@include normalizeBody;
|
||||
|
||||
color: $second-color;
|
||||
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
}
|
||||
}
|
||||
|
||||
.start-pomodoro {
|
||||
@include normalizeButton;
|
||||
@include titleFont;
|
||||
|
||||
margin-top: 6vh;
|
||||
width: 30vw;
|
||||
height: 8vh;
|
||||
|
||||
background: $second-color;
|
||||
border-radius: 24px;
|
||||
|
||||
font-size: 5vh;
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@media (max-width: 576px) {
|
||||
|
||||
.main-pomodoro {
|
||||
|
||||
height: auto;
|
||||
|
||||
.timer {
|
||||
font-size: 80pt;
|
||||
}
|
||||
|
||||
.start-pomodoro {
|
||||
font-size: 13pt;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.main-pomodoro-container.dark-mode-component {
|
||||
|
||||
background-color: $main-color-dark;
|
||||
|
||||
.main-pomodoro {
|
||||
|
||||
.timer {
|
||||
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.style-display {
|
||||
|
||||
h3, h4 {
|
||||
|
||||
color: #ffffff;
|
||||
}
|
||||
}
|
||||
|
||||
.start-pomodoro{
|
||||
background-color: $lightest-color-dark;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,71 +0,0 @@
|
||||
.pomodoro-counter {
|
||||
|
||||
|
||||
position: absolute;
|
||||
top: 29vh;
|
||||
|
||||
ul {
|
||||
|
||||
li {
|
||||
display: flex;
|
||||
|
||||
@include bodyFont;
|
||||
|
||||
list-style-type: none;
|
||||
margin-top: 2vh;
|
||||
|
||||
font-size: 15pt;
|
||||
|
||||
color: #00000070;
|
||||
|
||||
.separator {
|
||||
user-select: none;
|
||||
margin: 0px 0.5vw;
|
||||
}
|
||||
|
||||
.quantity {
|
||||
@include titleFont;
|
||||
|
||||
user-select: none;
|
||||
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
height: 30px;
|
||||
width: 30px;
|
||||
|
||||
border-radius: 100%;
|
||||
|
||||
color: $second-color;
|
||||
background-color: $light-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@media (max-width: 991.98px) {
|
||||
|
||||
.pomodoro-counter {
|
||||
|
||||
position: initial;
|
||||
padding-bottom: 5vh;
|
||||
}
|
||||
}
|
||||
|
||||
.pomodoro-counter.dark-mode-component {
|
||||
ul {
|
||||
|
||||
li {
|
||||
|
||||
color: #ffffff;
|
||||
|
||||
.quantity {
|
||||
|
||||
color: $lightest-color-dark;
|
||||
background: $second-color-dark;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,77 +0,0 @@
|
||||
|
||||
|
||||
@mixin titleFont {
|
||||
font-family: 'Raleway', sans-serif;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
@mixin bodyFont {
|
||||
font-family: 'Rambla', sans-serif;
|
||||
}
|
||||
|
||||
@mixin normalizeTitle {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
@mixin normalizeBody {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
@mixin normalizeButton {
|
||||
background: none;
|
||||
border: none;
|
||||
width: 8vw;
|
||||
}
|
||||
|
||||
@mixin svgStyle {
|
||||
cursor: pointer;
|
||||
|
||||
path {
|
||||
fill: rgb(170, 170, 170);
|
||||
// CREDITS TO https://stackoverflow.com/a/49627345
|
||||
}
|
||||
}
|
||||
|
||||
$background-color: #ffffff;
|
||||
$border-color: #969696;
|
||||
|
||||
$main-color: #62D2A2;
|
||||
$second-color: #1FAB89;
|
||||
$second-color-darker: #15745c;
|
||||
$light-color: #9DF3C4;
|
||||
$lightest-color: #D7FBE8;
|
||||
|
||||
$main-color-dark: #303841;
|
||||
$second-color-dark: #3A4750;
|
||||
$light-color-dark: #D72323;
|
||||
$light-color-dark-darker: #7c1414;
|
||||
$lightest-color-dark: #4c8ad5;
|
||||
$lightest-color-dark-darker: #eff3f8;
|
||||
|
||||
@import 'header';
|
||||
@import 'banner-login';
|
||||
@import 'mainPomodoro';
|
||||
@import 'styleSelector';
|
||||
@import 'goDownArrow';
|
||||
@import 'aboutThis';
|
||||
@import 'historyButton';
|
||||
@import 'pomodoro-counter';
|
||||
@import 'identify';
|
||||
@import 'dark-mode_toogle-switch';
|
||||
@import 'account';
|
||||
@import 'goToAccount';
|
||||
@import 'clockify-tasks-display';
|
||||
@import 'made-with-love';
|
||||
|
||||
html, body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
body {
|
||||
height: 100%;
|
||||
background-color: $background-color;
|
||||
}
|
||||
123
src/App.js
123
src/App.js
@@ -1,33 +1,24 @@
|
||||
import { getAuth, onAuthStateChanged } from 'firebase/auth';
|
||||
import './styles.css'
|
||||
|
||||
import React, { useState } from 'react';
|
||||
import { getAuth, onAuthStateChanged } from 'firebase/auth';
|
||||
import { BrowserRouter as Router, Route, Switch } from "react-router-dom";
|
||||
import AboutThis from "./components/AboutThis";
|
||||
import Account from "./components/Account";
|
||||
import BannerLogin from "./components/BannerLogin";
|
||||
import ClockifyTasksDisplay from './components/ClockifyTasksDisplay';
|
||||
import Credits from './components/Credits';
|
||||
import Footer from './components/Footer';
|
||||
import GoDownArrow from "./components/GoDownArrow";
|
||||
import Header from "./components/Header";
|
||||
import Identify from "./components/Identify";
|
||||
import MainPomodoro from "./components/MainPomodoro";
|
||||
|
||||
//Pages
|
||||
import ConfigAccount from "./pages/ConfigAccount/ConfigAccount";
|
||||
import Identify from "./pages/Identify/Identify";
|
||||
import Main from './pages/Main/Main';
|
||||
import AboutThis from "./pages/AboutThis/AboutThis";
|
||||
import Credits from './pages/Credits/Credits';
|
||||
|
||||
import Footer from './components/Footer/Footer';
|
||||
import Header from "./components/Header/Header";
|
||||
|
||||
function App() {
|
||||
|
||||
const [timerOn, setTimerOn] = useState(false)
|
||||
|
||||
const [signIn, setSignIn] = useState('')
|
||||
|
||||
const [apiKey, setApiKey] = useState('')
|
||||
const [taskName, setTaskName] = useState('')
|
||||
|
||||
const [workspaceID, setWorspaceID] = useState(0)
|
||||
const [projectID, setProjectID] = useState(0)
|
||||
|
||||
const [signedIn, setSignedIn] = useState('')
|
||||
const [darkMode, setDarkmode] = useState(false)
|
||||
|
||||
const [KonamiCodeActive, setKonamiCodeActive] = useState(false)
|
||||
|
||||
const [konamiCodeActive, setKonamiCodeActive] = useState(false)
|
||||
const [notificationPermission, setNotificationPermission] = useState(undefined)
|
||||
|
||||
const auth = getAuth()
|
||||
@@ -35,9 +26,9 @@ function App() {
|
||||
onAuthStateChanged(auth, (user) => {
|
||||
|
||||
if (user) {
|
||||
setSignIn(true)
|
||||
setSignedIn(true)
|
||||
} else {
|
||||
setSignIn(false)
|
||||
setSignedIn(false)
|
||||
}
|
||||
|
||||
})
|
||||
@@ -64,105 +55,43 @@ function App() {
|
||||
<Router>
|
||||
<>
|
||||
<Header
|
||||
signIn={signIn}
|
||||
signedIn={signedIn}
|
||||
|
||||
darkMode={darkMode}
|
||||
setDarkmode={setDarkmode}
|
||||
|
||||
KonamiCodeActive= {KonamiCodeActive}
|
||||
konamiCodeActive={konamiCodeActive}
|
||||
|
||||
notificationPermission={notificationPermission}
|
||||
setNotificationPermission={setNotificationPermission}
|
||||
/>
|
||||
|
||||
<Switch>
|
||||
|
||||
|
||||
|
||||
<Route path="/config-account">
|
||||
<Account
|
||||
|
||||
<ConfigAccount
|
||||
darkMode={darkMode}
|
||||
/>
|
||||
</Route>
|
||||
|
||||
<Route path="/identify">
|
||||
<Identify
|
||||
|
||||
darkMode={darkMode}
|
||||
/>
|
||||
<Identify darkMode={darkMode}/>
|
||||
</Route>
|
||||
|
||||
<Route path="/">
|
||||
<BannerLogin
|
||||
signIn={signIn}
|
||||
<Main
|
||||
signedIn={signedIn}
|
||||
darkMode={darkMode}
|
||||
/>
|
||||
|
||||
<ClockifyTasksDisplay
|
||||
|
||||
setTimerOn={setTimerOn}
|
||||
|
||||
signIn={signIn}
|
||||
timerOn={timerOn}
|
||||
|
||||
apiKey={apiKey}
|
||||
setApiKey={setApiKey}
|
||||
|
||||
taskName={taskName}
|
||||
setTaskName={setTaskName}
|
||||
|
||||
workspaceID={workspaceID}
|
||||
setWorspaceID={setWorspaceID}
|
||||
|
||||
projectID={projectID}
|
||||
setProjectID={setProjectID}
|
||||
|
||||
darkMode={darkMode}
|
||||
/>
|
||||
|
||||
<MainPomodoro
|
||||
signIn={signIn}
|
||||
timerOn={timerOn}
|
||||
setTimerOn={setTimerOn}
|
||||
|
||||
apiKey={apiKey}
|
||||
|
||||
taskName={taskName}
|
||||
setTaskName={setTaskName}
|
||||
|
||||
workspaceID={workspaceID}
|
||||
setWorspaceID={setWorspaceID}
|
||||
|
||||
projectID={projectID}
|
||||
setProjectID={setProjectID}
|
||||
|
||||
darkMode={darkMode}
|
||||
|
||||
setKonamiCodeActive = {setKonamiCodeActive}
|
||||
KonamiCodeActive= {KonamiCodeActive}
|
||||
|
||||
konamiCodeActive={konamiCodeActive}
|
||||
setKonamiCodeActive={setKonamiCodeActive}
|
||||
notificationPermission={notificationPermission}
|
||||
/>
|
||||
|
||||
<GoDownArrow
|
||||
direction={'about-this'}
|
||||
darkMode={darkMode}
|
||||
|
||||
/>
|
||||
<AboutThis
|
||||
darkMode={darkMode}
|
||||
|
||||
/>
|
||||
|
||||
<GoDownArrow
|
||||
direction={'credits'}
|
||||
darkMode={darkMode}
|
||||
|
||||
/>
|
||||
<Credits
|
||||
darkMode={darkMode}
|
||||
/>
|
||||
/>
|
||||
</Route>
|
||||
</Switch>
|
||||
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
import React from 'react'
|
||||
|
||||
const Message = (props) => {
|
||||
|
||||
const [message, setMessage] = React.useState('')
|
||||
|
||||
React.useEffect( () => {
|
||||
switch (props.message) {
|
||||
case 'API NOT VALID':
|
||||
setMessage('The API is not valid')
|
||||
break;
|
||||
|
||||
case 'API NOT UPLOADED':
|
||||
setMessage(`There's been an error while we upload your API Key. Please try again`)
|
||||
break;
|
||||
|
||||
case 'API UPLOADED':
|
||||
setMessage(`API uploaded successfully`)
|
||||
break;
|
||||
default:
|
||||
setMessage('')
|
||||
break;
|
||||
}
|
||||
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<div id="message" className={props.message === 'API UPLOADED' ? 'successfully' : null}>
|
||||
<h1>{message}</h1>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default Message
|
||||
@@ -1,27 +0,0 @@
|
||||
import React from 'react'
|
||||
|
||||
const BannerLogin = (props) => {
|
||||
|
||||
|
||||
|
||||
return (
|
||||
<>
|
||||
{
|
||||
!props.signIn ?
|
||||
|
||||
<div className="banner-login">
|
||||
<p>Access to integrate and save your progress with Clockify!</p>
|
||||
<div className="button-container">
|
||||
<button className="register" onClick={() => {window.location = '/identify?act=r'}}>Register</button>
|
||||
<button className="login" onClick={() => {window.location = '/identify?act=l'}}>Login</button>
|
||||
</div>
|
||||
</div>
|
||||
: <div className={props.darkMode ? 'banner-login blank dark-mode-component' : 'banner-login blank'}>
|
||||
|
||||
</div>
|
||||
}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default BannerLogin
|
||||
@@ -1,125 +0,0 @@
|
||||
import React, {useState} from 'react'
|
||||
import { makeRequest } from '../Clockify/clockify'
|
||||
|
||||
import { getFirestore, doc, getDoc } from 'firebase/firestore'
|
||||
import { onAuthStateChanged, getAuth } from 'firebase/auth'
|
||||
|
||||
import { firebase } from '../Firebase/firebase'
|
||||
import { withRouter } from 'react-router-dom'
|
||||
|
||||
const ClockifyTasksHoursCounter = (props) => {
|
||||
|
||||
const auth = getAuth()
|
||||
|
||||
const [userUID, setUserUID] = useState('')
|
||||
|
||||
const [workspacesArray, setWorkspacesArray] = useState([])
|
||||
|
||||
const [loading, setLoading] = useState(true)
|
||||
|
||||
const getApiKey = async () => {
|
||||
|
||||
try {
|
||||
|
||||
const db = await getFirestore(firebase)
|
||||
|
||||
const reference = await doc(db, 'users', userUID)
|
||||
|
||||
const dataSnap = await getDoc(reference)
|
||||
const result = await dataSnap.data()
|
||||
|
||||
return result.keyClockify
|
||||
|
||||
|
||||
} catch (error) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
const makeRequestWorkspaces = async (apiClockify) => {
|
||||
|
||||
try {
|
||||
const request = {
|
||||
method: "GET",
|
||||
headers: {
|
||||
'X-Api-Key': apiClockify,
|
||||
"content-type": "application/json"
|
||||
}
|
||||
}
|
||||
const response = await fetch(`https://api.clockify.me/api/v1/workspaces/`, request)
|
||||
const data = await response.json()
|
||||
|
||||
return await data
|
||||
|
||||
} catch (error) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
const bringData = async () => {
|
||||
|
||||
await makeRequest(props.apiKey)
|
||||
}
|
||||
|
||||
React.useEffect( () => {
|
||||
|
||||
if (props.signIn) {
|
||||
|
||||
onAuthStateChanged(auth, async (user) => {
|
||||
|
||||
if (user) {
|
||||
|
||||
setUserUID(await user.uid)
|
||||
|
||||
if (userUID) {
|
||||
|
||||
const keyClockify = await getApiKey()
|
||||
|
||||
const workspaces = await makeRequestWorkspaces(keyClockify)
|
||||
|
||||
workspaces.forEach(workspace => {
|
||||
|
||||
let copyWorkspacesArray = workspacesArray
|
||||
copyWorkspacesArray.push(workspace)
|
||||
|
||||
setWorkspacesArray(copyWorkspacesArray)
|
||||
})
|
||||
|
||||
setLoading(false)
|
||||
}
|
||||
} else {
|
||||
|
||||
return (<></>)
|
||||
}
|
||||
|
||||
})
|
||||
} else {
|
||||
|
||||
props.history.push('/')
|
||||
}
|
||||
|
||||
}, [props, onAuthStateChanged, setUserUID, userUID])
|
||||
|
||||
|
||||
return (
|
||||
<>
|
||||
{
|
||||
loading ?
|
||||
<h1>Loading</h1>
|
||||
:
|
||||
<div>
|
||||
<select>
|
||||
{
|
||||
workspacesArray.map(workspace => (
|
||||
|
||||
<option> {workspace.name} </option>
|
||||
))
|
||||
}
|
||||
</select>
|
||||
</div>
|
||||
}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default withRouter(ClockifyTasksHoursCounter)
|
||||
@@ -1,19 +0,0 @@
|
||||
const makeRequest = async (apiKey) => {
|
||||
try {
|
||||
const request = {
|
||||
method: "GET",
|
||||
headers: {
|
||||
'X-Api-Key': apiKey.trim(),
|
||||
"content-type": "application/json"
|
||||
}
|
||||
}
|
||||
const response = await fetch(`https://api.clockify.me/api/v1/workspaces/`, request)
|
||||
const data = await response.json()
|
||||
|
||||
return await data
|
||||
|
||||
} catch (error) {
|
||||
}
|
||||
}
|
||||
|
||||
export {makeRequest}
|
||||
@@ -1,35 +0,0 @@
|
||||
const uploadToClockifyTimer = async (workspaceID, projectID, start, end, apiKey, taskName) => {
|
||||
|
||||
if (!workspaceID && !projectID) {
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
const url = `https://api.clockify.me/api/v1/workspaces/${workspaceID}/time-entries`
|
||||
|
||||
const body = {
|
||||
start: start,
|
||||
end: end,
|
||||
projectId: projectID,
|
||||
description: taskName
|
||||
}
|
||||
|
||||
const headers = {
|
||||
'X-Api-Key': apiKey,
|
||||
'Content-type' : 'application/json; charset=UTF-8'
|
||||
}
|
||||
|
||||
const request = {
|
||||
method: 'POST',
|
||||
body: JSON.stringify(body),
|
||||
headers
|
||||
}
|
||||
|
||||
const result = await fetch(url, request)
|
||||
const data = await result.json()
|
||||
|
||||
} catch (error) {
|
||||
}
|
||||
}
|
||||
|
||||
export default uploadToClockifyTimer
|
||||
@@ -1,237 +0,0 @@
|
||||
import { getAuth, onAuthStateChanged } from "firebase/auth";
|
||||
import { doc, getDoc, getFirestore } from "firebase/firestore";
|
||||
import React, { useState } from 'react';
|
||||
import { firebase } from './Firebase/firebase';
|
||||
import loadingGifDarkTheme from './img/loading-dark-theme.png';
|
||||
import loadingGifLightTheme from './img/loading-light-theme.png';
|
||||
|
||||
const ClockifyTasksDisplay = (props) => {
|
||||
|
||||
const auth = getAuth()
|
||||
|
||||
const [userUID, setUserUID] = useState('')
|
||||
|
||||
const [workspaces, setWorkspaces] = useState([])
|
||||
const [workspacesReady, setWorkspacesReady] = useState(false)
|
||||
|
||||
const [projects, setProjects] = useState([])
|
||||
const [projectsDone, setProjectsDone] = useState(false)
|
||||
|
||||
const [loading, setLoading] = useState(true)
|
||||
const [apiAvailable, setApiAvailable] = useState(false)
|
||||
|
||||
const getApiKey = async () => {
|
||||
|
||||
try {
|
||||
|
||||
const db = await getFirestore(firebase)
|
||||
|
||||
const reference = await doc(db, 'users', userUID)
|
||||
|
||||
|
||||
const dataSnap = await getDoc(reference)
|
||||
const result = await dataSnap.data()
|
||||
|
||||
if (result.keyClockify) {
|
||||
|
||||
setApiAvailable(true)
|
||||
await generateArrayOfWorkspaces(result.keyClockify)
|
||||
}
|
||||
|
||||
|
||||
} catch (error) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
const makeRequestWorkspaces = async (apiClockify) => {
|
||||
try {
|
||||
const request = {
|
||||
method: "GET",
|
||||
headers: {
|
||||
'X-Api-Key': apiClockify,
|
||||
"content-type": "application/json"
|
||||
}
|
||||
}
|
||||
const response = await fetch(`https://api.clockify.me/api/v1/workspaces/`, request)
|
||||
const data = await response.json()
|
||||
|
||||
props.setApiKey(apiClockify)
|
||||
|
||||
return await data
|
||||
|
||||
} catch (error) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
const generateArrayOfWorkspaces = async (key) => {
|
||||
|
||||
const getApiKeyReturn = key
|
||||
|
||||
|
||||
const data = await makeRequestWorkspaces(key)
|
||||
|
||||
if (data.code !== 1000) {
|
||||
let workspacesCopy = []
|
||||
|
||||
await data.forEach(workspace => {
|
||||
|
||||
workspacesCopy.push(workspace)
|
||||
|
||||
});
|
||||
|
||||
await setWorkspaces(workspacesCopy)
|
||||
|
||||
setWorkspacesReady(true)
|
||||
setLoading(false)
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
React.useEffect( () => {
|
||||
|
||||
if (props.signIn) {
|
||||
|
||||
onAuthStateChanged(auth, async (user) => {
|
||||
|
||||
if (user) {
|
||||
|
||||
setUserUID(await user.uid)
|
||||
|
||||
if (userUID) {
|
||||
|
||||
await getApiKey()
|
||||
}
|
||||
} else {
|
||||
return (<></>)
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
}, [props, onAuthStateChanged, setUserUID, userUID])
|
||||
|
||||
const makeRequestProjects = async (e) => {
|
||||
|
||||
try {
|
||||
const request = {
|
||||
method: "GET",
|
||||
headers: {
|
||||
'X-Api-Key': props.apiKey,
|
||||
"content-type": "application/json"
|
||||
}
|
||||
}
|
||||
const response = await fetch(`https://api.clockify.me/api/v1/workspaces/${e}/projects`, request)
|
||||
const data = await response.json()
|
||||
|
||||
|
||||
|
||||
return await data
|
||||
|
||||
} catch (error) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
const defineProjects = async (e) => {
|
||||
|
||||
if (e === 0) {
|
||||
setProjectsDone(false)
|
||||
setProjects([])
|
||||
|
||||
} else {
|
||||
setProjectsDone(true)
|
||||
}
|
||||
|
||||
props.setWorspaceID(e)
|
||||
|
||||
const data = await makeRequestProjects(e)
|
||||
|
||||
await setProjects(data)
|
||||
|
||||
if (projects) {
|
||||
|
||||
|
||||
setProjectsDone(true)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const selectProject = (e) => {
|
||||
|
||||
props.setProjectID(e)
|
||||
}
|
||||
|
||||
if (loading && userUID) {
|
||||
|
||||
|
||||
if (!apiAvailable) {
|
||||
return (<div></div>)
|
||||
|
||||
} else {
|
||||
|
||||
return (
|
||||
<div className="clockify-tasks-display loading-container">
|
||||
<img src={props.darkMode ? loadingGifDarkTheme : loadingGifLightTheme} alt=""/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
return (
|
||||
<div className={props.darkMode ? 'clockify-tasks-display-container dark-mode-container' : 'clockify-tasks-display-container'}>
|
||||
{
|
||||
userUID ?
|
||||
<div className={props.timerOn ? 'clockify-tasks-display disabled' : 'clockify-tasks-display'}>
|
||||
<select onChange={(e) => {defineProjects(e.target.value)}} className='workspace-selector'>
|
||||
<option value="0">Select a Workspace</option>
|
||||
{
|
||||
workspacesReady ?
|
||||
workspaces.map( (workspace) => {
|
||||
return <option value={workspace.id} key={workspace.id}>{workspace.name}</option>
|
||||
})
|
||||
: null
|
||||
}
|
||||
</select>
|
||||
<select onChange={(e) => {selectProject(e.target.value)}} className={props.workspaceID !== 0 ? 'project-selector' : 'project-selector disabled'}>
|
||||
<option value="0">Select a Project</option>
|
||||
{
|
||||
projectsDone && projects !== undefined ?
|
||||
projects.map( (project) => {
|
||||
|
||||
if (!project.archived){
|
||||
return <option value={project.id} key={project.id}>{project.name}</option>
|
||||
|
||||
}
|
||||
})
|
||||
: null
|
||||
}
|
||||
</select>
|
||||
<input
|
||||
type="text"
|
||||
onChange={(e) => {props.setTaskName(e.target.value)}}
|
||||
value={props.taskName}
|
||||
placeholder="Add task description"
|
||||
className={props.projectID !== 0 ? null: 'disabled'}
|
||||
|
||||
onKeyPress={event => {
|
||||
|
||||
if (event.key === 'Enter') {
|
||||
|
||||
props.setTimerOn(true)
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
: null
|
||||
}
|
||||
</div>
|
||||
|
||||
)
|
||||
}
|
||||
|
||||
export default ClockifyTasksDisplay
|
||||
@@ -1,9 +1,11 @@
|
||||
import './footer-styles.css'
|
||||
|
||||
import React from 'react'
|
||||
|
||||
const Footer = (props) => {
|
||||
return (
|
||||
<footer className={props.darkMode ? 'made-with-love dark-mode-component' : 'made-with-love'}>
|
||||
Made with 💓 by <a href="https://porfolio-franp.netlify.app" target="_blank">Francisco Pessano</a>
|
||||
Made with 💓 by <a href="https://porfolio-franp.netlify.app" target="_blank" rel="noreferrer">Francisco Pessano</a>
|
||||
</footer>
|
||||
)
|
||||
}
|
||||
13
src/components/Footer/footer-styles.css
Normal file
13
src/components/Footer/footer-styles.css
Normal file
@@ -0,0 +1,13 @@
|
||||
.made-with-love {
|
||||
margin-top: auto;
|
||||
width: 100%;
|
||||
padding-top: 5vh;
|
||||
padding-bottom: 5vh;
|
||||
padding-left: 3vw;
|
||||
box-sizing: border-box;
|
||||
background-color: var(--main-background-color);
|
||||
color: rgb(185, 185, 185);
|
||||
}
|
||||
.made-with-love a {
|
||||
color: #ff8787;
|
||||
}/*# sourceMappingURL=footer-styles.css.map */
|
||||
1
src/components/Footer/footer-styles.css.map
Normal file
1
src/components/Footer/footer-styles.css.map
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"sources":["footer-styles.scss","footer-styles.css"],"names":[],"mappings":"AAAA;EAEE,gBAAA;EACA,WAAA;EAEA,gBAAA;EACA,mBAAA;EACA,iBAAA;EAEA,sBAAA;EAEA,8CAAA;EACA,yBAAA;ACHF;ADKE;EACE,cAAA;ACHJ","file":"footer-styles.css"}
|
||||
18
src/components/Footer/footer-styles.scss
Normal file
18
src/components/Footer/footer-styles.scss
Normal file
@@ -0,0 +1,18 @@
|
||||
.made-with-love {
|
||||
|
||||
margin-top: auto;
|
||||
width: 100%;
|
||||
|
||||
padding-top: 5vh;
|
||||
padding-bottom: 5vh;
|
||||
padding-left: 3vw;
|
||||
|
||||
box-sizing: border-box;
|
||||
|
||||
background-color: var(--main-background-color);
|
||||
color:rgb(185, 185, 185);
|
||||
|
||||
a {
|
||||
color: #ff8787
|
||||
}
|
||||
}
|
||||
@@ -1,17 +1,19 @@
|
||||
import './go-down-arrow-styles.css'
|
||||
|
||||
import React from 'react'
|
||||
import { Link, animateScroll as scroll } from "react-scroll";
|
||||
|
||||
const GoDownArrow = (props) => {
|
||||
|
||||
const width = window.screen.width
|
||||
const width = window.screen.width
|
||||
|
||||
if (width <= '991.98') {
|
||||
return (
|
||||
<div className={props.darkMode ? 'go-down-separator-line dark-mode-component' : 'go-down-separator-line'}>
|
||||
<hr/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
if (width <= '991.98') {
|
||||
return (
|
||||
<div className={props.darkMode ? 'go-down-separator-line dark-mode-component' : 'go-down-separator-line'}>
|
||||
<hr/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={props.darkMode ? 'go-down dark-mode-component' : 'go-down'} id={props.direction === 'credits' ? 'go-to-credits' : null}>
|
||||
26
src/components/GoDownArrow/go-down-arrow-styles.css
Normal file
26
src/components/GoDownArrow/go-down-arrow-styles.css
Normal file
@@ -0,0 +1,26 @@
|
||||
.go-down {
|
||||
background-color: var(--main-background-color);
|
||||
height: 8vh;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
.go-down svg {
|
||||
height: 6vh;
|
||||
width: 6vh;
|
||||
cursor: pointer;
|
||||
}
|
||||
.go-down svg path {
|
||||
fill: rgb(170, 170, 170);
|
||||
}
|
||||
|
||||
.go-down-separator-line {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
.go-down-separator-line hr {
|
||||
height: 1px;
|
||||
width: 75%;
|
||||
border: none;
|
||||
border-top: 1px solid rgb(184, 184, 184);
|
||||
}/*# sourceMappingURL=go-down-arrow-styles.css.map */
|
||||
1
src/components/GoDownArrow/go-down-arrow-styles.css.map
Normal file
1
src/components/GoDownArrow/go-down-arrow-styles.css.map
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"sources":["go-down-arrow-styles.scss","go-down-arrow-styles.css"],"names":[],"mappings":"AAAA;EAEI,8CAAA;EACA,WAAA;EAEA,aAAA;EACA,uBAAA;ACDJ;ADGI;EACI,WAAA;EACA,UAAA;EAEA,eAAA;ACFR;ADIQ;EACI,wBAAA;ACFZ;;ADQA;EAEI,WAAA;EAEA,aAAA;EACA,uBAAA;ACPJ;ADSI;EACI,WAAA;EACA,UAAA;EAEA,YAAA;EACA,wCAAA;ACRR","file":"go-down-arrow-styles.css"}
|
||||
@@ -1,9 +1,10 @@
|
||||
.go-down {
|
||||
|
||||
background-color: var(--main-background-color);
|
||||
height: 8vh;
|
||||
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
|
||||
|
||||
svg {
|
||||
height: 6vh;
|
||||
@@ -32,18 +33,4 @@
|
||||
border: none;
|
||||
border-top: 1px solid rgb(184, 184, 184);
|
||||
}
|
||||
}
|
||||
|
||||
.go-down-separator-line.dark-mode-component {
|
||||
background-color: $main-color-dark;
|
||||
}
|
||||
|
||||
.go-down.dark-mode-component {
|
||||
|
||||
background-color: $main-color-dark;
|
||||
}
|
||||
|
||||
.go-down.dark-mode-component#go-to-credits {
|
||||
|
||||
background-color: $second-color-dark;
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
import React from 'react'
|
||||
|
||||
const DarkMode = (props) => {
|
||||
|
||||
React.useEffect( () => {
|
||||
|
||||
if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
|
||||
props.setDarkmode(true)
|
||||
|
||||
const darkModeSwitch = document.getElementById('dark-mode_toogle-switch')
|
||||
|
||||
darkModeSwitch.checked = true
|
||||
}
|
||||
|
||||
const darkModeCache = localStorage.getItem('dark-mode')
|
||||
|
||||
if (darkModeCache === 'true') {
|
||||
props.setDarkmode(true)
|
||||
|
||||
const darkModeSwitch = document.getElementById('dark-mode_toogle-switch')
|
||||
|
||||
darkModeSwitch.checked = true
|
||||
}
|
||||
|
||||
}, [])
|
||||
|
||||
const changeTheme = () => {
|
||||
props.setDarkmode(!props.darkMode)
|
||||
|
||||
localStorage.setItem('dark-mode', !props.darkMode)
|
||||
}
|
||||
|
||||
|
||||
return (
|
||||
<div className="dark-mode">
|
||||
<input type="checkbox" id="dark-mode_toogle-switch" onChange={changeTheme}/>
|
||||
<label htmlFor="dark-mode_toogle-switch"></label>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default DarkMode
|
||||
@@ -1,22 +0,0 @@
|
||||
import React from 'react'
|
||||
|
||||
const GoToAccount = (props) => {
|
||||
return (
|
||||
<>
|
||||
{
|
||||
props.signIn ?
|
||||
<>
|
||||
<a href="/config-account" className={props.darkMode ? 'go-to-account dark-mode-component' : 'go-to-account'}>
|
||||
<div className="go-to-account-text">API</div>
|
||||
</a>
|
||||
<a href="/identify?act=clss" className={props.darkMode ? 'close-session dark-mode-component' : 'close-session'}>
|
||||
<div className="close-session-text">Close session</div>
|
||||
</a>
|
||||
</>
|
||||
: null
|
||||
}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default GoToAccount
|
||||
@@ -1,54 +0,0 @@
|
||||
import React from 'react'
|
||||
import DarkMode from './Header Childrens/DarkMode'
|
||||
import GoToAccount from './Header Childrens/GoToAccount'
|
||||
|
||||
const Header = (props) => {
|
||||
|
||||
const getPermisionDesktopNotification = async () => {
|
||||
|
||||
let permission = await Notification.requestPermission();
|
||||
|
||||
if (permission === 'granted') {
|
||||
props.setNotificationPermission(true)
|
||||
localStorage.setItem("notification-permission", true)
|
||||
} else {
|
||||
props.setNotificationPermission(false)
|
||||
localStorage.setItem("notification-permission", false)
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<header className={props.darkMode ? 'header-main-page dark-mode-component' : 'header-main-page'} >
|
||||
<a href="/" className='title-link'>
|
||||
<h1>Clockify Pomodoro Timer</h1>
|
||||
</a>
|
||||
<DarkMode
|
||||
darkMode={props.darkMode}
|
||||
setDarkmode={props.setDarkmode}
|
||||
/>
|
||||
<GoToAccount
|
||||
signIn={props.signIn}
|
||||
darkMode={props.darkMode}
|
||||
/>
|
||||
<div className="konami-code">
|
||||
{props.KonamiCodeActive ? 'Konami Code ON' : null}
|
||||
</div>
|
||||
</header>
|
||||
{
|
||||
props.notificationPermission === undefined || process.env.REACT_APP_ENVIROMENT !== "production" ?
|
||||
<div className={props.darkMode ? 'notification-select dark-mode-component' : 'notification-select'}>
|
||||
<p>Do you want to recibe a notification when a Pomodoro cicle ends?</p>
|
||||
<button className="yes" onClick={getPermisionDesktopNotification}>YES</button>
|
||||
<button className="no" onClick={() => {
|
||||
props.setNotificationPermission(false)
|
||||
localStorage.setItem("notification-permission", false)
|
||||
}}>Nah</button>
|
||||
</div>
|
||||
: null
|
||||
}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default React.memo(Header)
|
||||
72
src/components/Header/Header.jsx
Normal file
72
src/components/Header/Header.jsx
Normal file
@@ -0,0 +1,72 @@
|
||||
import './header-styles.css'
|
||||
|
||||
import React from 'react'
|
||||
import ThemeSwitch from './ThemeSwitch/ThemeSwitch'
|
||||
|
||||
const Header = (props) => {
|
||||
|
||||
const getPermisionDesktopNotification = async () => {
|
||||
let permission = await Notification.requestPermission();
|
||||
|
||||
if (permission === 'granted') {
|
||||
props.setNotificationPermission(true)
|
||||
localStorage.setItem("notification-permission", true)
|
||||
} else {
|
||||
props.setNotificationPermission(false)
|
||||
localStorage.setItem("notification-permission", false)
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<header className={props.darkMode ? 'header-main-page dark-mode-component' : 'header-main-page'} >
|
||||
<h1 className='title-link'><a href="/">Clockify Pomodoro Timer</a></h1>
|
||||
<div className="buttons-container">
|
||||
{
|
||||
props.signedIn ?
|
||||
<>
|
||||
<a href="/config-account" className={props.darkMode ? 'go-to-account dark-mode-component' : 'go-to-account'}>
|
||||
<div className="go-to-account-text">API</div>
|
||||
</a>
|
||||
<a href="/identify?act=clss" className={props.darkMode ? 'close-session dark-mode-component' : 'close-session'}>
|
||||
<div className="close-session-text">Close session</div>
|
||||
</a>
|
||||
</>
|
||||
: null
|
||||
}
|
||||
<ThemeSwitch
|
||||
darkMode={props.darkMode}
|
||||
setDarkmode={props.setDarkmode}
|
||||
/>
|
||||
</div>
|
||||
<div className="konami-code">
|
||||
{props.KonamiCodeActive ? 'Konami Code ON' : null}
|
||||
</div>
|
||||
{
|
||||
props.notificationPermission === undefined || process.env.REACT_APP_ENVIROMENT !== "production" ?
|
||||
<div className={props.darkMode ? 'notification-select dark-mode-component' : 'notification-select'}>
|
||||
<p>Do you want to recibe a notification when a Pomodoro cicle ends?</p>
|
||||
<button className="yes" onClick={getPermisionDesktopNotification}>YES</button>
|
||||
<button className="no" onClick={() => {
|
||||
props.setNotificationPermission(false)
|
||||
localStorage.setItem("notification-permission", false)
|
||||
}}>Nah</button>
|
||||
</div>
|
||||
: null
|
||||
}
|
||||
{
|
||||
!props.signedIn ?
|
||||
<div className="banner-login">
|
||||
<p>Access to integrate and save your progress with Clockify!</p>
|
||||
<div className="button-container">
|
||||
<button className="register" onClick={() => {window.location = '/identify?act=r'}}>Register</button>
|
||||
<button className="login" onClick={() => {window.location = '/identify?act=l'}}>Login</button>
|
||||
</div>
|
||||
</div>
|
||||
: null
|
||||
}
|
||||
</header>
|
||||
|
||||
)
|
||||
}
|
||||
|
||||
export default React.memo(Header)
|
||||
102
src/components/Header/ThemeSwitch/ThemeSwitch.jsx
Normal file
102
src/components/Header/ThemeSwitch/ThemeSwitch.jsx
Normal file
@@ -0,0 +1,102 @@
|
||||
import './theme-switch-styles.css'
|
||||
|
||||
import React from 'react'
|
||||
|
||||
const ThemeSwitch = () => {
|
||||
|
||||
React.useEffect( () => {
|
||||
|
||||
if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
|
||||
changeTheme({theme: "dark"})
|
||||
|
||||
const darkModeSwitch = document.getElementById('theme-switch_toogle-switch')
|
||||
darkModeSwitch.checked = true
|
||||
}
|
||||
|
||||
if (localStorage.getItem('dark-mode') === 'true') {
|
||||
changeTheme({theme: "dark"})
|
||||
|
||||
const darkModeSwitch = document.getElementById('theme-switch_toogle-switch')
|
||||
darkModeSwitch.checked = true
|
||||
|
||||
} else {
|
||||
changeTheme({theme: "white"})
|
||||
}
|
||||
|
||||
}, [])
|
||||
|
||||
function changeTheme(options) {
|
||||
let data
|
||||
let theme
|
||||
|
||||
if (options.e) {
|
||||
theme = options.e.target.checked ? "dark" : "white"
|
||||
localStorage.setItem('dark-mode', options.e.target.checked ? "true" : "false")
|
||||
}
|
||||
|
||||
if (options.theme) {
|
||||
theme = options.theme
|
||||
localStorage.setItem('dark-mode', options.theme === "dark" ? "true" : "false")
|
||||
}
|
||||
|
||||
switch (theme) {
|
||||
case "white":
|
||||
data = [
|
||||
["--main-text-color", "#1FAB89"],
|
||||
["--second-text-color", "#2c2c2c"],
|
||||
["--third-text-color", "#8d8d8d"],
|
||||
["--pomodoro-counter-text-color", "#8d8d8d"],
|
||||
|
||||
["--main-background-color", "#fff",],
|
||||
["--second-background-color", "#fff"],
|
||||
|
||||
["--main-color", "#62D2A2"],
|
||||
["--second-color", "#1FAB89"],
|
||||
|
||||
["--light-color", "#9DF3C4"],
|
||||
["--light-color-darker", "#3c8f61"],
|
||||
|
||||
["--lightest-color", "#D7FBE8"],
|
||||
["--lightest-color-darker", "#b2e9cb"]
|
||||
]
|
||||
break;
|
||||
|
||||
case "dark":
|
||||
data = [
|
||||
["--main-text-color", "#fff"],
|
||||
["--second-text-color", "#fff"],
|
||||
["--third-text-color", "#4c8ad5"],
|
||||
["--pomodoro-counter-text-color", "#fff"],
|
||||
|
||||
['--main-background-color', "#303841"],
|
||||
['--second-background-color', "#3A4750"],
|
||||
|
||||
['--main-color', '#303841'],
|
||||
["--second-color", "#3A4750"],
|
||||
|
||||
["--light-color", "#D72323"],
|
||||
["--light-color-darker", "#7c1414"],
|
||||
|
||||
["--lightest-color", "#4c8ad5"],
|
||||
["--lightest-color-darker", "#2f5686"]
|
||||
]
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
data.forEach((variable) => {
|
||||
document.body.style.setProperty(variable[0], variable[1]);
|
||||
})
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="theme-switch">
|
||||
<input type="checkbox" id="theme-switch_toogle-switch" onClick={(e) => changeTheme({e})}/>
|
||||
<label htmlFor="theme-switch_toogle-switch"></label>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default ThemeSwitch
|
||||
65
src/components/Header/ThemeSwitch/theme-switch-styles.css
Normal file
65
src/components/Header/ThemeSwitch/theme-switch-styles.css
Normal file
@@ -0,0 +1,65 @@
|
||||
.theme-switch {
|
||||
display: flex;
|
||||
}
|
||||
.theme-switch #theme-switch_toogle-switch {
|
||||
width: 0;
|
||||
height: 0;
|
||||
visibility: hidden;
|
||||
}
|
||||
.theme-switch label {
|
||||
display: block;
|
||||
width: 4vw;
|
||||
height: 4vh;
|
||||
background-color: var(--lightest-color);
|
||||
border-radius: 100px;
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
transition: 0.5s;
|
||||
box-shadow: 0 0 20px rgba(71, 122, 133, 0.3137254902);
|
||||
}
|
||||
.theme-switch label::after {
|
||||
content: "";
|
||||
width: 3.5vh;
|
||||
height: 3.5vh;
|
||||
background-color: #b632eb;
|
||||
position: absolute;
|
||||
border-radius: 100%;
|
||||
top: 0.25vh;
|
||||
left: 0.25vh;
|
||||
transition: 0.5s;
|
||||
}
|
||||
.theme-switch input:checked + label:after {
|
||||
left: calc(100% - 0.25vh);
|
||||
transform: translateX(-100%);
|
||||
background-color: var(--second-text-color);
|
||||
}
|
||||
.theme-switch input:checked + label {
|
||||
background-color: #b632eb;
|
||||
}
|
||||
|
||||
@media (max-width: 991.98px) {
|
||||
.dark-mode {
|
||||
position: initial;
|
||||
}
|
||||
.dark-mode label {
|
||||
width: 50px;
|
||||
height: 20px;
|
||||
}
|
||||
.dark-mode label::after {
|
||||
width: 15px;
|
||||
height: 15px;
|
||||
}
|
||||
}
|
||||
@media (max-width: 576px) {
|
||||
.dark-mode {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.dark-mode label {
|
||||
width: 50px;
|
||||
height: 20px;
|
||||
}
|
||||
.dark-mode label::after {
|
||||
width: 15px;
|
||||
height: 15px;
|
||||
}
|
||||
}/*# sourceMappingURL=theme-switch-styles.css.map */
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"sources":["theme-switch-styles.scss","theme-switch-styles.css"],"names":[],"mappings":"AAAA;EAEI,aAAA;ACAJ;ADEI;EACI,QAAA;EACA,SAAA;EACA,kBAAA;ACAR;ADGI;EACI,cAAA;EACA,UAAA;EACA,WAAA;EACA,uCAAA;EACA,oBAAA;EACA,kBAAA;EACA,eAAA;EACA,gBAAA;EACA,qDAAA;ACDR;ADII;EACI,WAAA;EACA,YAAA;EACA,aAAA;EACA,yBAAA;EACA,kBAAA;EACA,mBAAA;EACA,WAAA;EACA,YAAA;EACA,gBAAA;ACFR;ADKI;EACI,yBAAA;EACA,4BAAA;EAEA,0CAAA;ACJR;ADOI;EACI,yBAAA;ACLR;;ADSA;EAEI;IACI,iBAAA;ECPN;EDQM;IACI,WAAA;IACA,YAAA;ECNV;EDSM;IACI,WAAA;IACA,YAAA;ECPV;AACF;ADWA;EACI;IAWI,mBAAA;ECnBN;EDSM;IACI,WAAA;IACA,YAAA;ECPV;EDUM;IACI,WAAA;IACA,YAAA;ECRV;AACF","file":"theme-switch-styles.css"}
|
||||
@@ -1,11 +1,8 @@
|
||||
.dark-mode {
|
||||
.theme-switch {
|
||||
|
||||
position: absolute;
|
||||
|
||||
top: 1.7vh;
|
||||
left: calc(100% - 5vw);
|
||||
display: flex;
|
||||
|
||||
#dark-mode_toogle-switch {
|
||||
#theme-switch_toogle-switch {
|
||||
width: 0;
|
||||
height: 0;
|
||||
visibility: hidden;
|
||||
@@ -15,7 +12,7 @@
|
||||
display: block;
|
||||
width: 4vw;
|
||||
height: 4vh;
|
||||
background-color: $lightest-color;
|
||||
background-color: var(--lightest-color);
|
||||
border-radius: 100px;
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
@@ -39,7 +36,7 @@
|
||||
left: calc(100% - 0.25vh);
|
||||
transform: translateX(-100%);
|
||||
|
||||
background-color: $lightest-color;
|
||||
background-color: var(--second-text-color);
|
||||
}
|
||||
|
||||
input:checked + label{
|
||||
@@ -63,8 +60,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@media (max-width: 576px) {
|
||||
@media (max-width: 576px) {
|
||||
.dark-mode {
|
||||
label {
|
||||
width: 50px;
|
||||
234
src/components/Header/header-styles.css
Normal file
234
src/components/Header/header-styles.css
Normal file
@@ -0,0 +1,234 @@
|
||||
.header-main-page {
|
||||
background-color: var(--main-color);
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
flex-wrap: wrap;
|
||||
height: 24vh;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.header-main-page .title-link {
|
||||
width: -webkit-fit-content;
|
||||
width: -moz-fit-content;
|
||||
width: fit-content;
|
||||
color: #ffffff;
|
||||
font-size: 3.3em;
|
||||
display: inline;
|
||||
margin-top: auto;
|
||||
margin-bottom: auto;
|
||||
margin-left: 1vw;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-grow: 1;
|
||||
}
|
||||
.header-main-page .title-link a {
|
||||
color: #ffffff;
|
||||
font-family: var(--title-font);
|
||||
text-decoration: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
.header-main-page .konami-code {
|
||||
color: #4c8ad5;
|
||||
}
|
||||
.header-main-page .buttons-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-top: auto;
|
||||
margin-bottom: auto;
|
||||
}
|
||||
.header-main-page .buttons-container a, .header-main-page .buttons-container label {
|
||||
margin-right: 1vw;
|
||||
}
|
||||
.header-main-page .buttons-container a {
|
||||
text-decoration: none;
|
||||
}
|
||||
.header-main-page .buttons-container .go-to-account {
|
||||
width: 3vw;
|
||||
height: 3vw;
|
||||
background-color: var(--second-color);
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
border-radius: 100%;
|
||||
}
|
||||
.header-main-page .buttons-container .go-to-account .go-to-account-text {
|
||||
font-size: 1vw;
|
||||
text-decoration: none;
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
color: #ffffff;
|
||||
}
|
||||
.header-main-page .buttons-container .close-session {
|
||||
width: 7vw;
|
||||
height: 3vw;
|
||||
background-color: var(--second-color);
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
border-radius: 5%;
|
||||
}
|
||||
.header-main-page .buttons-container .close-session .close-session-text {
|
||||
font-size: 1vw;
|
||||
text-decoration: none;
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
@media (max-width: 991.98px) {
|
||||
.go-to-account, .close-session {
|
||||
position: initial;
|
||||
padding: 1vw;
|
||||
}
|
||||
|
||||
.go-to-account {
|
||||
margin-top: 10px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.go-to-account .go-to-account-text {
|
||||
font-size: 9pt;
|
||||
}
|
||||
|
||||
.close-session .close-session-text {
|
||||
font-size: 9pt;
|
||||
}
|
||||
}
|
||||
@media (max-width: 576px) {
|
||||
.go-to-account, .close-session {
|
||||
width: auto;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.go-to-account-text, .close-session-text {
|
||||
position: initial;
|
||||
margin: 10px 10px;
|
||||
}
|
||||
}
|
||||
.notification-select {
|
||||
width: 100%;
|
||||
height: 3vh;
|
||||
background-color: var(--second-color);
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
padding-left: 1vw;
|
||||
margin-top: auto;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.notification-select p {
|
||||
display: inline-block;
|
||||
align-self: center;
|
||||
color: #fff;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
margin-right: 1vw;
|
||||
}
|
||||
.notification-select button {
|
||||
height: 80%;
|
||||
width: 5%;
|
||||
margin-right: 0.5vw;
|
||||
border: none;
|
||||
border-radius: 2px;
|
||||
align-self: center;
|
||||
color: #fff;
|
||||
font-weight: bold;
|
||||
cursor: pointer;
|
||||
}
|
||||
.notification-select button.yes {
|
||||
background-color: rgb(76, 175, 80);
|
||||
}
|
||||
.notification-select button.no {
|
||||
background-color: rgb(211, 47, 47);
|
||||
}
|
||||
|
||||
@media (max-width: 991.98px) {
|
||||
.header-main-page h1 {
|
||||
font-size: 26pt;
|
||||
}
|
||||
.header-main-page h3 {
|
||||
font-size: 13pt;
|
||||
}
|
||||
|
||||
.notification-select {
|
||||
height: auto;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.notification-select p {
|
||||
width: 100%;
|
||||
margin-top: 1vh;
|
||||
margin-bottom: 1vh;
|
||||
}
|
||||
.notification-select button {
|
||||
height: 30px;
|
||||
width: 20%;
|
||||
margin-bottom: 1vh;
|
||||
}
|
||||
}
|
||||
.banner-login {
|
||||
width: 100%;
|
||||
background-color: #D17262;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 0px 5vw;
|
||||
}
|
||||
.banner-login p {
|
||||
color: #fff;
|
||||
}
|
||||
.banner-login .button-container {
|
||||
width: 20vw;
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
}
|
||||
.banner-login .button-container button {
|
||||
font-size: 12pt;
|
||||
font-weight: bold;
|
||||
color: #ffffff;
|
||||
height: 6vh;
|
||||
cursor: pointer;
|
||||
}
|
||||
.banner-login .button-container .register {
|
||||
border: solid 1px #ffffff;
|
||||
border-radius: 24px;
|
||||
}
|
||||
.banner-login .button-container .login {
|
||||
background-color: rgba(0, 0, 0, 0.3411764706);
|
||||
border-radius: 24px;
|
||||
}
|
||||
|
||||
.banner-login.blank {
|
||||
opacity: 0%;
|
||||
}
|
||||
|
||||
@media (max-width: 918px) {
|
||||
.banner-login {
|
||||
justify-content: initial;
|
||||
height: auto;
|
||||
padding: 2vh 2vw;
|
||||
}
|
||||
.banner-login p {
|
||||
width: 33.3%;
|
||||
}
|
||||
.banner-login .button-container {
|
||||
width: 66.6%;
|
||||
justify-content: space-around;
|
||||
}
|
||||
.banner-login .button-container button {
|
||||
width: 30%;
|
||||
}
|
||||
}
|
||||
@media (max-width: 576px) {
|
||||
.banner-login p {
|
||||
width: 50%;
|
||||
}
|
||||
.banner-login .button-container {
|
||||
width: 50%;
|
||||
flex-direction: column;
|
||||
}
|
||||
.banner-login .button-container button {
|
||||
width: 75%;
|
||||
margin: 10px;
|
||||
}
|
||||
}/*# sourceMappingURL=header-styles.css.map */
|
||||
1
src/components/Header/header-styles.css.map
Normal file
1
src/components/Header/header-styles.css.map
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"sources":["header-styles.scss","header-styles.css"],"names":[],"mappings":"AACA;EACI,mCAAA;EAEA,aAAA;EACA,8BAAA;EACA,eAAA;EAEA,YAAA;EAEA,sBAAA;ACHJ;ADKI;EACI,0BAAA;EAAA,uBAAA;EAAA,kBAAA;EAEA,cAAA;EAEA,gBAAA;EAEA,eAAA;EAEA,gBAAA;EACA,mBAAA;EACA,gBAAA;EAEA,aAAA;EACA,mBAAA;EACA,YAAA;ACRR;ADUQ;EACI,cAAA;EACA,8BAAA;EACA,qBAAA;EAEA,eAAA;ACTZ;ADaI;EACI,cAAA;ACXR;ADcI;EACI,aAAA;EACA,mBAAA;EAEA,gBAAA;EACA,mBAAA;ACbR;ADeQ;EACI,iBAAA;ACbZ;ADgBQ;EACI,qBAAA;ACdZ;ADiBQ;EAEI,UAAA;EACA,WAAA;EAEA,qCAAA;EAEA,aAAA;EACA,uBAAA;EACA,mBAAA;EAEA,mBAAA;ACnBZ;ADqBY;EACI,cAAA;EACA,qBAAA;EACA,yBAAA;KAAA,sBAAA;MAAA,qBAAA;UAAA,iBAAA;EAEA,cAAA;ACpBhB;ADwBQ;EACI,UAAA;EACA,WAAA;EAEA,qCAAA;EAEA,aAAA;EACA,uBAAA;EACA,mBAAA;EAEA,iBAAA;ACzBZ;AD2BY;EACI,cAAA;EAEA,qBAAA;EACA,yBAAA;KAAA,sBAAA;MAAA,qBAAA;UAAA,iBAAA;EAEA,cAAA;AC3BhB;;ADkCA;EAEI;IACG,iBAAA;IACA,YAAA;EChCL;;EDmCE;IAKI,gBAAA;IACA,mBAAA;ECpCN;ED+BM;IACI,cAAA;EC7BV;;EDqCM;IACI,cAAA;EClCV;AACF;ADsCA;EACI;IACI,WAAA;IACA,YAAA;ECpCN;;EDuCE;IACI,iBAAA;IACA,iBAAA;ECpCN;AACF;ADuCA;EAEI,WAAA;EACA,WAAA;EAEA,qCAAA;EAEA,aAAA;EACA,qBAAA;EAEA,iBAAA;EACA,gBAAA;EAEA,sBAAA;AC1CJ;AD4CI;EACI,qBAAA;EAEA,kBAAA;EAEA,WAAA;EAEA,UAAA;EAEA,SAAA;EACA,iBAAA;AC9CR;ADiDI;EACI,WAAA;EACA,SAAA;EAEA,mBAAA;EAEA,YAAA;EACA,kBAAA;EAEA,kBAAA;EAEA,WAAA;EACA,iBAAA;EAEA,eAAA;ACpDR;ADuDI;EACI,kCAAA;ACrDR;ADwDI;EACI,kCAAA;ACtDR;;AD0DA;EAGQ;IACI,eAAA;ECzDV;ED4DM;IACI,eAAA;EC1DV;;ED8DE;IACI,YAAA;IACA,eAAA;EC3DN;ED6DM;IACI,WAAA;IACA,eAAA;IACA,kBAAA;EC3DV;ED8DM;IACI,YAAA;IACA,UAAA;IACA,kBAAA;EC5DV;AACF;AD+DA;EAEI,WAAA;EAEA,yBAAA;EAMA,aAAA;EACA,mBAAA;EACA,8BAAA;EAEA,gBAAA;ACrEJ;AD6DI;EACI,WAAA;AC3DR;ADoEI;EAEI,WAAA;EAEA,aAAA;EACA,6BAAA;ACpER;ADsEQ;EACI,eAAA;EACA,iBAAA;EACA,cAAA;EAEA,WAAA;EACA,eAAA;ACrEZ;ADwEQ;EACI,yBAAA;EACA,mBAAA;ACtEZ;ADyEQ;EACI,6CAAA;EACA,mBAAA;ACvEZ;;AD4EA;EACI,WAAA;ACzEJ;;AD4EA;EACI;IACI,wBAAA;IAEA,YAAA;IAEA,gBAAA;EC3EN;ED6EM;IACI,YAAA;EC3EV;ED8EM;IACI,YAAA;IAEA,6BAAA;EC7EV;ED+EU;IACI,UAAA;EC7Ed;AACF;ADkFA;EAGQ;IACI,UAAA;EClFV;EDqFM;IACI,UAAA;IAEA,sBAAA;ECpFV;EDsFU;IACI,UAAA;IACA,YAAA;ECpFd;AACF","file":"header-styles.css"}
|
||||
313
src/components/Header/header-styles.scss
Normal file
313
src/components/Header/header-styles.scss
Normal file
@@ -0,0 +1,313 @@
|
||||
|
||||
.header-main-page {
|
||||
background-color: var(--main-color);
|
||||
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
flex-wrap: wrap;
|
||||
|
||||
height: calc(100vh - calc(68vh + 8vh)); // 100vh minus .main-pomodoro and .go-to-down-arrow
|
||||
|
||||
box-sizing: border-box;
|
||||
|
||||
.title-link {
|
||||
width: fit-content;
|
||||
|
||||
color: #ffffff;
|
||||
|
||||
font-size: 3.3em;
|
||||
|
||||
display: inline;
|
||||
|
||||
margin-top: auto;
|
||||
margin-bottom: auto;
|
||||
margin-left: 1vw;
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-grow: 1;
|
||||
|
||||
a {
|
||||
color: #ffffff;
|
||||
font-family: var(--title-font);
|
||||
text-decoration: none;
|
||||
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
.konami-code {
|
||||
color: #4c8ad5;
|
||||
}
|
||||
|
||||
.buttons-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
margin-top: auto;
|
||||
margin-bottom: auto;
|
||||
|
||||
a, label {
|
||||
margin-right: 1vw;
|
||||
}
|
||||
|
||||
a {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.go-to-account {
|
||||
|
||||
width: 3vw;
|
||||
height: 3vw;
|
||||
|
||||
background-color: var(--second-color);
|
||||
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
border-radius: 100%;
|
||||
|
||||
.go-to-account-text {
|
||||
font-size: 1vw;
|
||||
text-decoration: none;
|
||||
user-select: none;
|
||||
|
||||
color: #ffffff;
|
||||
}
|
||||
}
|
||||
|
||||
.close-session {
|
||||
width: 7vw;
|
||||
height: 3vw;
|
||||
|
||||
background-color: var(--second-color);
|
||||
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
border-radius: 5%;
|
||||
|
||||
.close-session-text {
|
||||
font-size: 1vw;
|
||||
|
||||
text-decoration: none;
|
||||
user-select: none;
|
||||
|
||||
color: #ffffff;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@media (max-width: 991.98px) {
|
||||
//! I fucking hate make the responsive design
|
||||
.go-to-account, .close-session {
|
||||
position: initial;
|
||||
padding: 1vw;
|
||||
|
||||
}
|
||||
.go-to-account {
|
||||
.go-to-account-text {
|
||||
font-size: 9pt;
|
||||
}
|
||||
|
||||
margin-top: 10px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.close-session {
|
||||
.close-session-text {
|
||||
font-size: 9pt;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 576px) {
|
||||
.go-to-account, .close-session {
|
||||
width: auto;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.go-to-account-text, .close-session-text {
|
||||
position: initial;
|
||||
margin:10px 10px;
|
||||
|
||||
}
|
||||
}
|
||||
.notification-select {
|
||||
|
||||
width: 100%;
|
||||
height: 3vh;
|
||||
|
||||
background-color: var(--second-color);
|
||||
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
|
||||
padding-left: 1vw;
|
||||
margin-top: auto;
|
||||
|
||||
box-sizing: border-box;
|
||||
|
||||
p {
|
||||
display: inline-block;
|
||||
|
||||
align-self: center;
|
||||
|
||||
color: #fff;
|
||||
|
||||
padding: 0;
|
||||
|
||||
margin: 0;
|
||||
margin-right: 1vw;
|
||||
}
|
||||
|
||||
button {
|
||||
height: 80%;
|
||||
width: 5%;
|
||||
|
||||
margin-right: 0.5vw;
|
||||
|
||||
border: none;
|
||||
border-radius: 2px;
|
||||
|
||||
align-self: center;
|
||||
|
||||
color: #fff;
|
||||
font-weight: bold;
|
||||
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
button.yes {
|
||||
background-color: rgb(76, 175, 80);
|
||||
}
|
||||
|
||||
button.no {
|
||||
background-color: rgb(211, 47, 47);
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 991.98px) {
|
||||
.header-main-page {
|
||||
|
||||
h1 {
|
||||
font-size: 26pt;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 13pt;
|
||||
}
|
||||
}
|
||||
|
||||
.notification-select {
|
||||
height: auto;
|
||||
flex-wrap: wrap;
|
||||
|
||||
p {
|
||||
width: 100%;
|
||||
margin-top: 1vh;
|
||||
margin-bottom: 1vh;
|
||||
}
|
||||
|
||||
button {
|
||||
height: 30px;
|
||||
width: 20%;
|
||||
margin-bottom: 1vh;
|
||||
}
|
||||
}
|
||||
}
|
||||
.banner-login {
|
||||
|
||||
width: 100%;
|
||||
|
||||
background-color: #D17262;
|
||||
|
||||
p {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
|
||||
padding: 0px 5vw;
|
||||
|
||||
.button-container {
|
||||
|
||||
width: 20vw;
|
||||
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
|
||||
button {
|
||||
font-size: 12pt;
|
||||
font-weight: bold;
|
||||
color: #ffffff;
|
||||
|
||||
height: 6vh;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.register {
|
||||
border: solid 1px #ffffff;
|
||||
border-radius: 24px;
|
||||
}
|
||||
|
||||
.login {
|
||||
background-color: #00000057;
|
||||
border-radius: 24px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.banner-login.blank {
|
||||
opacity: 0%;
|
||||
}
|
||||
|
||||
@media (max-width: 918px) {
|
||||
.banner-login {
|
||||
justify-content: initial;
|
||||
|
||||
height: auto;
|
||||
|
||||
padding: 2vh 2vw;
|
||||
|
||||
p {
|
||||
width: 33.3%;
|
||||
}
|
||||
|
||||
.button-container {
|
||||
width: 66.6%;
|
||||
|
||||
justify-content: space-around;
|
||||
|
||||
button {
|
||||
width: 30%;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 576px) {
|
||||
.banner-login {
|
||||
|
||||
p {
|
||||
width: 50%;
|
||||
}
|
||||
|
||||
.button-container {
|
||||
width: 50%;
|
||||
|
||||
flex-direction: column;
|
||||
|
||||
button {
|
||||
width: 75%;
|
||||
margin: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
import React from 'react'
|
||||
|
||||
const LoginForm = (props) => {
|
||||
return (
|
||||
<>
|
||||
<form onSubmit={props.sendForm}>
|
||||
<input
|
||||
type="email"
|
||||
placeholder="Email"
|
||||
onChange= {(e) => {
|
||||
props.setEmail(e.target.value)
|
||||
}}
|
||||
/>
|
||||
|
||||
<input
|
||||
type="password"
|
||||
placeholder="Password"
|
||||
onChange= { (e) => {
|
||||
props.setPassword(e.target.value)
|
||||
}}
|
||||
/>
|
||||
<input type="submit" value="Login"></input>
|
||||
|
||||
<button class="reset-password" onClick={() => props.setAct('i forgor')}>Reset Password?</button>
|
||||
</form>
|
||||
|
||||
|
||||
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default LoginForm
|
||||
@@ -1,39 +0,0 @@
|
||||
import React from 'react'
|
||||
|
||||
const RegisterForm = (props) => {
|
||||
return (
|
||||
<form onSubmit={props.sendForm}>
|
||||
<input
|
||||
type="email"
|
||||
placeholder="Email"
|
||||
onChange={(e) => {
|
||||
props.setEmail(e.target.value)
|
||||
}}
|
||||
/>
|
||||
|
||||
<input
|
||||
type="password"
|
||||
placeholder="Password"
|
||||
onChange={(e) => {
|
||||
props.setPassword(e.target.value)
|
||||
}}
|
||||
|
||||
/>
|
||||
|
||||
<input
|
||||
type="password"
|
||||
placeholder="Confirm Password"
|
||||
onChange={(e) => {
|
||||
props.setConfirmPassword(e.target.value)
|
||||
}}
|
||||
/>
|
||||
|
||||
<input
|
||||
type="submit"
|
||||
value="Register"
|
||||
/>
|
||||
</form>
|
||||
)
|
||||
}
|
||||
|
||||
export default RegisterForm
|
||||
@@ -1,19 +0,0 @@
|
||||
import React from 'react'
|
||||
|
||||
const ResetPassword = (props) => {
|
||||
return (
|
||||
<form onSubmit={props.sendForm}>
|
||||
<input
|
||||
type="email"
|
||||
placeholder="Email"
|
||||
onChange= {(e) => {
|
||||
props.setEmail(e.target.value)
|
||||
}}
|
||||
/>
|
||||
<input type="submit" value="Reset password"></input>
|
||||
<button class="reset-password" onClick={() => props.setAct('login')}>Back to login</button>
|
||||
</form>
|
||||
)
|
||||
}
|
||||
|
||||
export default ResetPassword
|
||||
@@ -1,311 +0,0 @@
|
||||
import { createUserWithEmailAndPassword, getAuth, onAuthStateChanged, sendPasswordResetEmail, signInWithEmailAndPassword, signOut } from 'firebase/auth'
|
||||
import { doc, getFirestore, setDoc } from 'firebase/firestore'
|
||||
import React, { useState } from 'react'
|
||||
import { withRouter } from 'react-router-dom'
|
||||
import { firebase } from './Firebase/firebase'
|
||||
import LoginForm from './Identify Childrens/LoginForm'
|
||||
import RegisterForm from './Identify Childrens/RegisterForm'
|
||||
import ResetPassword from './Identify Childrens/ResetPassword'
|
||||
import loadingGifDarkTheme from './img/loading-dark-theme.png'
|
||||
import loadingGifLightTheme from './img/loading-light-theme.png'
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
const Identify = (props) => {
|
||||
|
||||
const [act, setAct] = useState('')
|
||||
|
||||
const [email, setEmail] = useState('')
|
||||
const [password, setPassword] = useState('')
|
||||
const [confirmPassword, setConfirmPassword] = useState('')
|
||||
|
||||
const [message, setMessage] = React.useState('')
|
||||
const [errorMessage, setErrorMessage] = React.useState(0)
|
||||
const [successMessage, setSuccessMessage] = React.useState(0)
|
||||
const [loading, setLoading] = useState(false)
|
||||
|
||||
const auth = getAuth()
|
||||
|
||||
const register = async () => {
|
||||
|
||||
onAuthStateChanged(auth, (user) => {
|
||||
if (user) {
|
||||
return
|
||||
}
|
||||
})
|
||||
|
||||
try {
|
||||
const response = await createUserWithEmailAndPassword(auth, email, password)
|
||||
|
||||
|
||||
|
||||
const uid = response.user.uid
|
||||
|
||||
addNewUserToFirebase(uid)
|
||||
props.history.push('/config-account')
|
||||
setLoading(false)
|
||||
|
||||
|
||||
} catch (error) {
|
||||
|
||||
setMessage(error.message)
|
||||
setLoading(false)
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
const addNewUserToFirebase = async (uid) => {
|
||||
|
||||
try {
|
||||
|
||||
const db = getFirestore(firebase)
|
||||
|
||||
await setDoc(doc(db, 'users', uid), {
|
||||
|
||||
keyClockify: ''
|
||||
})
|
||||
|
||||
} catch (error) {
|
||||
setMessage(error)
|
||||
}
|
||||
}
|
||||
|
||||
const login = async () => {
|
||||
|
||||
onAuthStateChanged(auth, (user) => {
|
||||
if (user) {
|
||||
return
|
||||
}
|
||||
})
|
||||
|
||||
try {
|
||||
const response = await signInWithEmailAndPassword(auth, email, password)
|
||||
|
||||
props.history.push('/config-account')
|
||||
await setLoading(false)
|
||||
|
||||
|
||||
} catch (error) {
|
||||
|
||||
setErrorMessage('USER OR PASSWORD NOT VALID')
|
||||
setLoading(false)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
const resetPasswordFirestore = async () => {
|
||||
|
||||
try {
|
||||
|
||||
const response = await sendPasswordResetEmail(auth, email)
|
||||
|
||||
setSuccessMessage('Recovery email send')
|
||||
setLoading(false)
|
||||
|
||||
} catch (error) {
|
||||
setErrorMessage('There was a problem sending the email.')
|
||||
setLoading(false)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
const defineLogin = () => {
|
||||
if (act !== 'login') {
|
||||
setAct('login')
|
||||
}
|
||||
}
|
||||
|
||||
const defineRegister = () => {
|
||||
if (act !== 'register') {
|
||||
setAct('register')
|
||||
}
|
||||
}
|
||||
|
||||
const sendForm = (e) => {
|
||||
e.preventDefault()
|
||||
|
||||
setLoading(true)
|
||||
|
||||
if (!email.trim()) {
|
||||
setErrorMessage('EMAIL EMPTY')
|
||||
setLoading(false)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if (act !== 'i forgor') {
|
||||
|
||||
if (!password.trim()) {
|
||||
setErrorMessage('PASSWORD EMPTY')
|
||||
setLoading(false)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if (password.trim().length < 8) {
|
||||
setErrorMessage('PASSWORD TOO SHORT')
|
||||
setLoading(false)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (act === 'register') {
|
||||
|
||||
if (!confirmPassword.trim()) {
|
||||
setErrorMessage('CONFIRM PASSWORD PLEASE')
|
||||
setLoading(false)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if (password !== confirmPassword) {
|
||||
setErrorMessage("PASSWORDS DOESN'T MATCH")
|
||||
setLoading(false)
|
||||
|
||||
return
|
||||
}
|
||||
register()
|
||||
|
||||
e.target.reset()
|
||||
setEmail('')
|
||||
setPassword('')
|
||||
setConfirmPassword('')
|
||||
setErrorMessage(0)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if (act === 'login') {
|
||||
|
||||
login()
|
||||
|
||||
e.target.reset()
|
||||
setEmail('')
|
||||
setPassword('')
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if (act === 'i forgor') {
|
||||
|
||||
resetPasswordFirestore()
|
||||
|
||||
e.target.reset()
|
||||
setEmail('')
|
||||
setErrorMessage(0)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
setErrorMessage('ACTION NOT VALID')
|
||||
}
|
||||
|
||||
const signOutFromApp = () => {
|
||||
|
||||
signOut(auth)
|
||||
.then(() => {
|
||||
|
||||
setErrorMessage('YOU CLOSED THE SESSION')
|
||||
//! 'YOU CLOSE SESSION' MESSAGE CODE
|
||||
})
|
||||
}
|
||||
|
||||
React.useEffect( () => {
|
||||
const urlInfo = new URLSearchParams(window.location.search)
|
||||
const action = urlInfo.get('act')
|
||||
|
||||
if (action === 'r') {
|
||||
setAct('register')
|
||||
} else {
|
||||
setAct('login')
|
||||
}
|
||||
|
||||
if (action === 'clss') {
|
||||
signOutFromApp()
|
||||
return
|
||||
}
|
||||
|
||||
onAuthStateChanged(auth, (user) => {
|
||||
if (user) {
|
||||
props.history.push('/')
|
||||
}
|
||||
})
|
||||
}, [])
|
||||
|
||||
if (loading) {
|
||||
|
||||
return (
|
||||
<div className={props.darkMode ? 'loading-container dark-mode-component' : 'loading-container'} >
|
||||
<img src={props.darkMode ? loadingGifDarkTheme : loadingGifLightTheme} alt=""/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={props.darkMode ? 'identify-container dark-mode-component' : 'identify-container'}>
|
||||
<div className="error-message-container">
|
||||
{
|
||||
errorMessage ? <p>{errorMessage}</p> : null
|
||||
}
|
||||
</div>
|
||||
<div className="success-message-container">
|
||||
{
|
||||
successMessage ? <p>{successMessage}</p> : null
|
||||
}
|
||||
</div>
|
||||
<div className="identify">
|
||||
|
||||
<nav className="options-container">
|
||||
|
||||
<div
|
||||
|
||||
className={
|
||||
act === 'login' ? 'option active-option': 'option'
|
||||
}
|
||||
|
||||
onClick={() => {
|
||||
defineLogin()
|
||||
}}
|
||||
|
||||
>
|
||||
<h2>LOGIN</h2>
|
||||
</div>
|
||||
|
||||
<div
|
||||
|
||||
className={
|
||||
act === 'register' ? 'option active-option': 'option'
|
||||
}
|
||||
|
||||
onClick={() => {
|
||||
defineRegister()
|
||||
}}
|
||||
|
||||
>
|
||||
<h2>REGISTER</h2>
|
||||
</div>
|
||||
|
||||
</nav>
|
||||
|
||||
<div className="form-container">
|
||||
{
|
||||
act === 'login' ? <LoginForm setEmail={setEmail} setPassword={setPassword} sendForm={sendForm} setAct={setAct}/> : null
|
||||
}
|
||||
{
|
||||
act === 'register' ? <RegisterForm setEmail={setEmail} setPassword={setPassword} setConfirmPassword={setConfirmPassword} sendForm={sendForm}/> : null
|
||||
}
|
||||
{
|
||||
act === 'i forgor' ? <ResetPassword setEmail={setEmail} sendForm={sendForm} setAct={setAct}/> : null
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default withRouter(Identify)
|
||||
14
src/components/Loading/Loading.jsx
Normal file
14
src/components/Loading/Loading.jsx
Normal file
@@ -0,0 +1,14 @@
|
||||
import React from 'react'
|
||||
import loadingImage from './img/loading-light-theme.png'
|
||||
|
||||
const Loading = () => {
|
||||
return (
|
||||
<>
|
||||
<div className="loading-container">
|
||||
<img src={loadingImage} alt="loading"/>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default Loading
|
||||
|
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 29 KiB |
|
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 26 KiB |
5
src/components/Loading/loading-styles.css
Normal file
5
src/components/Loading/loading-styles.css
Normal file
@@ -0,0 +1,5 @@
|
||||
.loading-container {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: #fff;
|
||||
}/*# sourceMappingURL=loading-styles.css.map */
|
||||
1
src/components/Loading/loading-styles.css.map
Normal file
1
src/components/Loading/loading-styles.css.map
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"sources":["loading-styles.scss","loading-styles.css"],"names":[],"mappings":"AAAA;EACI,WAAA;EACA,YAAA;EAEA,sBAAA;ACAJ","file":"loading-styles.css"}
|
||||
6
src/components/Loading/loading-styles.scss
Normal file
6
src/components/Loading/loading-styles.scss
Normal file
@@ -0,0 +1,6 @@
|
||||
.loading-container {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
background-color: #fff;
|
||||
}
|
||||
@@ -1,117 +0,0 @@
|
||||
const setTimeStyleExternal = (props, setMinutes, setSeconds, setBreakTime, setActualStyle, breakTime) => {
|
||||
|
||||
if (props.style === 'Can I play, Daddy?') {
|
||||
const minutes = 10
|
||||
const seconds = 0
|
||||
|
||||
setMinutes(minutes)
|
||||
setSeconds(seconds)
|
||||
|
||||
setBreakTime(
|
||||
{
|
||||
normal: {
|
||||
minutes: 5,
|
||||
seconds: 0
|
||||
},
|
||||
extended: {
|
||||
minutes: 15,
|
||||
seconds: 0
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
setActualStyle(props.style)
|
||||
|
||||
return {
|
||||
minutes, seconds, breakTime
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (props.style === 'Regular'){
|
||||
|
||||
const minutes = 25
|
||||
const seconds = 0
|
||||
|
||||
setMinutes(minutes)
|
||||
setSeconds(seconds)
|
||||
|
||||
setBreakTime(
|
||||
{
|
||||
normal: {
|
||||
minutes: 5,
|
||||
seconds: 0
|
||||
},
|
||||
extended: {
|
||||
minutes: 15,
|
||||
seconds: 0
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
setActualStyle(props.style)
|
||||
|
||||
return {
|
||||
minutes, seconds, breakTime
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (props.style === 'Creative work') {
|
||||
const minutes = 50
|
||||
const seconds = 0
|
||||
|
||||
setMinutes(minutes)
|
||||
setSeconds(seconds)
|
||||
|
||||
setBreakTime(
|
||||
{
|
||||
normal: {
|
||||
minutes: 10,
|
||||
seconds: 0
|
||||
},
|
||||
extended: {
|
||||
minutes: 20,
|
||||
seconds: 0
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
setActualStyle(props.style)
|
||||
|
||||
return {
|
||||
minutes, seconds, breakTime
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (props.style === 'Last minute delivery') {
|
||||
const minutes = 90
|
||||
const seconds = 0
|
||||
|
||||
setMinutes(minutes)
|
||||
setSeconds(seconds)
|
||||
|
||||
setBreakTime(
|
||||
{
|
||||
normal: {
|
||||
minutes: 15,
|
||||
seconds: 0
|
||||
},
|
||||
extended: {
|
||||
minutes: 30,
|
||||
seconds: 0
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
setActualStyle(props.style)
|
||||
|
||||
return {
|
||||
minutes, seconds, breakTime
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
export default setTimeStyleExternal
|
||||
@@ -1,22 +0,0 @@
|
||||
import React from 'react'
|
||||
|
||||
const PomodoroCounter = (props) => {
|
||||
|
||||
return (
|
||||
<div className={props.darkMode ? 'pomodoro-counter dark-mode-component': 'pomodoro-counter'}>
|
||||
<ul>
|
||||
<li>
|
||||
<span className="quantity">{props.pomodoros}</span><span className="separator"> - </span>Pomodoros
|
||||
</li>
|
||||
<li>
|
||||
<span className="quantity">{props.rests}</span><span className="separator"> - </span>Rests
|
||||
</li>
|
||||
<li>
|
||||
<span className="quantity">{props.longRests}</span><span className="separator"> - </span>Long rests
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default PomodoroCounter
|
||||
@@ -1,33 +0,0 @@
|
||||
import React from 'react'
|
||||
|
||||
const StyleSelectionChildren = (props) => {
|
||||
return (
|
||||
<div
|
||||
className="style-container"
|
||||
onClick = { (e) => {
|
||||
props.setStyle(props.title)
|
||||
}}
|
||||
>
|
||||
|
||||
<span class="checkbox__input">
|
||||
<input
|
||||
id={`input-${props.number}`}
|
||||
type="checkbox"
|
||||
checked=
|
||||
{
|
||||
props.style === props.title ? true : false
|
||||
}
|
||||
|
||||
>
|
||||
</input>
|
||||
<span className="checkbox_control"></span>
|
||||
</span>
|
||||
<label for={`input-${props.number}`}>
|
||||
<span className="title">{props.title}</span>
|
||||
<span className="times">{props.times}</span>
|
||||
</label>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default StyleSelectionChildren
|
||||
@@ -1,21 +0,0 @@
|
||||
import React from 'react'
|
||||
import StyleSelectionChildren from './Style Selector Children/StyleSelectionChildren'
|
||||
|
||||
const StyleSelector = (props) => {
|
||||
return (
|
||||
<div className={props.darkMode ? 'style-selector-container dark-mode-component' : 'style-selector-container'}>
|
||||
<div className={`style-selector ${props.displayHidden ? 'style-selector-hidden': 'style-selector-show'}`} >
|
||||
<h2>Select Style</h2>
|
||||
|
||||
<div className="style-selection-container">
|
||||
<StyleSelectionChildren number={1} title={"Can I play, Daddy?"} times={"10 min. | 5 min. | 15 min."} style={props.style} setStyle={props.setStyle}/>
|
||||
<StyleSelectionChildren number={2} title={"Regular"} times={"25 min. | 5 min. | 15 min."} style={props.style} setStyle={props.setStyle}/>
|
||||
<StyleSelectionChildren number={3} title={"Creative work"} times={"50 min. | 10 min. | 20 min."} style={props.style} setStyle={props.setStyle}/>
|
||||
<StyleSelectionChildren number={4} title={"Last minute delivery"} times={"90 min. | 15 min. | 30 min."} style={props.style} setStyle={props.setStyle}/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default StyleSelector
|
||||
@@ -1,112 +0,0 @@
|
||||
import React, {useState} from 'react'
|
||||
import MainPomodoroTimer from './Main Pomodoro Childrens/MainPomodoroTimer'
|
||||
import PomodoroCounter from './Main Pomodoro Childrens/PomodoroCounter'
|
||||
import StyleSelector from './Main Pomodoro Childrens/StyleSelector'
|
||||
import uploadToClockifyTimer from './Clockify/uploadToClockifyTimer'
|
||||
|
||||
const MainPomodoro = (props) => {
|
||||
|
||||
const [style, setStyle] = useState('Regular')
|
||||
const [displayHidden, setDisplayHidden] = useState(true)
|
||||
|
||||
const [pomodoros, setPomodoros] = useState(0)
|
||||
const [rests, setRests] = useState(0)
|
||||
const [longRests, setLongRests] = useState(0)
|
||||
|
||||
const [startTime, setStartTime] = useState('')
|
||||
const [endTime, setEndTime] = useState('')
|
||||
|
||||
const [letsUpload, setLetsUpload] = useState(false)
|
||||
|
||||
|
||||
const showStyles = () => {
|
||||
setDisplayHidden(!displayHidden)
|
||||
}
|
||||
|
||||
React.useEffect( () => {
|
||||
if (letsUpload) {
|
||||
|
||||
uploadToClockifyTimer(props.workspaceID, props.projectID, startTime, endTime, props.apiKey, props.taskName)
|
||||
|
||||
setLetsUpload(false)
|
||||
|
||||
setStartTime('')
|
||||
setEndTime('')
|
||||
}
|
||||
})
|
||||
|
||||
return (
|
||||
<div className={props.darkMode ? 'main-pomodoro-container dark-mode-component' : 'main-pomodoro-container'}>
|
||||
<div className="main-pomodoro">
|
||||
|
||||
<MainPomodoroTimer
|
||||
|
||||
style={style}
|
||||
|
||||
timerOn={props.timerOn}
|
||||
setTimerOn={props.setTimerOn}
|
||||
|
||||
pomodoros={pomodoros}
|
||||
setPomodoros={setPomodoros}
|
||||
|
||||
rests={rests}
|
||||
setRests={setRests}
|
||||
|
||||
longRests={longRests}
|
||||
setLongRests={setLongRests}
|
||||
|
||||
|
||||
workspaceID={props.workspaceID}
|
||||
setWorspaceID={props.setWorspaceID}
|
||||
|
||||
projectID={props.projectID}
|
||||
setProjectID={props.setProjectID}
|
||||
|
||||
apiKey={props.apiKey}
|
||||
|
||||
/*alreadyCountingStart={alreadyCountingStart}
|
||||
setAlreadyCountingStart={setAlreadyCountingStart}
|
||||
|
||||
alreadyCountingEnd={alreadyCountingEnd}
|
||||
setAlreadyCountingEnd={setAlreadyCountingEnd}*/
|
||||
|
||||
startTime={startTime}
|
||||
setStartTime={setStartTime}
|
||||
|
||||
endtime={endTime}
|
||||
setEndTime={setEndTime}
|
||||
|
||||
setLetsUpload={setLetsUpload}
|
||||
|
||||
setKonamiCodeActive={props.setKonamiCodeActive}
|
||||
KonamiCodeActive= {props.KonamiCodeActive}
|
||||
|
||||
notificationPermission={props.notificationPermission}
|
||||
|
||||
/>
|
||||
|
||||
|
||||
<div className="style-display">
|
||||
<h4>
|
||||
Style
|
||||
</h4>
|
||||
<h3 onClick={showStyles}>
|
||||
{style}
|
||||
</h3>
|
||||
</div>
|
||||
|
||||
<button className="start-pomodoro" onClick={() => props.setTimerOn(!props.timerOn)}>{
|
||||
props.timerOn ? 'STOP' : 'START'
|
||||
|
||||
}</button>
|
||||
</div>
|
||||
|
||||
<StyleSelector displayHidden={displayHidden} style={style} setStyle={setStyle} darkMode={props.darkMode}/>
|
||||
<PomodoroCounter pomodoros={pomodoros} rests={rests} longRests={longRests} darkMode={props.darkMode}/>
|
||||
</div>
|
||||
|
||||
|
||||
)
|
||||
}
|
||||
|
||||
export default MainPomodoro
|
||||
12
src/components/Message/Message.jsx
Normal file
12
src/components/Message/Message.jsx
Normal file
@@ -0,0 +1,12 @@
|
||||
import React from 'react'
|
||||
|
||||
const Message = (props) => {
|
||||
|
||||
return (
|
||||
<div id="message" className={props.message.success === true ? 'successfully' : null}>
|
||||
<h1>{props.message.text}</h1>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default Message
|
||||
@@ -1,8 +1,11 @@
|
||||
import './about-this-styles.css'
|
||||
|
||||
import React from 'react'
|
||||
import GoDownArrow from '../../components/GoDownArrow/GoDownArrow'
|
||||
|
||||
const AboutThis = (props) => {
|
||||
|
||||
return (
|
||||
<>
|
||||
<div id="about-this" className={props.darkMode ? 'dark-mode-component' : null}>
|
||||
<div className="titles">
|
||||
<h3>About<span className="line-through"> us </span>this</h3>
|
||||
@@ -56,12 +59,17 @@ const AboutThis = (props) => {
|
||||
You have more projects?
|
||||
</h4>
|
||||
<p>
|
||||
Yes!, all there are in my <a target="_blank" href="https://porfolio-franp.netlify.app">personal website</a>.
|
||||
Yes!, all there are in my <a target="_blank" href="https://porfolio-franp.netlify.app" rel="noreferrer">personal website</a>.
|
||||
</p>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<GoDownArrow
|
||||
direction={'credits'}
|
||||
darkMode={props.darkMode}
|
||||
/>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
50
src/pages/AboutThis/about-this-styles.css
Normal file
50
src/pages/AboutThis/about-this-styles.css
Normal file
@@ -0,0 +1,50 @@
|
||||
#about-this, #credits {
|
||||
height: 83vh;
|
||||
background-color: var(--second-background-color);
|
||||
color: var(--second-text-color);
|
||||
padding: 0px 3vw;
|
||||
padding-top: 5vh;
|
||||
padding-bottom: 5vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
}
|
||||
#about-this .titles, #credits .titles {
|
||||
display: flex;
|
||||
}
|
||||
#about-this .titles h3, #credits .titles h3 {
|
||||
width: 50%;
|
||||
font-size: 22pt;
|
||||
}
|
||||
#about-this .titles h3 .line-through, #credits .titles h3 .line-through {
|
||||
text-decoration: line-through;
|
||||
text-decoration-thickness: 3px;
|
||||
}
|
||||
#about-this .information, #credits .information {
|
||||
display: flex;
|
||||
}
|
||||
#about-this .information ul, #credits .information ul {
|
||||
width: 50%;
|
||||
}
|
||||
#about-this .information ul li, #credits .information ul li {
|
||||
margin-top: 3vh;
|
||||
}
|
||||
#about-this .information ul li h4, #credits .information ul li h4 {
|
||||
font-size: 18pt;
|
||||
}
|
||||
#about-this .information ul li p, #credits .information ul li p {
|
||||
font-size: 13pt;
|
||||
margin-left: 2vw;
|
||||
margin-top: 1vh;
|
||||
}
|
||||
|
||||
#credits {
|
||||
height: 95vh;
|
||||
}
|
||||
|
||||
@media (max-width: 918px) {
|
||||
#about-this, #credits {
|
||||
height: auto;
|
||||
padding-bottom: 5vh;
|
||||
}
|
||||
}/*# sourceMappingURL=about-this-styles.css.map */
|
||||
1
src/pages/AboutThis/about-this-styles.css.map
Normal file
1
src/pages/AboutThis/about-this-styles.css.map
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"sources":["about-this-styles.scss","about-this-styles.css"],"names":[],"mappings":"AAAA;EACI,YAAA;EAEA,gDAAA;EACA,+BAAA;EAEA,gBAAA;EACA,gBAAA;EACA,mBAAA;EAEA,aAAA;EACA,sBAAA;EACA,oBAAA;ACFJ;ADII;EAEI,aAAA;ACHR;ADKQ;EACI,UAAA;EAEA,eAAA;ACJZ;ADMY;EACI,6BAAA;EACA,8BAAA;ACJhB;ADSI;EAEI,aAAA;ACRR;ADUQ;EACI,UAAA;ACRZ;ADUY;EAEI,eAAA;ACThB;ADWgB;EACI,eAAA;ACTpB;ADYgB;EACI,eAAA;EACA,gBAAA;EACA,eAAA;ACVpB;;ADiBA;EACI,YAAA;ACdJ;;ADiBA;EACI;IACI,YAAA;IAEA,mBAAA;ECfN;AACF","file":"about-this-styles.css"}
|
||||
@@ -1,6 +1,9 @@
|
||||
#about-this, #credits {
|
||||
height: 83vh;
|
||||
|
||||
background-color: var(--second-background-color);
|
||||
color: var(--second-text-color);
|
||||
|
||||
padding: 0px 3vw;
|
||||
padding-top: 5vh;
|
||||
padding-bottom: 5vh;
|
||||
@@ -16,9 +19,6 @@
|
||||
h3 {
|
||||
width: 50%;
|
||||
|
||||
@include titleFont;
|
||||
@include normalizeTitle;
|
||||
|
||||
font-size: 22pt;
|
||||
|
||||
.line-through {
|
||||
@@ -40,14 +40,10 @@
|
||||
margin-top: 3vh;
|
||||
|
||||
h4 {
|
||||
@include normalizeTitle;
|
||||
@include bodyFont;
|
||||
font-size: 18pt;
|
||||
}
|
||||
|
||||
p {
|
||||
@include normalizeBody;
|
||||
@include bodyFont;
|
||||
font-size: 13pt;
|
||||
margin-left: 2vw;
|
||||
margin-top: 1vh;
|
||||
@@ -67,29 +63,4 @@
|
||||
|
||||
padding-bottom: 5vh;
|
||||
}
|
||||
}
|
||||
|
||||
#about-this.dark-mode-component, #credits.dark-mode-component {
|
||||
|
||||
background-color: $second-color-dark;
|
||||
|
||||
color: #ffffff;
|
||||
|
||||
.information {
|
||||
|
||||
display: flex;
|
||||
|
||||
ul {
|
||||
|
||||
li {
|
||||
|
||||
p {
|
||||
|
||||
a {
|
||||
color: $lightest-color-dark;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,14 +1,16 @@
|
||||
import './config-account-styles.css'
|
||||
|
||||
import React, { useState } from 'react';
|
||||
import { getAuth, onAuthStateChanged } from 'firebase/auth';
|
||||
import { doc, getDoc, getFirestore, updateDoc } from "firebase/firestore";
|
||||
import React, { useState } from 'react';
|
||||
import Message from './Account Childrens/Message';
|
||||
import { firebase } from './Firebase/firebase';
|
||||
import loadingGifDarkTheme from './img/loading-dark-theme.png';
|
||||
import loadingGifLightTheme from './img/loading-light-theme.png';
|
||||
|
||||
const Account = (props) => {
|
||||
import Loading from '../../components/Loading/Loading';
|
||||
import Message from '../../components/Message/Message';
|
||||
import { firebase } from '../../Firebase/firebase';
|
||||
|
||||
const [signIn, setSignIn] = useState('false')
|
||||
const ConfigAccount = (props) => {
|
||||
|
||||
const [signedIn, setSignedIn] = useState('false')
|
||||
const [apiKey, setApiKey] = useState('')
|
||||
const [fristThreeApiKey, setFristThreeApiKey] = useState('')
|
||||
|
||||
@@ -21,14 +23,13 @@ const Account = (props) => {
|
||||
let userUID
|
||||
|
||||
onAuthStateChanged(auth, (user) => {
|
||||
|
||||
if (user) {
|
||||
setSignIn(true)
|
||||
setSignedIn(true)
|
||||
userUID = user.uid
|
||||
} else {
|
||||
setSignIn(false)
|
||||
setSignedIn(false)
|
||||
setLoading(false)
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
React.useEffect( () => {
|
||||
@@ -44,24 +45,31 @@ const Account = (props) => {
|
||||
const data = await makeRequest()
|
||||
|
||||
if (await validateRequest(data)) {
|
||||
|
||||
setActualState('API VALID')
|
||||
|
||||
if (await uploadApiKey()) {
|
||||
|
||||
setActualState('API UPLOADED')
|
||||
setActualState({
|
||||
text: "API uploaded successfully",
|
||||
success: true
|
||||
})
|
||||
setFristThreeApiKey(apiKey[0] + apiKey[1] + apiKey[2])
|
||||
|
||||
setProcessing(false)
|
||||
} else {
|
||||
|
||||
setActualState('API NOT UPLOADED')
|
||||
setActualState({
|
||||
text: "There's been an error while we upload your API Key. Please try again",
|
||||
success: false
|
||||
})
|
||||
setProcessing(false)
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
setActualState('API NOT VALID')
|
||||
setActualState({
|
||||
text: 'The API is not valid',
|
||||
sucess: false
|
||||
})
|
||||
setProcessing(false)
|
||||
}
|
||||
|
||||
@@ -135,7 +143,10 @@ const Account = (props) => {
|
||||
const applyApiState = (data) => {
|
||||
if (data.keyClockify !== '') {
|
||||
|
||||
setActualState('API UPLOADED')
|
||||
setActualState({
|
||||
text: "API uploaded successfully",
|
||||
success: true
|
||||
})
|
||||
setApiKey(data.keyClockify)
|
||||
setFristThreeApiKey(apiKey[0] + apiKey[1] + apiKey[2])
|
||||
}
|
||||
@@ -159,27 +170,26 @@ const Account = (props) => {
|
||||
setApiKey('aa')
|
||||
setApiKey('')
|
||||
}
|
||||
|
||||
if (loading) {
|
||||
return (
|
||||
<div className={props.darkMode ? "loading-container dark-mode-component" : "loading-container"}>
|
||||
<img src={props.darkMode ? loadingGifDarkTheme : loadingGifLightTheme} alt="" />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
{
|
||||
loading ?
|
||||
<Loading/>
|
||||
:
|
||||
<div className={props.darkMode ? "account-container dark-mode-component" : "account-container"}>
|
||||
{
|
||||
actualState === 'API NOT VALID' || actualState === 'API NOT UPLOADED' || actualState === 'API UPLOADED' ? <Message message={actualState}/> : null
|
||||
actualState !== '' ?
|
||||
<Message message={actualState}/>
|
||||
: null
|
||||
}
|
||||
{
|
||||
signIn ?
|
||||
signedIn ?
|
||||
<div className="next-step">
|
||||
<div className={actualState === 'API UPLOADED' ? 'disabled' : null}>
|
||||
<div className={actualState.success === true ? 'disabled' : null}>
|
||||
<div className="next-step-title">
|
||||
<h1>One more step...</h1>
|
||||
<h2>Insert your <a href="https://clockify.me/help/faq/where-can-find-api-information" target="_blank">Clockify API</a> here</h2>
|
||||
<h2>Insert your <a href="https://app.clockify.me/user/settings" target="_blank" rel="noreferrer">Clockify API Key</a> here</h2>
|
||||
</div>
|
||||
|
||||
<form
|
||||
@@ -204,7 +214,7 @@ const Account = (props) => {
|
||||
</div>
|
||||
|
||||
{
|
||||
actualState === 'API UPLOADED' ?
|
||||
actualState.success === true ?
|
||||
|
||||
<div className="flex-container-change-api-container">
|
||||
<div className="change-api-container">
|
||||
@@ -233,11 +243,14 @@ const Account = (props) => {
|
||||
</div>
|
||||
: null
|
||||
}
|
||||
</div>:
|
||||
</div>
|
||||
:
|
||||
<h1>Sign in before access to this page...</h1>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default Account
|
||||
export default ConfigAccount
|
||||
105
src/pages/ConfigAccount/config-account-styles.css
Normal file
105
src/pages/ConfigAccount/config-account-styles.css
Normal file
@@ -0,0 +1,105 @@
|
||||
.account-container #message {
|
||||
padding-left: 5vw;
|
||||
background-color: #ff6a6a;
|
||||
}
|
||||
.account-container #message h1 {
|
||||
color: #ffffff;
|
||||
padding: 2vh 0px;
|
||||
}
|
||||
.account-container .successfully {
|
||||
background-color: #75b7ff !important;
|
||||
}
|
||||
.account-container .successfully h1 {
|
||||
color: #3a3a3a !important;
|
||||
}
|
||||
.account-container .next-step {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background-color: var(--second-background-color);
|
||||
}
|
||||
.account-container .next-step .disabled {
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
cursor: initial;
|
||||
pointer-events: none;
|
||||
opacity: 30%;
|
||||
}
|
||||
.account-container .next-step .next-step-title {
|
||||
padding-left: 5vw;
|
||||
padding-top: 5vh;
|
||||
background-color: --light-color;
|
||||
}
|
||||
.account-container .next-step .next-step-title h1, .account-container .next-step .next-step-title h2 {
|
||||
color: --second-color;
|
||||
padding-bottom: 3vh;
|
||||
}
|
||||
.account-container .next-step form {
|
||||
width: 50vw;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
padding-top: 1vh;
|
||||
}
|
||||
.account-container .next-step form input {
|
||||
height: 4vh;
|
||||
width: 60%;
|
||||
margin-bottom: 1vh;
|
||||
border: none;
|
||||
border-bottom: 1px solid var(--border-color);
|
||||
outline: none;
|
||||
}
|
||||
.account-container .next-step form input[type=submit] {
|
||||
width: 50%;
|
||||
border: var(--border-color) solid 1px;
|
||||
}
|
||||
.account-container .next-step form .disabled {
|
||||
opacity: 0%;
|
||||
}
|
||||
.account-container .next-step .flex-container-change-api-container {
|
||||
padding-left: 5vw;
|
||||
}
|
||||
.account-container .next-step .flex-container-change-api-container .change-api-container {
|
||||
color: var(--second-text-color);
|
||||
background-color: var(--main-background-color);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 1vh 3vw;
|
||||
border-radius: 5px;
|
||||
}
|
||||
.account-container .next-step .flex-container-change-api-container .change-api-container .api-preview-container .api-preview {
|
||||
font-weight: bold;
|
||||
}
|
||||
.account-container .next-step .flex-container-change-api-container .change-api-container #change-API-button {
|
||||
height: 4vh;
|
||||
width: 20vw;
|
||||
margin: 1vh 0px;
|
||||
border: none;
|
||||
outline: none;
|
||||
background-color: var(--lightest-color);
|
||||
border: var(--border-color) solid 1px;
|
||||
}
|
||||
|
||||
.loading-container {
|
||||
width: 100%;
|
||||
height: 83vh;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
@media (max-width: 991.98px) {
|
||||
.account-container .next-step {
|
||||
display: flex;
|
||||
}
|
||||
.account-container .next-step .next-step-title h1 {
|
||||
font-size: 15pt;
|
||||
}
|
||||
.account-container .next-step .next-step-title h2 {
|
||||
font-size: 12pt;
|
||||
}
|
||||
.account-container .next-step .flex-container-change-api-container .change-api-container {
|
||||
width: auto;
|
||||
}
|
||||
}/*# sourceMappingURL=config-account-styles.css.map */
|
||||
1
src/pages/ConfigAccount/config-account-styles.css.map
Normal file
1
src/pages/ConfigAccount/config-account-styles.css.map
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"sources":["config-account-styles.scss","config-account-styles.css"],"names":[],"mappings":"AAEI;EACI,iBAAA;EAEA,yBAAA;ACFR;ADIQ;EACI,cAAA;EACA,gBAAA;ACFZ;ADMI;EACI,oCAAA;ACJR;ADMQ;EAAI,yBAAA;ACHZ;ADMI;EAEI,aAAA;EACA,mBAAA;EAEA,gDAAA;ACNR;ADQQ;EACI,yBAAA;KAAA,sBAAA;MAAA,qBAAA;UAAA,iBAAA;EACA,eAAA;EACA,oBAAA;EACA,YAAA;ACNZ;ADSQ;EACI,iBAAA;EAEA,gBAAA;EAEA,+BAAA;ACTZ;ADWY;EACI,qBAAA;EAEA,mBAAA;ACVhB;ADcQ;EACI,WAAA;EAEA,aAAA;EACA,sBAAA;EACA,mBAAA;EAEA,gBAAA;ACdZ;ADiBY;EACI,WAAA;EACA,UAAA;EAEA,kBAAA;EAEA,YAAA;EACA,4CAAA;EACA,aAAA;ACjBhB;ADoBY;EACI,UAAA;EACA,qCAAA;AClBhB;ADsBQ;EACI,WAAA;ACpBZ;ADuBQ;EACI,iBAAA;ACrBZ;ADuBY;EACI,+BAAA;EACA,8CAAA;EAEA,aAAA;EACA,sBAAA;EAEA,gBAAA;EAEA,kBAAA;ACxBhB;AD4BoB;EACI,iBAAA;AC1BxB;AD8BgB;EACI,WAAA;EACA,WAAA;EAEA,eAAA;EAEA,YAAA;EACA,aAAA;EAEA,uCAAA;EACA,qCAAA;AC/BpB;;ADsCA;EACI,WAAA;EACA,YAAA;EAEA,aAAA;EACA,uBAAA;EACA,mBAAA;ACpCJ;;ADwCA;EAIQ;IAEI,aAAA;ECzCV;ED8Cc;IACI,eAAA;EC5ClB;ED+Cc;IACI,eAAA;EC7ClB;EDkDc;IACI,WAAA;EChDlB;AACF","file":"config-account-styles.css"}
|
||||
@@ -1,20 +1,11 @@
|
||||
html, body {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.account-container {
|
||||
|
||||
height: 69vh; //xd
|
||||
|
||||
#message {
|
||||
padding-left: 5vw;
|
||||
|
||||
background-color: #ff6a6a;
|
||||
|
||||
h1 {
|
||||
@include titleFont();
|
||||
@include normalizeTitle();
|
||||
|
||||
color: #ffffff;
|
||||
padding: 2vh 0px;
|
||||
}
|
||||
@@ -28,6 +19,11 @@ html, body {
|
||||
|
||||
.next-step {
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
background-color: var(--second-background-color);
|
||||
|
||||
.disabled {
|
||||
user-select: none;
|
||||
cursor: initial;
|
||||
@@ -40,14 +36,10 @@ html, body {
|
||||
|
||||
padding-top: 5vh;
|
||||
|
||||
background-color: $light-color;
|
||||
background-color: --light-color;
|
||||
|
||||
h1, h2 {
|
||||
|
||||
@include normalizeTitle();
|
||||
@include titleFont();
|
||||
|
||||
color: $second-color;
|
||||
color: --second-color;
|
||||
|
||||
padding-bottom: 3vh;
|
||||
}
|
||||
@@ -70,14 +62,13 @@ html, body {
|
||||
margin-bottom: 1vh;
|
||||
|
||||
border: none;
|
||||
border-bottom: 1px solid $border-color;
|
||||
border-bottom: 1px solid var(--border-color);
|
||||
outline: none;
|
||||
|
||||
}
|
||||
|
||||
input[type=submit] {
|
||||
width: 50%;
|
||||
border: $border-color solid 1px;
|
||||
border: var(--border-color) solid 1px;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -89,26 +80,18 @@ html, body {
|
||||
padding-left: 5vw;
|
||||
|
||||
.change-api-container {
|
||||
width: 50vw;
|
||||
background-color: $lightest-color;
|
||||
color: var(--second-text-color);
|
||||
background-color: var(--main-background-color);
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
padding-top: 1vh;
|
||||
padding: 1vh 3vw;
|
||||
|
||||
border-radius: 2px;
|
||||
|
||||
padding-left: 1vw;
|
||||
border-radius: 5px;
|
||||
|
||||
.api-preview-container {
|
||||
|
||||
|
||||
.title {
|
||||
@include normalizeTitle();
|
||||
@include titleFont();
|
||||
}
|
||||
|
||||
.api-preview {
|
||||
font-weight: bold;
|
||||
}
|
||||
@@ -118,12 +101,13 @@ html, body {
|
||||
height: 4vh;
|
||||
width: 20vw;
|
||||
|
||||
margin-bottom: 1vh;
|
||||
margin: 1vh 0px;
|
||||
|
||||
border: none;
|
||||
outline: none;
|
||||
|
||||
border: $border-color solid 1px;
|
||||
background-color: var(--lightest-color);
|
||||
border: var(--border-color) solid 1px;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -167,47 +151,4 @@ html, body {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.account-container.dark-mode-component {
|
||||
background-color: $second-color-dark;
|
||||
|
||||
.next-step {
|
||||
|
||||
.next-step-title {
|
||||
background-color: $lightest-color-dark;
|
||||
|
||||
h1, h2 {
|
||||
color: #ffffff;
|
||||
|
||||
a {
|
||||
color: $lightest-color;
|
||||
}
|
||||
a:visited {
|
||||
color: $light-color;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
.flex-container-change-api-container {
|
||||
|
||||
.change-api-container {
|
||||
|
||||
background-color: $lightest-color-dark;
|
||||
|
||||
.api-preview-container {
|
||||
|
||||
p {
|
||||
color: rgb(255, 255, 255)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.loading-container.dark-mode-component {
|
||||
background-color: $second-color-dark
|
||||
}
|
||||
@@ -66,9 +66,6 @@ const Credits = (props) => {
|
||||
</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<h4>
|
||||
349
src/pages/Identify/Identify.jsx
Normal file
349
src/pages/Identify/Identify.jsx
Normal file
@@ -0,0 +1,349 @@
|
||||
import './identify-styles.css'
|
||||
|
||||
import React, { useState } from 'react'
|
||||
import { doc, getFirestore, setDoc } from 'firebase/firestore'
|
||||
import { createUserWithEmailAndPassword, getAuth, onAuthStateChanged, sendPasswordResetEmail, signInWithEmailAndPassword, signOut } from 'firebase/auth'
|
||||
import { withRouter } from 'react-router-dom'
|
||||
|
||||
import { firebase } from '../../Firebase/firebase'
|
||||
import Loading from '../../components/Loading/Loading'
|
||||
|
||||
const Identify = (props) => {
|
||||
|
||||
const [act, setAct] = useState('')
|
||||
|
||||
const [email, setEmail] = useState('')
|
||||
const [password, setPassword] = useState('')
|
||||
const [confirmPassword, setConfirmPassword] = useState('')
|
||||
|
||||
const [message, setMessage] = React.useState('')
|
||||
const [errorMessage, setErrorMessage] = React.useState(0)
|
||||
const [successMessage, setSuccessMessage] = React.useState(0)
|
||||
const [loading, setLoading] = useState(false)
|
||||
|
||||
const auth = getAuth()
|
||||
|
||||
const register = async () => {
|
||||
|
||||
onAuthStateChanged(auth, (user) => {
|
||||
if (user) {
|
||||
return
|
||||
}
|
||||
})
|
||||
|
||||
try {
|
||||
const response = await createUserWithEmailAndPassword(auth, email, password)
|
||||
|
||||
|
||||
|
||||
const uid = response.user.uid
|
||||
|
||||
addNewUserToFirebase(uid)
|
||||
props.history.push('/config-account')
|
||||
setLoading(false)
|
||||
|
||||
|
||||
} catch (error) {
|
||||
|
||||
setMessage(error.message)
|
||||
setLoading(false)
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
const addNewUserToFirebase = async (uid) => {
|
||||
try {
|
||||
const db = getFirestore(firebase)
|
||||
await setDoc(doc(db, 'users', uid), {
|
||||
keyClockify: ''
|
||||
})
|
||||
} catch (error) {
|
||||
setMessage(error)
|
||||
}
|
||||
}
|
||||
|
||||
const login = async () => {
|
||||
onAuthStateChanged(auth, (user) => {
|
||||
if (user) {
|
||||
return
|
||||
}
|
||||
})
|
||||
|
||||
try {
|
||||
await signInWithEmailAndPassword(auth, email, password)
|
||||
|
||||
props.history.push('/config-account')
|
||||
|
||||
} catch (error) {
|
||||
setErrorMessage('USER OR PASSWORD NOT VALID')
|
||||
}
|
||||
|
||||
setLoading(false)
|
||||
}
|
||||
|
||||
const resetPasswordFirestore = async () => {
|
||||
|
||||
try {
|
||||
|
||||
await sendPasswordResetEmail(auth, email)
|
||||
|
||||
setSuccessMessage('Recovery email send')
|
||||
setLoading(false)
|
||||
|
||||
} catch (error) {
|
||||
setErrorMessage('There was a problem sending the email.')
|
||||
setLoading(false)
|
||||
}
|
||||
}
|
||||
|
||||
const defineLogin = () => {
|
||||
if (act !== 'login') {
|
||||
setAct('login')
|
||||
}
|
||||
}
|
||||
|
||||
const defineRegister = () => {
|
||||
if (act !== 'register') {
|
||||
setAct('register')
|
||||
}
|
||||
}
|
||||
|
||||
const sendForm = (e) => {
|
||||
e.preventDefault()
|
||||
|
||||
setLoading(true)
|
||||
|
||||
if (!email.trim()) {
|
||||
setErrorMessage('EMAIL EMPTY')
|
||||
setLoading(false)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if (act !== 'i forgor') {
|
||||
|
||||
if (!password.trim()) {
|
||||
setErrorMessage('PASSWORD EMPTY')
|
||||
setLoading(false)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if (password.trim().length < 8) {
|
||||
setErrorMessage('PASSWORD TOO SHORT')
|
||||
setLoading(false)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (act === 'register') {
|
||||
|
||||
if (!confirmPassword.trim()) {
|
||||
setErrorMessage('CONFIRM PASSWORD PLEASE')
|
||||
setLoading(false)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if (password !== confirmPassword) {
|
||||
setErrorMessage("PASSWORDS DOESN'T MATCH")
|
||||
setLoading(false)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
register()
|
||||
|
||||
e.target.reset()
|
||||
setEmail('')
|
||||
setPassword('')
|
||||
setConfirmPassword('')
|
||||
setErrorMessage(0)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if (act === 'login') {
|
||||
|
||||
login()
|
||||
|
||||
e.target.reset()
|
||||
setEmail('')
|
||||
setPassword('')
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if (act === 'i forgor') {
|
||||
|
||||
resetPasswordFirestore()
|
||||
|
||||
e.target.reset()
|
||||
setEmail('')
|
||||
setErrorMessage(0)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
setErrorMessage('ACTION NOT VALID')
|
||||
}
|
||||
|
||||
const signOutFromApp = () => {
|
||||
|
||||
signOut(auth)
|
||||
.then(() => {
|
||||
|
||||
setErrorMessage('YOU CLOSED THE SESSION')
|
||||
//! 'YOU CLOSE SESSION' MESSAGE CODE
|
||||
})
|
||||
}
|
||||
|
||||
React.useEffect( () => {
|
||||
const urlInfo = new URLSearchParams(window.location.search)
|
||||
const action = urlInfo.get('act')
|
||||
|
||||
if (action === 'r') {
|
||||
setAct('register')
|
||||
} else {
|
||||
setAct('login')
|
||||
}
|
||||
|
||||
if (action === 'clss') {
|
||||
signOutFromApp()
|
||||
return
|
||||
}
|
||||
|
||||
onAuthStateChanged(auth, (user) => {
|
||||
if (user) {
|
||||
props.history.push('/')
|
||||
}
|
||||
})
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<>
|
||||
|
||||
{
|
||||
loading ?
|
||||
<Loading />
|
||||
:
|
||||
<div className={props.darkMode ? 'identify-container dark-mode-component' : 'identify-container'}>
|
||||
<div className="error-message-container">
|
||||
{
|
||||
errorMessage ? <p>{errorMessage}</p> : null
|
||||
}
|
||||
</div>
|
||||
<div className="success-message-container">
|
||||
{
|
||||
successMessage ? <p>{successMessage}</p> : null
|
||||
}
|
||||
</div>
|
||||
<div className="identify">
|
||||
<nav className="options-container">
|
||||
<div
|
||||
className={act === 'login' ? 'option active-option': 'option'}
|
||||
onClick={() => {
|
||||
defineLogin()
|
||||
}}
|
||||
>
|
||||
<h2>LOGIN</h2>
|
||||
</div>
|
||||
|
||||
<div
|
||||
className={act === 'register' ? 'option active-option': 'option'}
|
||||
onClick={() => {
|
||||
defineRegister()
|
||||
}}
|
||||
>
|
||||
<h2>REGISTER</h2>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div className="form-container">
|
||||
{
|
||||
act === 'login' ?
|
||||
<form onSubmit={sendForm}>
|
||||
<input
|
||||
type="email"
|
||||
placeholder="Email"
|
||||
onChange= {(e) => {
|
||||
setEmail(e.target.value)
|
||||
}}
|
||||
/>
|
||||
|
||||
<input
|
||||
type="password"
|
||||
placeholder="Password"
|
||||
onChange= { (e) => {
|
||||
setPassword(e.target.value)
|
||||
}}
|
||||
/>
|
||||
<input className="login" type="submit" value="Login"></input>
|
||||
|
||||
<button className="reset-password" onClick={() => setAct('i forgor')}>Reset Password?</button>
|
||||
</form>
|
||||
: null
|
||||
}
|
||||
{
|
||||
act === 'register' ?
|
||||
<form onSubmit={sendForm}>
|
||||
<input
|
||||
type="email"
|
||||
placeholder="Email"
|
||||
onChange={(e) => {
|
||||
setEmail(e.target.value)
|
||||
}}
|
||||
/>
|
||||
|
||||
<input
|
||||
type="password"
|
||||
placeholder="Password"
|
||||
onChange={(e) => {
|
||||
setPassword(e.target.value)
|
||||
}}
|
||||
|
||||
/>
|
||||
|
||||
<input
|
||||
type="password"
|
||||
placeholder="Confirm Password"
|
||||
onChange={(e) => {
|
||||
setConfirmPassword(e.target.value)
|
||||
}}
|
||||
/>
|
||||
|
||||
<input
|
||||
type="submit"
|
||||
value="Register"
|
||||
className="register"
|
||||
/>
|
||||
</form>
|
||||
: null
|
||||
}
|
||||
{
|
||||
act === 'i forgor' ?
|
||||
<form onSubmit={sendForm}>
|
||||
<input
|
||||
type="email"
|
||||
placeholder="Email"
|
||||
onChange= {(e) => {
|
||||
setEmail(e.target.value)
|
||||
}}
|
||||
/>
|
||||
<input type="submit" value="Reset password"></input>
|
||||
<button class="reset-password" onClick={() => setAct('login')}>Back to login</button>
|
||||
</form>
|
||||
: null
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default withRouter(Identify)
|
||||
98
src/pages/Identify/identify-styles.css
Normal file
98
src/pages/Identify/identify-styles.css
Normal file
@@ -0,0 +1,98 @@
|
||||
.identify-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
flex-grow: 1;
|
||||
}
|
||||
.identify-container:has {
|
||||
height: 100%;
|
||||
}
|
||||
.identify-container .error-message-container, .identify-container .success-message-container {
|
||||
width: 70vw;
|
||||
background-color: #D17262;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
.identify-container .error-message-container p, .identify-container .success-message-container p {
|
||||
margin: 2vw;
|
||||
color: #ffffff;
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
font-size: 22pt;
|
||||
}
|
||||
.identify-container .success-message-container {
|
||||
background-color: var(--lightest-color);
|
||||
}
|
||||
.identify-container .success-message-container p {
|
||||
color: #464646;
|
||||
}
|
||||
.identify-container .identify {
|
||||
width: 70vw;
|
||||
}
|
||||
.identify-container .identify .options-container {
|
||||
display: flex;
|
||||
}
|
||||
.identify-container .identify .options-container .option {
|
||||
width: 35vw;
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
padding: 5vh 0px;
|
||||
background-color: var(--second-color);
|
||||
cursor: pointer;
|
||||
transition: 0.4s ease-in-out;
|
||||
filter: brightness(80%);
|
||||
}
|
||||
.identify-container .identify .options-container .option h2 {
|
||||
color: #ffffff;
|
||||
}
|
||||
.identify-container .identify .options-container .active-option {
|
||||
cursor: initial;
|
||||
filter: brightness(100%);
|
||||
}
|
||||
.identify-container .identify .form-container {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
.identify-container .identify .form-container form {
|
||||
width: 50vw;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
padding-top: 1vh;
|
||||
}
|
||||
.identify-container .identify .form-container form input {
|
||||
height: 4vh;
|
||||
width: 60%;
|
||||
margin-bottom: 1vh;
|
||||
border: none;
|
||||
border-bottom: 1px solid var(--border-color);
|
||||
outline: none;
|
||||
background-color: var(--main-background-color);
|
||||
color: var(--second-text-color);
|
||||
}
|
||||
.identify-container .identify .form-container form input.login {
|
||||
background-color: var(--second-background-color);
|
||||
color: var(--second-text-color);
|
||||
}
|
||||
.identify-container .identify .form-container form input.register {
|
||||
background-color: var(--second-background-color);
|
||||
}
|
||||
.identify-container .identify .form-container form input[type=submit] {
|
||||
width: 50%;
|
||||
border: var(--border-color) solid 1px;
|
||||
}
|
||||
|
||||
.reset-password {
|
||||
height: 4vh;
|
||||
width: 60%;
|
||||
margin-bottom: 1vh;
|
||||
border: none;
|
||||
border-bottom: 1px solid var(--border-color);
|
||||
outline: none;
|
||||
width: 50%;
|
||||
border: var(--border-color) solid 1px;
|
||||
background-color: var(--lightest-color-darker);
|
||||
}/*# sourceMappingURL=identify-styles.css.map */
|
||||
1
src/pages/Identify/identify-styles.css.map
Normal file
1
src/pages/Identify/identify-styles.css.map
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"sources":["identify-styles.scss","identify-styles.css"],"names":[],"mappings":"AAAA;EAMI,aAAA;EACA,sBAAA;EACA,mBAAA;EAEA,YAAA;ACLJ;ADHI;EACI,YAAA;ACKR;ADII;EACI,WAAA;EAEA,yBAAA;EAEA,aAAA;EACA,uBAAA;EACA,mBAAA;ACJR;ADMQ;EACI,WAAA;EACA,cAAA;EAEA,yBAAA;KAAA,sBAAA;MAAA,qBAAA;UAAA,iBAAA;EAEA,eAAA;ACNZ;ADYI;EAEI,uCAAA;ACXR;ADaQ;EAEI,cAAA;ACZZ;ADgBI;EACI,WAAA;ACdR;ADgBQ;EACI,aAAA;ACdZ;ADgBY;EACI,WAAA;EAEA,aAAA;EACA,6BAAA;EAEA,gBAAA;EACA,qCAAA;EAEA,eAAA;EAEA,4BAAA;EAEA,uBAAA;ACnBhB;ADqBgB;EACI,cAAA;ACnBpB;ADuBY;EACI,eAAA;EACA,wBAAA;ACrBhB;ADyBQ;EAEI,aAAA;EACA,uBAAA;ACxBZ;AD0BY;EACI,WAAA;EAEA,aAAA;EACA,sBAAA;EACA,mBAAA;EAEA,gBAAA;AC1BhB;AD6BgB;EACI,WAAA;EACA,UAAA;EAEA,kBAAA;EAEA,YAAA;EACA,4CAAA;EACA,aAAA;EAEA,8CAAA;EACA,+BAAA;AC9BpB;ADgCoB;EACI,gDAAA;EACA,+BAAA;AC9BxB;ADiCoB;EACI,gDAAA;AC/BxB;ADmCgB;EACI,UAAA;EACA,qCAAA;ACjCpB;;ADwCA;EACI,WAAA;EACA,UAAA;EAEA,kBAAA;EAEA,YAAA;EACA,4CAAA;EACA,aAAA;EAEA,UAAA;EACA,qCAAA;EACA,8CAAA;ACxCJ","file":"identify-styles.css"}
|
||||
@@ -1,12 +1,9 @@
|
||||
html, body {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.identify-container {
|
||||
|
||||
&:has {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
@@ -26,11 +23,9 @@ html, body {
|
||||
margin: 2vw;
|
||||
color: #ffffff;
|
||||
|
||||
@include titleFont();
|
||||
user-select: none;
|
||||
|
||||
font-size: 22pt;
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -38,7 +33,7 @@ html, body {
|
||||
|
||||
.success-message-container {
|
||||
|
||||
background-color: $lightest-color;
|
||||
background-color: var(--lightest-color);
|
||||
|
||||
p {
|
||||
|
||||
@@ -59,23 +54,22 @@ html, body {
|
||||
justify-content: space-around;
|
||||
|
||||
padding: 5vh 0px;
|
||||
background-color: $second-color;
|
||||
background-color: var(--second-color);
|
||||
|
||||
cursor: pointer;
|
||||
|
||||
transition: 0.4s ease-in-out;
|
||||
|
||||
filter: brightness(80%);
|
||||
|
||||
h2 {
|
||||
@include titleFont();
|
||||
@include normalizeTitle();
|
||||
|
||||
color: #ffffff;
|
||||
}
|
||||
}
|
||||
|
||||
.active-option {
|
||||
cursor: initial;
|
||||
background-color: $second-color-darker;
|
||||
filter: brightness(100%);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -101,33 +95,29 @@ html, body {
|
||||
margin-bottom: 1vh;
|
||||
|
||||
border: none;
|
||||
border-bottom: 1px solid $border-color;
|
||||
border-bottom: 1px solid var(--border-color);
|
||||
outline: none;
|
||||
|
||||
background-color: var(--main-background-color);
|
||||
color: var(--second-text-color);
|
||||
|
||||
&.login {
|
||||
background-color: var(--second-background-color);
|
||||
color: var(--second-text-color);
|
||||
}
|
||||
|
||||
&.register {
|
||||
background-color: var(--second-background-color);
|
||||
}
|
||||
}
|
||||
|
||||
input[type=submit] {
|
||||
width: 50%;
|
||||
border: $border-color solid 1px;
|
||||
border: var(--border-color) solid 1px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
.loading-container {
|
||||
width: 100%;
|
||||
height: 83vh;
|
||||
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
&.dark-mode-component {
|
||||
background-color:$main-color-dark ;
|
||||
}
|
||||
}
|
||||
|
||||
.reset-password {
|
||||
@@ -137,48 +127,10 @@ html, body {
|
||||
margin-bottom: 1vh;
|
||||
|
||||
border: none;
|
||||
border-bottom: 1px solid $border-color;
|
||||
border-bottom: 1px solid var(--border-color);
|
||||
outline: none;
|
||||
|
||||
width: 50%;
|
||||
border: $border-color solid 1px;
|
||||
background-color: $main-color;
|
||||
|
||||
}
|
||||
|
||||
.identify-container.dark-mode-component {
|
||||
|
||||
background-color: $second-color-dark;
|
||||
|
||||
.identify {
|
||||
|
||||
.options-container {
|
||||
|
||||
.option {
|
||||
background-color: $light-color-dark;
|
||||
}
|
||||
|
||||
.active-option{
|
||||
background-color: $light-color-dark-darker;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.form-container {
|
||||
|
||||
form {
|
||||
|
||||
input {
|
||||
|
||||
color: white;
|
||||
|
||||
background: none;
|
||||
}
|
||||
|
||||
input[type=submit] {
|
||||
background-color: $main-color-dark;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
border: var(--border-color) solid 1px;
|
||||
background-color: var(--lightest-color-darker);
|
||||
}
|
||||
206
src/pages/Main/ClockifyTaskForm/ClockifyTaskForm.jsx
Normal file
206
src/pages/Main/ClockifyTaskForm/ClockifyTaskForm.jsx
Normal file
@@ -0,0 +1,206 @@
|
||||
import './clockify-task-form.css'
|
||||
|
||||
import React, { useState } from 'react';
|
||||
import { getAuth, onAuthStateChanged } from "firebase/auth";
|
||||
import { doc, getDoc, getFirestore } from "firebase/firestore";
|
||||
|
||||
import { firebase } from '../../../Firebase/firebase';
|
||||
import Loading from "../../../components/Loading/Loading";
|
||||
|
||||
const ClockifyTaskForm = ({timerOn, setTimerOn, signedIn, apiKey, setApiKey, taskName, setTaskName, workspaceID, setWorkspaceID, projectID, setProjectID, darkMode}) => {
|
||||
|
||||
const auth = getAuth()
|
||||
|
||||
const [userUID, setUserUID] = useState('')
|
||||
|
||||
const [workspaces, setWorkspaces] = useState([])
|
||||
const [workspacesReady, setWorkspacesReady] = useState(false)
|
||||
|
||||
const [projects, setProjects] = useState([])
|
||||
const [projectsDone, setProjectsDone] = useState(false)
|
||||
|
||||
const [loading, setLoading] = useState(true)
|
||||
|
||||
async function getApiKey() {
|
||||
|
||||
try {
|
||||
|
||||
const db = getFirestore(firebase)
|
||||
|
||||
const reference = doc(db, 'users', userUID)
|
||||
|
||||
const dataSnap = await getDoc(reference)
|
||||
const result = dataSnap.data()
|
||||
|
||||
if (result.keyClockify) {
|
||||
|
||||
await generateArrayOfWorkspaces(result.keyClockify)
|
||||
}
|
||||
|
||||
|
||||
} catch (error) {
|
||||
}
|
||||
|
||||
setLoading(false)
|
||||
}
|
||||
|
||||
React.useEffect(() => {
|
||||
|
||||
if (signedIn) {
|
||||
|
||||
onAuthStateChanged(auth, async (user) => {
|
||||
|
||||
if (user) {
|
||||
|
||||
setUserUID(user.uid)
|
||||
|
||||
if (user.uid) {
|
||||
await getApiKey()
|
||||
setLoading(false)
|
||||
}
|
||||
} else {
|
||||
return (<></>)
|
||||
}
|
||||
|
||||
})
|
||||
} else {
|
||||
setLoading(false)
|
||||
}
|
||||
|
||||
}, [signedIn, getApiKey])
|
||||
|
||||
async function makeRequestWorkspaces(apiClockify) {
|
||||
try {
|
||||
const request = {
|
||||
method: "GET",
|
||||
headers: {
|
||||
'X-Api-Key': apiClockify,
|
||||
"content-type": "application/json"
|
||||
}
|
||||
}
|
||||
const response = await fetch(`https://api.clockify.me/api/v1/workspaces/`, request)
|
||||
const data = await response.json()
|
||||
|
||||
setApiKey(apiClockify)
|
||||
|
||||
return await data
|
||||
|
||||
} catch (error) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
async function generateArrayOfWorkspaces(key) {
|
||||
|
||||
const data = await makeRequestWorkspaces(key)
|
||||
|
||||
if (data.code !== 1000) {
|
||||
let workspacesCopy = []
|
||||
|
||||
await data.forEach(workspace => {
|
||||
workspacesCopy.push(workspace)
|
||||
});
|
||||
|
||||
setWorkspaces(workspacesCopy)
|
||||
|
||||
setWorkspacesReady(true)
|
||||
setLoading(false)
|
||||
}
|
||||
}
|
||||
|
||||
async function requestProjects(e) {
|
||||
|
||||
try {
|
||||
const request = {
|
||||
method: "GET",
|
||||
headers: {
|
||||
'X-Api-Key': apiKey,
|
||||
"content-type": "application/json"
|
||||
}
|
||||
}
|
||||
const response = await fetch(`https://api.clockify.me/api/v1/workspaces/${e}/projects`, request)
|
||||
const data = response.json()
|
||||
|
||||
return data
|
||||
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
const defineProjects = async (e) => {
|
||||
|
||||
if (e === 0) {
|
||||
setProjectsDone(false)
|
||||
setProjects([])
|
||||
|
||||
}
|
||||
setWorkspaceID(e)
|
||||
|
||||
const data = await requestProjects(e)
|
||||
setProjects(data)
|
||||
setProjectsDone(true)
|
||||
}
|
||||
|
||||
const selectProject = (e) => {
|
||||
|
||||
setProjectID(e)
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
{
|
||||
loading ?
|
||||
<Loading />
|
||||
:
|
||||
<div className={darkMode ? 'clockify-task-form-container dark-mode-container' : 'clockify-tasks-display-container'}>
|
||||
{
|
||||
userUID ?
|
||||
<div className={`clockify-task-form ${timerOn || !workspacesReady ? "disabled" : ""}`}>
|
||||
<select onChange={(e) => {defineProjects(e.target.value)}} className='workspace-selector'>
|
||||
<option value="0">Select a Workspace</option>
|
||||
{
|
||||
workspacesReady ?
|
||||
workspaces.map( (workspace) => {
|
||||
return <option value={workspace.id} key={workspace.id}>{workspace.name}</option>
|
||||
})
|
||||
: null
|
||||
}
|
||||
</select>
|
||||
<select onChange={(e) => {selectProject(e.target.value)}} className={workspaceID !== 0 ? 'project-selector' : 'project-selector disabled'}>
|
||||
<option value="0">Select a Project</option>
|
||||
{
|
||||
projectsDone && projects.length !== 0 ?
|
||||
projects.map((project) => (
|
||||
!project.archived ?
|
||||
<option value={project.id} key={project.id}>{project.name}</option>
|
||||
: null
|
||||
))
|
||||
: null
|
||||
}
|
||||
</select>
|
||||
<input
|
||||
type="text"
|
||||
onChange={(e) => {setTaskName(e.target.value)}}
|
||||
value={taskName}
|
||||
placeholder="Add task description"
|
||||
className={projectID !== 0 ? null: 'disabled'}
|
||||
|
||||
onKeyPress={event => {
|
||||
|
||||
if (event.key === 'Enter') {
|
||||
|
||||
setTimerOn(true)
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
: null
|
||||
}
|
||||
</div>
|
||||
}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default ClockifyTaskForm
|
||||
91
src/pages/Main/ClockifyTaskForm/clockify-task-form.css
Normal file
91
src/pages/Main/ClockifyTaskForm/clockify-task-form.css
Normal file
@@ -0,0 +1,91 @@
|
||||
.clockify-task-form {
|
||||
width: 20vw;
|
||||
position: absolute;
|
||||
top: 60vh;
|
||||
left: 2.5vw;
|
||||
}
|
||||
.clockify-task-form.loading-container {
|
||||
width: 20vw;
|
||||
height: auto;
|
||||
background: none;
|
||||
}
|
||||
.clockify-task-form.disabled {
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
cursor: initial;
|
||||
pointer-events: none;
|
||||
opacity: 30%;
|
||||
}
|
||||
.clockify-task-form .workspace-selector, .clockify-task-form .project-selector {
|
||||
width: 15vw;
|
||||
height: 3vw;
|
||||
}
|
||||
.clockify-task-form .workspace-selector.disabled, .clockify-task-form .project-selector.disabled {
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
cursor: initial;
|
||||
pointer-events: none;
|
||||
opacity: 30%;
|
||||
}
|
||||
.clockify-task-form select {
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
.clockify-task-form input[type=text] {
|
||||
width: 15vw;
|
||||
height: 3vw;
|
||||
font-size: 12pt;
|
||||
outline: none;
|
||||
padding: 1px 2px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.clockify-task-form input[type=text].disabled {
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
cursor: initial;
|
||||
pointer-events: none;
|
||||
opacity: 30%;
|
||||
}
|
||||
|
||||
@media (max-width: 991.98px) {
|
||||
.clockify-tasks-display {
|
||||
position: initial;
|
||||
width: auto;
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
padding: 3vh 5vw;
|
||||
}
|
||||
.clockify-tasks-display.loading-container {
|
||||
width: 90%;
|
||||
height: auto;
|
||||
}
|
||||
.clockify-tasks-display .workspace-selector, .clockify-tasks-display .project-selector, .clockify-tasks-display input[type=text] {
|
||||
width: 20vw;
|
||||
height: 5vw;
|
||||
}
|
||||
}
|
||||
@media (max-width: 576px) {
|
||||
.clockify-tasks-display {
|
||||
position: initial;
|
||||
width: auto;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
.clockify-tasks-display.loading-container {
|
||||
width: 90%;
|
||||
height: auto;
|
||||
}
|
||||
.clockify-tasks-display .workspace-selector, .clockify-tasks-display .project-selector, .clockify-tasks-display input[type=text] {
|
||||
width: 70%;
|
||||
height: 4vh;
|
||||
margin-top: 1vh;
|
||||
}
|
||||
}/*# sourceMappingURL=clockify-task-form.css.map */
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"sources":["clockify-task-form.scss","clockify-task-form.css"],"names":[],"mappings":"AAAA;EAEI,WAAA;EACA,kBAAA;EAEA,SAAA;EACA,WAAA;ACDJ;ADGI;EACI,WAAA;EACA,YAAA;EACA,gBAAA;ACDR;ADII;EACI,yBAAA;KAAA,sBAAA;MAAA,qBAAA;UAAA,iBAAA;EACA,eAAA;EACA,oBAAA;EACA,YAAA;ACFR;ADKI;EACI,WAAA;EACA,WAAA;ACHR;ADKQ;EACI,yBAAA;KAAA,sBAAA;MAAA,qBAAA;UAAA,iBAAA;EACA,eAAA;EACA,oBAAA;EACA,YAAA;ACHZ;ADOI;EACI,gBAAA;EACA,mBAAA;EACA,uBAAA;ACLR;ADQI;EACI,WAAA;EACA,WAAA;EAEA,eAAA;EAEA,aAAA;EACA,gBAAA;EAEA,sBAAA;ACTR;ADWQ;EACI,yBAAA;KAAA,sBAAA;MAAA,qBAAA;UAAA,iBAAA;EACA,eAAA;EACA,oBAAA;EACA,YAAA;ACTZ;;ADcA;EAEI;IACI,iBAAA;IACA,WAAA;IAEA,aAAA;IACA,6BAAA;IAEA,gBAAA;ECdN;EDgBM;IACI,UAAA;IACA,YAAA;ECdV;EDiBM;IACI,WAAA;IACA,WAAA;ECfV;AACF;ADoBA;EAEI;IACI,iBAAA;IACA,WAAA;IAEA,aAAA;IACA,sBAAA;IACA,mBAAA;ECpBN;EDsBM;IACI,UAAA;IACA,YAAA;ECpBV;EDuBM;IACI,UAAA;IACA,WAAA;IACA,eAAA;ECrBV;AACF","file":"clockify-task-form.css"}
|
||||
@@ -1,4 +1,4 @@
|
||||
.clockify-tasks-display {
|
||||
.clockify-task-form {
|
||||
|
||||
width: 20vw;
|
||||
position: absolute;
|
||||
@@ -40,8 +40,6 @@
|
||||
input[type=text] {
|
||||
width: 15vw;
|
||||
height: 3vw;
|
||||
|
||||
@include bodyFont();
|
||||
|
||||
font-size: 12pt;
|
||||
|
||||
@@ -104,11 +102,4 @@
|
||||
margin-top: 1vh;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.clockify-tasks-display-container.dark-mode-container {
|
||||
|
||||
background-color: $second-color-dark;
|
||||
|
||||
|
||||
}
|
||||
69
src/pages/Main/Main.jsx
Normal file
69
src/pages/Main/Main.jsx
Normal file
@@ -0,0 +1,69 @@
|
||||
import React, { useState } from 'react'
|
||||
import GoDownArrow from '../../components/GoDownArrow/GoDownArrow'
|
||||
import ClockifyTaskForm from './ClockifyTaskForm/ClockifyTaskForm'
|
||||
import Pomodoro from './Pomodoro/Pomodoro'
|
||||
|
||||
const Main = ({signedIn, darkMode, setKonamiCodeActive, KonamiCodeActive, notificationPermission}) => {
|
||||
|
||||
const [timerOn, setTimerOn] = useState(false)
|
||||
const [apiKey, setApiKey] = useState('')
|
||||
const [taskName, setTaskName] = useState('')
|
||||
|
||||
const [workspaceID, setWorkspaceID] = useState(0)
|
||||
const [projectID, setProjectID] = useState(0)
|
||||
|
||||
return (
|
||||
<>
|
||||
<ClockifyTaskForm
|
||||
|
||||
timerOn={timerOn}
|
||||
setTimerOn={setTimerOn}
|
||||
|
||||
signedIn={signedIn}
|
||||
|
||||
apiKey={apiKey}
|
||||
setApiKey={setApiKey}
|
||||
|
||||
taskName={taskName}
|
||||
setTaskName={setTaskName}
|
||||
|
||||
workspaceID={workspaceID}
|
||||
setWorkspaceID={setWorkspaceID}
|
||||
|
||||
projectID={projectID}
|
||||
setProjectID={setProjectID}
|
||||
|
||||
darkMode={darkMode}
|
||||
/>
|
||||
<Pomodoro
|
||||
signedIn={signedIn}
|
||||
timerOn={timerOn}
|
||||
setTimerOn={setTimerOn}
|
||||
|
||||
apiKey={apiKey}
|
||||
|
||||
taskName={taskName}
|
||||
setTaskName={setTaskName}
|
||||
|
||||
workspaceID={workspaceID}
|
||||
setWorkspaceID={setWorkspaceID}
|
||||
|
||||
projectID={projectID}
|
||||
setProjectID={setProjectID}
|
||||
|
||||
darkMode={darkMode}
|
||||
|
||||
setKonamiCodeActive = {setKonamiCodeActive}
|
||||
KonamiCodeActive= {KonamiCodeActive}
|
||||
|
||||
notificationPermission={notificationPermission}
|
||||
/>
|
||||
<GoDownArrow
|
||||
direction={'about-this'}
|
||||
darkMode={darkMode}
|
||||
/>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default Main
|
||||
152
src/pages/Main/Pomodoro/Pomodoro.jsx
Normal file
152
src/pages/Main/Pomodoro/Pomodoro.jsx
Normal file
@@ -0,0 +1,152 @@
|
||||
import './pomodoro-styles.css'
|
||||
|
||||
import React, {useState} from 'react'
|
||||
|
||||
import PomodoroTimer from './PomodoroTimer/PomodoroTimer'
|
||||
import StyleSelector from './StyleSelector/StyleSelector'
|
||||
|
||||
const Pomodoro = (props) => {
|
||||
|
||||
const [style, setStyle] = useState({title: "Regular", times: [25, 5, 15]}) //Regular time set
|
||||
const [displayHidden, setDisplayHidden] = useState(true)
|
||||
|
||||
const [stats, setStats] = useState({pomodoros: 0, rests: 0, longRests: 0})
|
||||
|
||||
const [startTime, setStartTime] = useState('')
|
||||
const [endTime, setEndTime] = useState('')
|
||||
|
||||
const [letsUpload, setLetsUpload] = useState(false)
|
||||
|
||||
|
||||
const showStyles = () => {
|
||||
setDisplayHidden(!displayHidden)
|
||||
}
|
||||
|
||||
React.useEffect( () => {
|
||||
if (letsUpload) {
|
||||
|
||||
async function uploadToClockifyTimer() {
|
||||
|
||||
if (!props.workspaceID && !props.projectID) {
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
const url = `https://api.clockify.me/api/v1/workspaces/${props.workspaceID}/time-entries`
|
||||
|
||||
const body = {
|
||||
start: startTime,
|
||||
end: endTime,
|
||||
projectId: props.projectID,
|
||||
description: props.taskName
|
||||
}
|
||||
|
||||
const headers = {
|
||||
'X-Api-Key': props.apiKey,
|
||||
'Content-type' : 'application/json; charset=UTF-8'
|
||||
}
|
||||
|
||||
const request = {
|
||||
method: 'POST',
|
||||
body: JSON.stringify(body),
|
||||
headers
|
||||
}
|
||||
|
||||
await fetch(url, request)
|
||||
|
||||
} catch (error) {
|
||||
}
|
||||
}
|
||||
|
||||
uploadToClockifyTimer()
|
||||
|
||||
setLetsUpload(false)
|
||||
|
||||
setStartTime('')
|
||||
setEndTime('')
|
||||
}
|
||||
})
|
||||
|
||||
return (
|
||||
<div className={props.darkMode ? 'main-pomodoro-container dark-mode-component' : 'main-pomodoro-container'}>
|
||||
<div className="main-pomodoro">
|
||||
|
||||
<PomodoroTimer
|
||||
style={style}
|
||||
|
||||
timerOn={props.timerOn}
|
||||
setTimerOn={props.setTimerOn}
|
||||
|
||||
stats={stats}
|
||||
setStats={setStats}
|
||||
|
||||
workspaceID={props.workspaceID}
|
||||
setWorkspaceID={props.setWorkspaceID}
|
||||
|
||||
projectID={props.projectID}
|
||||
setProjectID={props.setProjectID}
|
||||
|
||||
apiKey={props.apiKey}
|
||||
|
||||
startTime={startTime}
|
||||
setStartTime={setStartTime}
|
||||
|
||||
endtime={endTime}
|
||||
setEndTime={setEndTime}
|
||||
|
||||
setLetsUpload={setLetsUpload}
|
||||
|
||||
setKonamiCodeActive={props.setKonamiCodeActive}
|
||||
KonamiCodeActive= {props.KonamiCodeActive}
|
||||
|
||||
notificationPermission={props.notificationPermission}
|
||||
/>
|
||||
|
||||
|
||||
<div className="style-display">
|
||||
<h4>
|
||||
Style
|
||||
</h4>
|
||||
<h3 onClick={showStyles}>
|
||||
{style.title}
|
||||
</h3>
|
||||
</div>
|
||||
|
||||
<button className="start-pomodoro" onClick={() => props.setTimerOn(!props.timerOn)}>{
|
||||
props.timerOn ? 'STOP' : 'START'
|
||||
|
||||
}</button>
|
||||
</div>
|
||||
|
||||
<StyleSelector
|
||||
displayHidden={displayHidden}
|
||||
|
||||
style={style}
|
||||
setStyle={setStyle}
|
||||
|
||||
darkMode={props.darkMode}
|
||||
/>
|
||||
|
||||
<div className={props.darkMode ? 'pomodoro-counter dark-mode-component': 'pomodoro-counter'}>
|
||||
<ul>
|
||||
{
|
||||
Object.keys(stats).map(stat => {
|
||||
//camelCase to Natural Case
|
||||
const text = stat.replace(/([A-Z])/g, " $1")
|
||||
const result = text.charAt(0).toUpperCase() + text.slice(1);
|
||||
//Credits: https://stackoverflow.com/a/7225450/18740899
|
||||
|
||||
return (
|
||||
<li key={stat}>
|
||||
<span className="quantity">{stats[stat]}</span><span className="separator"> - </span>{result}
|
||||
</li>
|
||||
)
|
||||
})
|
||||
}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default Pomodoro
|
||||
@@ -1,15 +1,13 @@
|
||||
import React, {useState} from 'react'
|
||||
|
||||
import uploadToClockifyTimer from '../Clockify/uploadToClockifyTimer'
|
||||
import getAndFormatCurrentTime from '../Clockify/getAndFormatCurrentTime'
|
||||
import randomText from '../Misc/randomText'
|
||||
import detectKeys from '../Misc/detectKeys'
|
||||
import getAndFormatCurrentTime from './getAndFormatCurrentTime'
|
||||
import randomText from './randomText'
|
||||
import detectKeys from './detectKeys'
|
||||
|
||||
import bell_x2 from '../sounds/bell-x2.mp3'
|
||||
import bell_x3 from '../sounds/bell-x3.mp3'
|
||||
import setTimeStyleExternal from './MainPomodoroTimer Children/setTimeStyle'
|
||||
import bell_x2 from '../../../../sounds/bell-x2.mp3'
|
||||
import bell_x3 from '../../../../sounds/bell-x3.mp3'
|
||||
|
||||
const MainPomodoroTimer = (props) => {
|
||||
const PomodoroTimer = (props) => {
|
||||
|
||||
const [minutes, setMinutes] = useState(25)
|
||||
const [seconds, setSeconds] = useState(0)
|
||||
@@ -21,7 +19,7 @@ const MainPomodoroTimer = (props) => {
|
||||
|
||||
const [timerActivity, setTimerActivity] = useState(false)
|
||||
|
||||
const [actualStyle, setActualStyle] = useState('')
|
||||
const [actualStyle, setActualStyle] = useState({title: "", times: []})
|
||||
|
||||
const [alreadyCountingStart, setAlreadyCountingStart] = useState(false) /* TOO MUCH FUCKING STATES https://pbs.twimg.com/media/EoM2rXuW8AMRxZh?format=png&name=large*/
|
||||
const [alreadyCountingEnd, setAlreadyCountingEnd] = useState(false)
|
||||
@@ -30,13 +28,29 @@ const MainPomodoroTimer = (props) => {
|
||||
|
||||
const [velocity, setVelocity] = useState(1)
|
||||
|
||||
const setTimeStyle = () => setTimeStyleExternal(props, setMinutes, setSeconds, setBreakTime, setActualStyle, breakTime)
|
||||
function setPomodoroTime() {
|
||||
setMinutes(props.style.times[0])
|
||||
setSeconds(0)
|
||||
|
||||
React.useEffect (() => {
|
||||
setBreakTime(
|
||||
{
|
||||
normal: {
|
||||
minutes: props.style.times[1],
|
||||
seconds: 0
|
||||
},
|
||||
extended: {
|
||||
minutes: props.style.times[2],
|
||||
seconds: 0
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
if (actualStyle !== props.style) {
|
||||
setTimeStyle()
|
||||
setActualStyle(props.style)
|
||||
}
|
||||
|
||||
React.useEffect(() => {
|
||||
if (actualStyle.title !== props.style.title) {
|
||||
setPomodoroTime()
|
||||
}
|
||||
|
||||
if (controlKonamiCode) {
|
||||
@@ -45,7 +59,7 @@ const MainPomodoroTimer = (props) => {
|
||||
|
||||
setControlKonamiCode(false)
|
||||
}
|
||||
})
|
||||
}, [props.style])
|
||||
|
||||
const startTimer = () => {
|
||||
|
||||
@@ -101,44 +115,20 @@ const MainPomodoroTimer = (props) => {
|
||||
if (!counter) {
|
||||
console.error('NOT PARAMETER PASSED')
|
||||
}
|
||||
|
||||
if (counter === "Pomodoros") {
|
||||
props.setPomodoros(props.pomodoros + 1)
|
||||
return
|
||||
}
|
||||
|
||||
if (counter === "Rest") {
|
||||
props.setRests(props.rests + 1)
|
||||
return
|
||||
}
|
||||
|
||||
if (counter === "Long Rest") {
|
||||
props.setLongRests(props.longRests + 1)
|
||||
return
|
||||
}
|
||||
|
||||
if (counter) {
|
||||
console.error('PARAMETER NOT VALID');
|
||||
}
|
||||
//Get propiertys of stats obj
|
||||
Object.keys(props.stats).forEach(stat => {
|
||||
if (counter === stat) {
|
||||
const statsCopy = {...props.stats}
|
||||
statsCopy[stat] = props.stats[stat] + 1
|
||||
|
||||
props.setStats(statsCopy)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/*React.useEffect( () => {
|
||||
|
||||
if (props.timerOn) {
|
||||
getAndFormatCurrentTime()
|
||||
}
|
||||
|
||||
if (!props.timerOn){
|
||||
getAndFormatCurrentTime()
|
||||
//uploadToClockifyTimer( props.workspaceID, props.projectID, '2021-10-02T13:00:14Z', '2021-10-02T15:00:14Z', props.apiKey)
|
||||
}
|
||||
|
||||
})*/
|
||||
|
||||
const getFavicon = () => {
|
||||
|
||||
return document.getElementById('favicon')
|
||||
|
||||
}
|
||||
|
||||
React.useEffect ( () => {
|
||||
@@ -175,23 +165,21 @@ const MainPomodoroTimer = (props) => {
|
||||
|
||||
if (restCounter !== 3){
|
||||
|
||||
setPomodoroCounter('Pomodoros')
|
||||
setPomodoroCounter('pomodoros')
|
||||
|
||||
setRestCounter((restCounter + 1))
|
||||
|
||||
setBreak(1, 0)
|
||||
setWeAreInBreakTime(true)
|
||||
|
||||
|
||||
}
|
||||
|
||||
if (restCounter === 3) {
|
||||
|
||||
setPomodoroCounter('Pomodoros')
|
||||
setPomodoroCounter('pomodoros')
|
||||
setRestCounter((restCounter + 1))
|
||||
|
||||
setBreak(0, 1)
|
||||
setWeAreInBreakTime(true)
|
||||
setWeAreInBreakTime(true)
|
||||
}
|
||||
|
||||
if (!alreadyCountingEnd) {
|
||||
@@ -208,7 +196,6 @@ const MainPomodoroTimer = (props) => {
|
||||
}
|
||||
|
||||
if (minutes >= 0 || seconds > 0) {
|
||||
|
||||
idTimeOut = startTimer()
|
||||
}
|
||||
}
|
||||
@@ -231,18 +218,17 @@ const MainPomodoroTimer = (props) => {
|
||||
}
|
||||
|
||||
if (restCounter === 4) {
|
||||
setPomodoroCounter('Long Rest')
|
||||
setPomodoroCounter('longRests')
|
||||
setRestCounter(0)
|
||||
|
||||
} else {
|
||||
setPomodoroCounter('Rest')
|
||||
setPomodoroCounter('rests')
|
||||
}
|
||||
|
||||
setWeAreInBreakTime(false)
|
||||
props.setTimerOn(false)
|
||||
|
||||
setTimeStyle()
|
||||
|
||||
setPomodoroTime()
|
||||
}, 1000)
|
||||
}
|
||||
|
||||
@@ -253,25 +239,18 @@ const MainPomodoroTimer = (props) => {
|
||||
}
|
||||
}
|
||||
|
||||
return () => {
|
||||
clearInterval(idTimeOut)
|
||||
}
|
||||
|
||||
return () => { clearInterval(idTimeOut) }
|
||||
}
|
||||
|
||||
if (!props.timerOn) {
|
||||
|
||||
document.title = 'Clockify Pomodoro Timer'
|
||||
|
||||
getFavicon().href = './img/favicon.ico'
|
||||
|
||||
if ( timerActivity === true) {
|
||||
|
||||
if (!weAreInBreakTime) {
|
||||
|
||||
if (restCounter !== 3){
|
||||
|
||||
setPomodoroCounter('Pomodoros')
|
||||
setPomodoroCounter('pomodoros')
|
||||
setRestCounter((restCounter + 1))
|
||||
|
||||
if (!alreadyCountingEnd) {
|
||||
@@ -288,12 +267,11 @@ const MainPomodoroTimer = (props) => {
|
||||
setWeAreInBreakTime(true)
|
||||
}, 10)
|
||||
}
|
||||
|
||||
if (restCounter === 3) {
|
||||
|
||||
setTimeout(() => {
|
||||
|
||||
setPomodoroCounter('Pomodoros')
|
||||
setPomodoroCounter('pomodoros')
|
||||
setRestCounter((restCounter + 1))
|
||||
|
||||
setBreak(0, 1)
|
||||
@@ -319,21 +297,19 @@ const MainPomodoroTimer = (props) => {
|
||||
if (weAreInBreakTime) {
|
||||
|
||||
if (restCounter === 4) {
|
||||
|
||||
|
||||
setPomodoroCounter('Long Rest')
|
||||
setPomodoroCounter('longRests')
|
||||
setRestCounter(0)
|
||||
|
||||
} else {
|
||||
|
||||
setPomodoroCounter('Rest')
|
||||
setPomodoroCounter('rests')
|
||||
}
|
||||
|
||||
setWeAreInBreakTime(false)
|
||||
}
|
||||
|
||||
setTimerActivity(false)
|
||||
setTimeStyle()
|
||||
setPomodoroTime()
|
||||
}
|
||||
|
||||
setAlreadyCountingStart(false)
|
||||
@@ -346,7 +322,7 @@ const MainPomodoroTimer = (props) => {
|
||||
|
||||
if (minutes < 10) {
|
||||
return '0' + minutes
|
||||
}
|
||||
}
|
||||
else {
|
||||
return minutes
|
||||
}
|
||||
@@ -356,7 +332,7 @@ const MainPomodoroTimer = (props) => {
|
||||
|
||||
if (seconds < 10) {
|
||||
return '0' + seconds
|
||||
}
|
||||
}
|
||||
else {
|
||||
return seconds
|
||||
}
|
||||
@@ -394,4 +370,4 @@ const MainPomodoroTimer = (props) => {
|
||||
)
|
||||
}
|
||||
|
||||
export default MainPomodoroTimer
|
||||
export default PomodoroTimer
|
||||
75
src/pages/Main/Pomodoro/StyleSelector/StyleSelector.jsx
Normal file
75
src/pages/Main/Pomodoro/StyleSelector/StyleSelector.jsx
Normal file
@@ -0,0 +1,75 @@
|
||||
import './style-selector.css'
|
||||
|
||||
import React from 'react'
|
||||
|
||||
const StyleSelector = (props) => {
|
||||
|
||||
const data = [
|
||||
{
|
||||
title: "Can I play, Daddy?",
|
||||
times: [10, 5, 15]
|
||||
},
|
||||
{
|
||||
title: "Regular",
|
||||
times: [25, 5, 15]
|
||||
},
|
||||
{
|
||||
title: "Creative work",
|
||||
times: [50, 10, 20]
|
||||
},
|
||||
{
|
||||
title: "Last minute delivery",
|
||||
times: [90, 15, 30]
|
||||
}
|
||||
]
|
||||
|
||||
return (
|
||||
<div className={props.darkMode ? 'style-selector-container dark-mode-component' : 'style-selector-container'}>
|
||||
<div className={`style-selector ${props.displayHidden ? 'style-selector-hidden': 'style-selector-show'}`} >
|
||||
<h2>Select Style</h2>
|
||||
|
||||
<div className="style-selection-container">
|
||||
{
|
||||
data.map((obj, index) => (
|
||||
<div
|
||||
key={obj.title}
|
||||
className="style-container"
|
||||
>
|
||||
<span class="checkbox__input"
|
||||
onClick = { (e) => {
|
||||
props.setStyle(obj)
|
||||
}}
|
||||
>
|
||||
<input
|
||||
id={`input-${index}`}
|
||||
type="checkbox"
|
||||
checked={ props.style.title === obj.title ? true : false}
|
||||
/>
|
||||
<span className="checkbox_control"></span>
|
||||
</span>
|
||||
<label for={`input-${index}`} onClick = { (e) => {
|
||||
props.setStyle(obj)
|
||||
}}
|
||||
>
|
||||
<span className="title">{obj.title}</span>
|
||||
<span className="times">
|
||||
{
|
||||
obj.times.map((subObj, index) => (
|
||||
index !== obj.times.length - 1 ?
|
||||
`${subObj} min. | `
|
||||
:
|
||||
`${subObj} min.`
|
||||
))
|
||||
}
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
))
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default StyleSelector
|
||||
112
src/pages/Main/Pomodoro/StyleSelector/style-selector.css
Normal file
112
src/pages/Main/Pomodoro/StyleSelector/style-selector.css
Normal file
@@ -0,0 +1,112 @@
|
||||
.style-selector {
|
||||
width: calc(20vw - 1px);
|
||||
padding-left: 3vw;
|
||||
padding-bottom: 12vh;
|
||||
position: absolute;
|
||||
top: 29vh;
|
||||
left: 75vw;
|
||||
box-shadow: 1px 6px 15px rgba(0, 0, 0, 0.1254901961);
|
||||
z-index: 50;
|
||||
transition: 0.2s ease-in-out;
|
||||
}
|
||||
.style-selector h2 {
|
||||
color: var(--main-text-color);
|
||||
font-size: 30pt;
|
||||
text-align: center;
|
||||
margin-left: -3vw;
|
||||
margin-top: 1vh;
|
||||
margin-bottom: 3vh;
|
||||
}
|
||||
.style-selector .style-selection-container .style-container {
|
||||
display: flex;
|
||||
height: 10vh;
|
||||
align-items: center;
|
||||
}
|
||||
.style-selector .style-selection-container .style-container label {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
color: var(--second-text-color);
|
||||
}
|
||||
.style-selector .style-selection-container .style-container label .title {
|
||||
font-size: 13pt;
|
||||
}
|
||||
.style-selector .style-selection-container .style-container label .times {
|
||||
color: var(--third-text-color);
|
||||
font-size: 13pt;
|
||||
}
|
||||
.style-selector .style-selection-container input {
|
||||
width: 65px;
|
||||
opacity: 0;
|
||||
}
|
||||
.style-selector .style-selection-container .checkbox__input {
|
||||
display: grid;
|
||||
grid-template-areas: "checkbox";
|
||||
}
|
||||
.style-selector .style-selection-container .checkbox__input > * {
|
||||
grid-area: checkbox;
|
||||
}
|
||||
.style-selector .style-selection-container .checkbox_control {
|
||||
display: inline-grid;
|
||||
width: 45px;
|
||||
height: 45px;
|
||||
border: 3px solid var(--main-text-color);
|
||||
border-radius: 0.25em;
|
||||
border-radius: 100%;
|
||||
transition: ease-in-out 0.2s;
|
||||
}
|
||||
.style-selector .style-selection-container .checkbox__input input:checked + .checkbox_control {
|
||||
background-color: var(--lightest-color);
|
||||
}
|
||||
|
||||
.style-selector-show {
|
||||
opacity: 100%;
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
||||
.style-selector-hidden {
|
||||
opacity: 0%;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
@media (max-width: 991.98px) {
|
||||
.style-selector {
|
||||
position: initial;
|
||||
margin: 0 0 5% 0;
|
||||
width: 100%;
|
||||
padding: 0;
|
||||
padding: 0px 5vw;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.style-selector h2 {
|
||||
text-align: start;
|
||||
margin-left: 0;
|
||||
}
|
||||
.style-selector .style-selection-container {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
width: 100%;
|
||||
}
|
||||
.style-selector .style-selection-container .style-container {
|
||||
height: 100%;
|
||||
width: 30%;
|
||||
margin: 1% 10%;
|
||||
}
|
||||
}
|
||||
@media (max-width: 918px) {
|
||||
.style-selector {
|
||||
margin-bottom: 5vh;
|
||||
}
|
||||
.style-selector .style-selection-container {
|
||||
flex-wrap: nowrap;
|
||||
flex-direction: column;
|
||||
}
|
||||
.style-selector .style-selection-container .style-container {
|
||||
width: 60%;
|
||||
}
|
||||
}
|
||||
@media (max-width: 462px) {
|
||||
.style-selector .style-selection-container .style-container {
|
||||
width: 100%;
|
||||
}
|
||||
}/*# sourceMappingURL=style-selector.css.map */
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"sources":["style-selector.scss","style-selector.css"],"names":[],"mappings":"AAAA;EAEI,uBAAA;EAEA,iBAAA;EACA,oBAAA;EAEA,kBAAA;EAEA,SAAA;EACA,UAAA;EAEA,oDAAA;EAEA,WAAA;EAyEA,4BAAA;AC7EJ;ADMI;EACI,6BAAA;EACA,eAAA;EACA,kBAAA;EAEA,iBAAA;EACA,eAAA;EACA,kBAAA;ACLR;ADSQ;EACI,aAAA;EACA,YAAA;EAEA,mBAAA;ACRZ;ADUY;EACI,aAAA;EACA,sBAAA;EACA,uBAAA;EAEA,+BAAA;ACThB;ADWgB;EACI,eAAA;ACTpB;ADYgB;EACI,8BAAA;EACA,eAAA;ACVpB;ADeQ;EACI,WAAA;EACA,UAAA;ACbZ;ADgBQ;EACI,aAAA;EACA,+BAAA;ACdZ;ADgBY;EACI,mBAAA;ACdhB;ADmBQ;EACI,oBAAA;EAEA,WAAA;EACA,YAAA;EAEA,wCAAA;EACA,qBAAA;EACA,mBAAA;EAEA,4BAAA;ACpBZ;ADuBQ;EAEI,uCAAA;ACtBZ;;AD+BA;EACI,aAAA;EACA,oBAAA;AC5BJ;;AD+BA;EACI,WAAA;EACA,oBAAA;AC5BJ;;AD+BA;EACI;IACI,iBAAA;IAEA,gBAAA;IAEA,WAAA;IAEA,UAAA;IACA,gBAAA;IAEA,sBAAA;EChCN;EDkCM;IACI,iBAAA;IAEA,cAAA;ECjCV;EDqCM;IAEI,aAAA;IAEA,eAAA;IAEA,WAAA;ECtCV;EDwCU;IACI,YAAA;IACA,UAAA;IAEA,cAAA;ECvCd;AACF;AD4CA;EAEI;IAWI,kBAAA;ECrDN;ED4CM;IACI,iBAAA;IAEA,sBAAA;EC3CV;ED6CU;IACI,UAAA;EC3Cd;AACF;ADkDA;EAMY;IACI,WAAA;ECrDd;AACF","file":"style-selector.css"}
|
||||
@@ -15,22 +15,16 @@
|
||||
z-index: 50;
|
||||
|
||||
h2 {
|
||||
@include bodyFont;
|
||||
color: $second-color;
|
||||
color: var(--main-text-color);
|
||||
font-size: 30pt;
|
||||
text-align: center;
|
||||
|
||||
margin-left: -3vw;
|
||||
|
||||
|
||||
|
||||
margin-top: 1vh;
|
||||
margin-bottom: 3vh;
|
||||
}
|
||||
|
||||
.style-selection-container {
|
||||
|
||||
|
||||
.style-container{
|
||||
display: flex;
|
||||
height: 10vh;
|
||||
@@ -42,16 +36,15 @@
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
|
||||
color: var(--second-text-color);
|
||||
|
||||
.title {
|
||||
@include bodyFont;
|
||||
font-size: 13pt;
|
||||
}
|
||||
|
||||
.times {
|
||||
@include bodyFont;
|
||||
color: $second-color;
|
||||
color: var(--third-text-color);
|
||||
font-size: 13pt;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -77,7 +70,7 @@
|
||||
width: 45px;
|
||||
height: 45px;
|
||||
|
||||
border: 3px solid $main-color;
|
||||
border: 3px solid var(--main-text-color);
|
||||
border-radius: 0.25em;
|
||||
border-radius: 100%;
|
||||
|
||||
@@ -86,7 +79,7 @@
|
||||
|
||||
.checkbox__input input:checked + .checkbox_control {
|
||||
|
||||
background-color: $light-color;
|
||||
background-color: var(--lightest-color);
|
||||
}
|
||||
|
||||
// CREDITS TO https://moderncss.dev/pure-css-custom-checkbox-style/
|
||||
@@ -173,43 +166,4 @@
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.style-selector-container.dark-mode-component {
|
||||
|
||||
.style-selector {
|
||||
|
||||
h2 {
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.style-selection-container {
|
||||
|
||||
|
||||
.style-container{
|
||||
|
||||
label {
|
||||
|
||||
.title {
|
||||
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.times {
|
||||
color: $lightest-color-dark;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.checkbox_control {
|
||||
|
||||
border: 3px solid $lightest-color-dark-darker;
|
||||
}
|
||||
|
||||
.checkbox__input input:checked + .checkbox_control {
|
||||
|
||||
background-color: $lightest-color-dark;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
101
src/pages/Main/Pomodoro/pomodoro-styles.css
Normal file
101
src/pages/Main/Pomodoro/pomodoro-styles.css
Normal file
@@ -0,0 +1,101 @@
|
||||
.main-pomodoro {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 68vh;
|
||||
background-color: var(--main-background-color);
|
||||
}
|
||||
.main-pomodoro .timer {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
font-weight: bold;
|
||||
font-size: 130pt;
|
||||
color: var(--main-text-color);
|
||||
}
|
||||
.main-pomodoro .style-display {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
}
|
||||
.main-pomodoro .style-display h4 {
|
||||
font-size: 24pt;
|
||||
color: var(--main-text-color);
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
}
|
||||
.main-pomodoro .style-display h3 {
|
||||
font-size: 30pt;
|
||||
color: var(--main-text-color);
|
||||
cursor: pointer;
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
}
|
||||
.main-pomodoro .start-pomodoro {
|
||||
margin-top: 6vh;
|
||||
width: 30vw;
|
||||
height: 8vh;
|
||||
font-family: var(--title-font);
|
||||
font-weight: 700;
|
||||
background: var(--second-color);
|
||||
border-radius: 24px;
|
||||
font-size: 5vh;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.pomodoro-counter {
|
||||
position: absolute;
|
||||
top: 29vh;
|
||||
color: var(--pomodoro-counter-text-color);
|
||||
}
|
||||
.pomodoro-counter ul li {
|
||||
display: flex;
|
||||
list-style-type: none;
|
||||
margin-top: 2vh;
|
||||
font-size: 15pt;
|
||||
}
|
||||
.pomodoro-counter ul li .separator {
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
margin: 0px 0.5vw;
|
||||
}
|
||||
.pomodoro-counter ul li .quantity {
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
background-color: var(--lightest-color);
|
||||
height: 30px;
|
||||
width: 30px;
|
||||
border-radius: 100%;
|
||||
font-family: var(--title-font);
|
||||
font-weight: 700;
|
||||
color: var(--main-text-color);
|
||||
}
|
||||
|
||||
@media (max-width: 991.98px) {
|
||||
.pomodoro-counter {
|
||||
position: initial;
|
||||
padding-bottom: 5vh;
|
||||
}
|
||||
}
|
||||
@media (max-width: 576px) {
|
||||
.main-pomodoro {
|
||||
height: auto;
|
||||
}
|
||||
.main-pomodoro .timer {
|
||||
font-size: 80pt;
|
||||
}
|
||||
.main-pomodoro .start-pomodoro {
|
||||
font-size: 13pt;
|
||||
}
|
||||
}/*# sourceMappingURL=pomodoro-styles.css.map */
|
||||
1
src/pages/Main/Pomodoro/pomodoro-styles.css.map
Normal file
1
src/pages/Main/Pomodoro/pomodoro-styles.css.map
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"sources":["pomodoro-styles.scss","pomodoro-styles.css"],"names":[],"mappings":"AAAA;EAEI,aAAA;EACA,sBAAA;EACA,mBAAA;EACA,uBAAA;EAEA,YAAA;EAEA,8CAAA;ACFJ;ADII;EAEI,aAAA;EACA,uBAAA;EAEA,iBAAA;EACA,gBAAA;EAEA,6BAAA;ACLR;ADQI;EAEI,aAAA;EACA,mBAAA;EACA,sBAAA;ACPR;ADSQ;EACI,eAAA;EAEA,6BAAA;EACA,yBAAA;KAAA,sBAAA;MAAA,qBAAA;UAAA,iBAAA;ACRZ;ADWQ;EACI,eAAA;EAEA,6BAAA;EAEA,eAAA;EACA,yBAAA;KAAA,sBAAA;MAAA,qBAAA;UAAA,iBAAA;ACXZ;ADeI;EACI,eAAA;EACA,WAAA;EACA,WAAA;EAEA,8BAAA;EACA,gBAAA;EAEA,+BAAA;EACA,mBAAA;EAEA,cAAA;EACA,YAAA;AChBR;;ADoBA;EACI,kBAAA;EACA,SAAA;EACA,yCAAA;ACjBJ;ADoBQ;EACI,aAAA;EAEA,qBAAA;EACA,eAAA;EAEA,eAAA;ACpBZ;ADsBY;EACI,yBAAA;KAAA,sBAAA;MAAA,qBAAA;UAAA,iBAAA;EACA,iBAAA;ACpBhB;ADuBY;EAEI,yBAAA;KAAA,sBAAA;MAAA,qBAAA;UAAA,iBAAA;EAEA,aAAA;EACA,uBAAA;EACA,mBAAA;EAEA,uCAAA;EAEA,YAAA;EACA,WAAA;EAEA,mBAAA;EAEA,8BAAA;EACA,gBAAA;EACA,6BAAA;AC3BhB;;ADiCA;EAEI;IAEI,iBAAA;IACA,mBAAA;EChCN;AACF;ADmCA;EAEI;IAEI,YAAA;ECnCN;EDqCM;IACI,eAAA;ECnCV;EDsCM;IACI,eAAA;ECpCV;AACF","file":"pomodoro-styles.css"}
|
||||
127
src/pages/Main/Pomodoro/pomodoro-styles.scss
Normal file
127
src/pages/Main/Pomodoro/pomodoro-styles.scss
Normal file
@@ -0,0 +1,127 @@
|
||||
.main-pomodoro {
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
height: 68vh;
|
||||
|
||||
background-color: var(--main-background-color);
|
||||
|
||||
.timer {
|
||||
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
|
||||
font-weight: bold;
|
||||
font-size: 130pt;
|
||||
|
||||
color: var(--main-text-color);
|
||||
}
|
||||
|
||||
.style-display {
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
|
||||
h4 {
|
||||
font-size: 24pt;
|
||||
|
||||
color: var(--main-text-color);
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 30pt;
|
||||
|
||||
color: var(--main-text-color);
|
||||
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
}
|
||||
}
|
||||
|
||||
.start-pomodoro {
|
||||
margin-top: 6vh;
|
||||
width: 30vw;
|
||||
height: 8vh;
|
||||
|
||||
font-family: var(--title-font);
|
||||
font-weight: 700;
|
||||
|
||||
background: var(--second-color);
|
||||
border-radius: 24px;
|
||||
|
||||
font-size: 5vh;
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
|
||||
.pomodoro-counter {
|
||||
position: absolute;
|
||||
top: 29vh;
|
||||
color: var(--pomodoro-counter-text-color);
|
||||
|
||||
ul {
|
||||
li {
|
||||
display: flex;
|
||||
|
||||
list-style-type: none;
|
||||
margin-top: 2vh;
|
||||
|
||||
font-size: 15pt;
|
||||
|
||||
.separator {
|
||||
user-select: none;
|
||||
margin: 0px 0.5vw;
|
||||
}
|
||||
|
||||
.quantity {
|
||||
|
||||
user-select: none;
|
||||
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
background-color: var(--lightest-color);
|
||||
|
||||
height: 30px;
|
||||
width: 30px;
|
||||
|
||||
border-radius: 100%;
|
||||
|
||||
font-family: var(--title-font);
|
||||
font-weight: 700;
|
||||
color: var(--main-text-color);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 991.98px) {
|
||||
|
||||
.pomodoro-counter {
|
||||
|
||||
position: initial;
|
||||
padding-bottom: 5vh;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 576px) {
|
||||
|
||||
.main-pomodoro {
|
||||
|
||||
height: auto;
|
||||
|
||||
.timer {
|
||||
font-size: 80pt;
|
||||
}
|
||||
|
||||
.start-pomodoro {
|
||||
font-size: 13pt;
|
||||
}
|
||||
}
|
||||
}
|
||||
51
src/styles.css
Normal file
51
src/styles.css
Normal file
@@ -0,0 +1,51 @@
|
||||
body {
|
||||
--main-text-color: #1FAB89;
|
||||
--second-text-color: #272727;
|
||||
--third-text-color: #fff;
|
||||
--pomodoro-counter-text-color: #8d8d8d;
|
||||
--main-background-color: #fff;
|
||||
--second-background-color: #fff;
|
||||
--main-color: #62D2A2;
|
||||
--second-color: #1FAB89;
|
||||
--light-color: #9DF3C4;
|
||||
--light-color-darker: #3c8f61;
|
||||
--lightest-color: #D7FBE8;
|
||||
--lightest-color-darker: #b2e9cb;
|
||||
--body-font: "Rambla", sans-serif;
|
||||
--title-font: "Raleway", sans-serif;
|
||||
--border-color: #969696;
|
||||
}
|
||||
|
||||
html, body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
body {
|
||||
height: 100%;
|
||||
background-color: var(--main-background-color);
|
||||
}
|
||||
|
||||
button {
|
||||
background: none;
|
||||
border: none;
|
||||
width: 8vw;
|
||||
}
|
||||
|
||||
h1, h2, h3, h4, h5, h6, p {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
* {
|
||||
font-family: "Rambla", sans-serif;
|
||||
}
|
||||
|
||||
h1, h2, h3, h4, h5, h6 {
|
||||
font-family: "Raleway", sans-serif;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
a {
|
||||
color: rgb(85, 185, 252);
|
||||
}/*# sourceMappingURL=styles.css.map */
|
||||
1
src/styles.css.map
Normal file
1
src/styles.css.map
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"sources":["styles.scss","styles.css"],"names":[],"mappings":"AAAA;EAEI,0BAAA;EACA,4BAAA;EACA,wBAAA;EACA,sCAAA;EAEA,6BAAA;EACA,+BAAA;EAEA,qBAAA;EACA,uBAAA;EAEA,sBAAA;EACA,6BAAA;EAEA,yBAAA;EACA,gCAAA;EAEA,iCAAA;EACA,mCAAA;EACA,uBAAA;ACLJ;;ADQA;EACI,SAAA;EACA,UAAA;ACLJ;;ADQA;EACI,YAAA;EACA,8CAAA;ACLJ;;ADQA;EACI,gBAAA;EACA,YAAA;EACA,UAAA;ACLJ;;ADQA;EACI,SAAA;EACA,UAAA;ACLJ;;ADQA;EACI,iCAAA;ACLJ;;ADQA;EACI,kCAAA;EACA,gBAAA;ACLJ;;ADQA;EACI,wBAAA;ACLJ","file":"styles.css"}
|
||||
57
src/styles.scss
Normal file
57
src/styles.scss
Normal file
@@ -0,0 +1,57 @@
|
||||
body {
|
||||
|
||||
--main-text-color: #1FAB89;
|
||||
--second-text-color: #272727;
|
||||
--third-text-color: #fff;
|
||||
--pomodoro-counter-text-color: #8d8d8d;
|
||||
|
||||
--main-background-color: #fff;
|
||||
--second-background-color: #fff;
|
||||
|
||||
--main-color: #62D2A2;
|
||||
--second-color: #1FAB89;
|
||||
|
||||
--light-color: #9DF3C4;
|
||||
--light-color-darker: #3c8f61;
|
||||
|
||||
--lightest-color: #D7FBE8;
|
||||
--lightest-color-darker: #b2e9cb;
|
||||
|
||||
--body-font: 'Rambla', sans-serif;
|
||||
--title-font: 'Raleway', sans-serif;
|
||||
--border-color: #969696;
|
||||
}
|
||||
|
||||
html, body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
body {
|
||||
height: 100%;
|
||||
background-color: var(--main-background-color);
|
||||
}
|
||||
|
||||
button {
|
||||
background: none;
|
||||
border: none;
|
||||
width: 8vw;
|
||||
}
|
||||
|
||||
h1, h2, h3, h4, h5, h6, p {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
* {
|
||||
font-family: 'Rambla', sans-serif;
|
||||
}
|
||||
|
||||
h1, h2, h3, h4, h5, h6 {
|
||||
font-family: 'Raleway', sans-serif;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
a {
|
||||
color: rgb(85, 185, 252);
|
||||
}
|
||||
Reference in New Issue
Block a user