diff --git a/package.json b/package.json index 853a857..ee92b30 100644 --- a/package.json +++ b/package.json @@ -3,9 +3,13 @@ "version": "0.1.0", "private": true, "dependencies": { + "@fortawesome/fontawesome-svg-core": "^6.1.1", + "@fortawesome/free-solid-svg-icons": "^6.1.1", + "@fortawesome/react-fontawesome": "^0.1.18", "@testing-library/jest-dom": "^5.14.1", "@testing-library/react": "^11.2.7", "@testing-library/user-event": "^12.8.3", + "@uiball/loaders": "^1.2.6", "firebase": "^9.1.0", "react": "^17.0.2", "react-countdown": "^2.3.2", diff --git a/public/index.html b/public/index.html index 5b1ef86..f697fcd 100644 --- a/public/index.html +++ b/public/index.html @@ -3,8 +3,7 @@ - - + diff --git a/src/pages/Main/ClockifyTaskForm/ClockifyTaskForm.jsx b/src/pages/Main/ClockifyTaskForm/ClockifyTaskForm.jsx index cf6b49c..8a149ca 100644 --- a/src/pages/Main/ClockifyTaskForm/ClockifyTaskForm.jsx +++ b/src/pages/Main/ClockifyTaskForm/ClockifyTaskForm.jsx @@ -1,27 +1,28 @@ import './clockify-task-form.css' -import React, { useState } from 'react'; +import React, { useRef, useState } from 'react'; import { getAuth, onAuthStateChanged } from "firebase/auth"; import { doc, getDoc, getFirestore } from "firebase/firestore"; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' 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}) => { +import {faCheck, faPlus} from '@fortawesome/free-solid-svg-icons' +import { Ring } from '@uiball/loaders' + +const ClockifyTaskForm = ({timerOn, setTimerOn, signedIn, apiKey, setApiKey, taskName, setTaskName, projectID, setProjectID, darkMode, taskID, setTaskID, clockifyData, changeClockifyData}) => { 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 descriptionInput = useRef("") const [loading, setLoading] = useState(true) - async function getApiKey() { + let newTask = useRef("") + const [addingNewTask, setAddingNewTask] = useState(false) + + async function getApiKey(userUID) { try { @@ -39,25 +40,22 @@ const ClockifyTaskForm = ({timerOn, setTimerOn, signedIn, apiKey, setApiKey, tas } catch (error) { + console.log(error); } setLoading(false) } React.useEffect(() => { - if (signedIn) { onAuthStateChanged(auth, async (user) => { - if (user) { + if (user && user.uid) { - setUserUID(user.uid) - - if (user.uid) { - await getApiKey() - setLoading(false) - } + await getApiKey(user.uid) + setLoading(false) + } else { return (<>) } @@ -67,7 +65,7 @@ const ClockifyTaskForm = ({timerOn, setTimerOn, signedIn, apiKey, setApiKey, tas setLoading(false) } - }, [signedIn, getApiKey]) + }, [signedIn]) async function makeRequestWorkspaces(apiClockify) { try { @@ -86,7 +84,7 @@ const ClockifyTaskForm = ({timerOn, setTimerOn, signedIn, apiKey, setApiKey, tas return await data } catch (error) { - + console.log(error); } } @@ -95,20 +93,17 @@ const ClockifyTaskForm = ({timerOn, setTimerOn, signedIn, apiKey, setApiKey, tas const data = await makeRequestWorkspaces(key) if (data.code !== 1000) { - let workspacesCopy = [] + let workspaces = [] await data.forEach(workspace => { - workspacesCopy.push(workspace) + workspaces.push(workspace) }); - - setWorkspaces(workspacesCopy) - - setWorkspacesReady(true) - setLoading(false) + + changeClockifyData({workspaces: workspaces}) } } - async function requestProjects(e) { + const getProjects = async (e) => { try { const request = { @@ -119,32 +114,70 @@ const ClockifyTaskForm = ({timerOn, setTimerOn, signedIn, apiKey, setApiKey, tas } } const response = await fetch(`https://api.clockify.me/api/v1/workspaces/${e}/projects`, request) - const data = response.json() + const data = await response.json() + + console.log(data); + changeClockifyData({projects: data}) - return data - } catch (error) { console.log(error); } } - const defineProjects = async (e) => { - - if (e === 0) { - setProjectsDone(false) - setProjects([]) + async function getTasks(projectID) { + if (projectID === "0") { + changeClockifyData({projectID: undefined}) + changeClockifyData({tasks: undefined}) + return } - setWorkspaceID(e) - const data = await requestProjects(e) - setProjects(data) - setProjectsDone(true) + 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/${clockifyData.workspaceID}/projects/${projectID}/tasks`, request) + const data = await response.json() + + changeClockifyData({tasks: data}) + + } catch (error) { + console.log(error); + } } - const selectProject = (e) => { + async function addNewTask() { - setProjectID(e) + setAddingNewTask("loading") + + try { + const url = `https://api.clockify.me/api/v1/workspaces/${clockifyData.workspaceID}/projects/${clockifyData.projectID}/tasks` + const request = { + method: "POST", + body: JSON.stringify({ + name: newTask.current.value + }), + headers: { + 'X-Api-Key': apiKey, + "content-type": "application/json", + } + } + + await fetch(url, request) + + newTask.current.value = "" + + await getTasks(clockifyData.projectID) + + } catch (error) { + console.log(error); + } + + setAddingNewTask(false) } return ( @@ -155,41 +188,107 @@ const ClockifyTaskForm = ({timerOn, setTimerOn, signedIn, apiKey, setApiKey, tas :
{ - userUID ? -
- { + changeClockifyData({workspaceID: e.target.value}) + getProjects(e.target.value) + }} + className='workspace-selector' + > { - workspacesReady ? - workspaces.map( (workspace) => { + clockifyData.workspaces && + clockifyData.workspaces.map((workspace) => { return }) - : null } - { + changeClockifyData({projectID: e.target.value}) + getTasks(e.target.value) + }} + className={`project-selector ${(!clockifyData.workspaceID) && 'disabled'}`} + > { - projectsDone && projects.length !== 0 ? - projects.map((project) => ( + clockifyData.projects && + clockifyData.projects.map((project) => ( !project.archived ? - + : null )) - : null } + + + + <> + { + addingNewTask && + + } + + {setTaskName(e.target.value)}} - value={taskName} + ref={descriptionInput} + onChange={(e) => changeClockifyData({description: e.target.value})} placeholder="Add task description" - className={projectID !== 0 ? null: 'disabled'} - + className={!clockifyData.projectID && 'disabled'} onKeyPress={event => { - if (event.key === 'Enter') { - setTimerOn(true) } }} diff --git a/src/pages/Main/ClockifyTaskForm/clockify-task-form.css b/src/pages/Main/ClockifyTaskForm/clockify-task-form.css index 467cc6b..503dbe0 100644 --- a/src/pages/Main/ClockifyTaskForm/clockify-task-form.css +++ b/src/pages/Main/ClockifyTaskForm/clockify-task-form.css @@ -4,32 +4,39 @@ top: 60vh; left: 2.5vw; } +.clockify-task-form input::-moz-placeholder { + font-family: "Arial", sans-serif; +} +.clockify-task-form input:-ms-input-placeholder { + font-family: "Arial", sans-serif; +} +.clockify-task-form select, .clockify-task-form select option, .clockify-task-form input, .clockify-task-form input::placeholder { + font-family: "Arial", sans-serif; +} .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; + height: 5vh; } -.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 .add-task { + width: 3.5vh; + height: 3.5vh; + margin-left: 0.5vh; + display: inline; + background-color: var(--main-text-color); + border-radius: 100%; + color: #fff; + cursor: pointer; +} +.clockify-task-form .add-task:hover { + filter: brightness(90%); +} +.clockify-task-form .add-task:active { + filter: brightness(110%); } .clockify-task-form select { overflow: hidden; @@ -44,14 +51,14 @@ padding: 1px 2px; box-sizing: border-box; } -.clockify-task-form input[type=text].disabled { +.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%; + opacity: 0.3; } @media (max-width: 991.98px) { diff --git a/src/pages/Main/ClockifyTaskForm/clockify-task-form.css.map b/src/pages/Main/ClockifyTaskForm/clockify-task-form.css.map index ece60ba..449b608 100644 --- a/src/pages/Main/ClockifyTaskForm/clockify-task-form.css.map +++ b/src/pages/Main/ClockifyTaskForm/clockify-task-form.css.map @@ -1 +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"} \ No newline at end of file +{"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,gCAAA;ACDR;ADAI;EACI,gCAAA;ACDR;ADAI;EACI,gCAAA;ACDR;ADII;EACI,WAAA;EACA,YAAA;EACA,gBAAA;ACFR;ADKI;EACI,WAAA;EACA,WAAA;ACHR;ADMI;EACI,YAAA;EACA,aAAA;EAEA,kBAAA;EAEA,eAAA;EAEA,wCAAA;EACA,mBAAA;EAEA,WAAA;EAEA,eAAA;ACTR;ADWQ;EACI,uBAAA;ACTZ;ADYQ;EACI,wBAAA;ACVZ;ADcI;EACI,gBAAA;EACA,mBAAA;EACA,uBAAA;ACZR;ADeI;EACI,WAAA;EACA,WAAA;EAEA,eAAA;EAEA,aAAA;EACA,gBAAA;EAEA,sBAAA;AChBR;ADmBI;EACI,yBAAA;KAAA,sBAAA;MAAA,qBAAA;UAAA,iBAAA;EACA,eAAA;EACA,oBAAA;EACA,YAAA;ACjBR;;ADqBA;EAEI;IACI,iBAAA;IACA,WAAA;IAEA,aAAA;IACA,6BAAA;IAEA,gBAAA;ECrBN;EDuBM;IACI,UAAA;IACA,YAAA;ECrBV;EDwBM;IACI,WAAA;IACA,WAAA;ECtBV;AACF;AD2BA;EAEI;IACI,iBAAA;IACA,WAAA;IAEA,aAAA;IACA,sBAAA;IACA,mBAAA;EC3BN;ED6BM;IACI,UAAA;IACA,YAAA;EC3BV;ED8BM;IACI,UAAA;IACA,WAAA;IACA,eAAA;EC5BV;AACF","file":"clockify-task-form.css"} \ No newline at end of file diff --git a/src/pages/Main/ClockifyTaskForm/clockify-task-form.scss b/src/pages/Main/ClockifyTaskForm/clockify-task-form.scss index a33d5db..c3c9e36 100644 --- a/src/pages/Main/ClockifyTaskForm/clockify-task-form.scss +++ b/src/pages/Main/ClockifyTaskForm/clockify-task-form.scss @@ -6,28 +6,42 @@ top: 60vh; left: 2.5vw; + select, select option, input, input::placeholder { + font-family: 'Arial', sans-serif; + } + &.loading-container { width: 20vw; height: auto; background: none; } - - &.disabled { - user-select: none; - cursor: initial; - pointer-events: none; - opacity: 30%; - } .workspace-selector, .project-selector { width: 15vw; - height: 3vw; + height: 5vh; + } - &.disabled { - user-select: none; - cursor: initial; - pointer-events: none; - opacity: 30%; + .add-task { + width: 3.5vh; + height: 3.5vh; + + margin-left: 0.5vh; + + display: inline; + + background-color: var(--main-text-color); + border-radius: 100%; + + color: #fff; + + cursor: pointer; + + &:hover { + filter: brightness(90%); + } + + &:active { + filter: brightness(110%); } } @@ -47,13 +61,13 @@ padding: 1px 2px; box-sizing: border-box; + } - &.disabled { - user-select: none; - cursor: initial; - pointer-events: none; - opacity: 30%; - } + .disabled { + user-select: none; + cursor: initial; + pointer-events: none; + opacity: 0.3; } } diff --git a/src/pages/Main/Main.jsx b/src/pages/Main/Main.jsx index b14b203..4b452d8 100644 --- a/src/pages/Main/Main.jsx +++ b/src/pages/Main/Main.jsx @@ -7,10 +7,15 @@ const Main = ({signedIn, darkMode, setKonamiCodeActive, KonamiCodeActive, notifi const [timerOn, setTimerOn] = useState(false) const [apiKey, setApiKey] = useState('') - const [taskName, setTaskName] = useState('') - const [workspaceID, setWorkspaceID] = useState(0) - const [projectID, setProjectID] = useState(0) + const [clockifyData, setClockifyData] = useState({}) + + function changeClockifyData(obj) { + setClockifyData(clockifyData => ({ + ...clockifyData, + ...obj + })) + } return ( <> @@ -24,16 +29,8 @@ const Main = ({signedIn, darkMode, setKonamiCodeActive, KonamiCodeActive, notifi apiKey={apiKey} setApiKey={setApiKey} - taskName={taskName} - setTaskName={setTaskName} - - workspaceID={workspaceID} - setWorkspaceID={setWorkspaceID} - - projectID={projectID} - setProjectID={setProjectID} - - darkMode={darkMode} + clockifyData={clockifyData} + changeClockifyData={changeClockifyData} /> { async function uploadToClockifyTimer() { - if (!props.workspaceID && !props.projectID) { + if (!props.clockifyData.workspaceID && !props.clockifyData.projectID) { return } try { - const url = `https://api.clockify.me/api/v1/workspaces/${props.workspaceID}/time-entries` + const url = `https://api.clockify.me/api/v1/workspaces/${props.clockifyData.workspaceID}/time-entries` const body = { start: startTime, end: endTime, - projectId: props.projectID, - description: props.taskName + description: props.clockifyData.description, + projectId: props.clockifyData.projectID, + taskId: props.clockifyData.taskID ? props.clockifyData.taskID : "", } const headers = { @@ -55,6 +56,7 @@ const Pomodoro = (props) => { await fetch(url, request) } catch (error) { + console.log(error); } } @@ -68,7 +70,7 @@ const Pomodoro = (props) => { }) return ( -
+
{ stats={stats} setStats={setStats} - - workspaceID={props.workspaceID} - setWorkspaceID={props.setWorkspaceID} - - projectID={props.projectID} - setProjectID={props.setProjectID} - - apiKey={props.apiKey} startTime={startTime} setStartTime={setStartTime} diff --git a/src/pages/Main/Pomodoro/StyleSelector/style-selector.css b/src/pages/Main/Pomodoro/StyleSelector/style-selector.css index 524a5ac..5451944 100644 --- a/src/pages/Main/Pomodoro/StyleSelector/style-selector.css +++ b/src/pages/Main/Pomodoro/StyleSelector/style-selector.css @@ -5,7 +5,7 @@ position: absolute; top: 29vh; left: 75vw; - box-shadow: 1px 6px 15px #00000020; + box-shadow: 1px 6px 15px rgba(0, 0, 0, 0.1254901961); z-index: 50; transition: 0.2s ease-in-out; } @@ -109,6 +109,4 @@ .style-selector .style-selection-container .style-container { width: 100%; } -} - -/*# sourceMappingURL=style-selector.css.map */ +}/*# sourceMappingURL=style-selector.css.map */ \ No newline at end of file diff --git a/src/pages/Main/Pomodoro/StyleSelector/style-selector.css.map b/src/pages/Main/Pomodoro/StyleSelector/style-selector.css.map index a7b22e0..d8c63fc 100644 --- a/src/pages/Main/Pomodoro/StyleSelector/style-selector.css.map +++ b/src/pages/Main/Pomodoro/StyleSelector/style-selector.css.map @@ -1 +1 @@ -{"version":3,"sourceRoot":"","sources":["style-selector.scss"],"names":[],"mappings":"AAAA;EAEI;EAEA;EACA;EAEA;EAEA;EACA;EAEA;EAEA;EAyEA;;AAvEA;EACI;EACA;EACA;EAEA;EACA;EACA;;AAIA;EACI;EACA;EAEA;;AAEA;EACI;EACA;EACA;EAEA;;AAEA;EACI;;AAGJ;EACI;EACA;;AAKZ;EACI;EACA;;AAGJ;EACI;EACA;;AAEA;EACI;;AAKR;EACI;EAEA;EACA;EAEA;EACA;EACA;EAEA;;AAGJ;EAEI;;;AASZ;EACI;EACA;;;AAGJ;EACI;EACA;;;AAGJ;EACI;IACI;IAEA;IAEA;IAEA;IACA;IAEA;;EAEA;IACI;IAEA;;EAIJ;IAEI;IAEA;IAEA;;EAEA;IACI;IACA;IAEA;;;AAMhB;EAEI;IAWI;;EATA;IACI;IAEA;;EAEA;IACI;;;AAQhB;EAMY;IACI","file":"style-selector.css"} \ No newline at end of file +{"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,UAAA;EACA,oBAAA;AC5BJ;;AD+BA;EACI,UAAA;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"} \ No newline at end of file