From 604ee4684c6858ffe0c1abaf580ad3bcfd9ebdcf Mon Sep 17 00:00:00 2001 From: Otsuki Hitoshi Date: Tue, 21 Jul 2020 08:49:47 +0900 Subject: [PATCH 1/8] WIP: Add add attendance feature --- package-lock.json | 57 ++++++++++++++++++++++ package.json | 1 + src/Navbar.tsx | 117 ++++++++++++++++++++++++++++++++++++---------- src/index.tsx | 1 + 4 files changed, 151 insertions(+), 25 deletions(-) diff --git a/package-lock.json b/package-lock.json index 7167e60..6df8eb9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1117,6 +1117,14 @@ "resolved": "https://registry.npmjs.org/@csstools/normalize.css/-/normalize.css-10.1.0.tgz", "integrity": "sha512-ij4wRiunFfaJxjB0BdrYHIH8FxBJpOwNPhhAcunlmPdXudL1WQV1qoP9un6JsEBAgQH+7UXyyjh0g7jTxXK6tg==" }, + "@date-fns/upgrade": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@date-fns/upgrade/-/upgrade-1.0.3.tgz", + "integrity": "sha512-0BLzKmXwWw3Zh3cZzW4xScmwGijXCAulaFdikqNiSnK8PAgYYSWWxOP/kuJFpKaoIT5KzstVGyHsjA7t/QXi1Q==", + "requires": { + "date-fns": "^2.1" + } + }, "@hapi/address": { "version": "2.1.4", "resolved": "https://registry.npmjs.org/@hapi/address/-/address-2.1.4.tgz", @@ -4446,6 +4454,20 @@ } } }, + "date-fns": { + "version": "2.14.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.14.0.tgz", + "integrity": "sha512-1zD+68jhFgDIM0rF05rcwYO8cExdNqxjq4xP1QKM60Q45mnO6zaMWB4tOzrIr4M4GSLntsKeE4c9Bdl2jhL/yw==" + }, + "dayzed": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/dayzed/-/dayzed-3.1.0.tgz", + "integrity": "sha512-Mwb/T78ppKDIoXsNgSLfIYfIO7ylal+vKp8VVMzK6rQq4VJSE7AdrGFN2EQDmve037J9TKZo06mX+QuuKQ2raA==", + "requires": { + "@babel/runtime": "^7.6.2", + "date-fns": "^2.0.0" + } + }, "debug": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", @@ -6100,6 +6122,11 @@ "mime-types": "^2.1.12" } }, + "format-string-by-pattern": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/format-string-by-pattern/-/format-string-by-pattern-1.2.1.tgz", + "integrity": "sha512-x7JY+q8XvBmHCf4ZSQiiG+8fmC02oiei1JoAsUcdHcy8Kn6LwaE1KUlQ8ph3fNnIcWY65B3aVuKArdbAEQxpLg==" + }, "forwarded": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", @@ -10849,6 +10876,11 @@ "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.7.tgz", "integrity": "sha512-TAv1KJFh3RhqxNvhzxj6LeT5NWklP6rDr2a0jaTfsZ5wSZWHOGeqQyejUp3xxLfPt2UpyJEcVQB/zyPcmonNFA==" }, + "react-fast-compare": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.0.tgz", + "integrity": "sha512-rtGImPZ0YyLrscKI9xTpV8psd6I8VAtjKCzQDlzyDvqJA8XOW78TXYQwNRNd8g8JZnDu8q9Fu/1v4HPAVwVdHA==" + }, "react-is": { "version": "16.13.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", @@ -10974,6 +11006,31 @@ "workbox-webpack-plugin": "4.3.1" } }, + "react-semantic-ui-datepickers": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/react-semantic-ui-datepickers/-/react-semantic-ui-datepickers-2.8.0.tgz", + "integrity": "sha512-0VADVRuiNsGhPwaT5jtcx1KRKgWvv+zz/kpQmJkKWhHI518JmEGpGhSdac13djenke54dUdGdtEEPwU7lgA7mg==", + "requires": { + "@babel/runtime": "7.10.3", + "@date-fns/upgrade": "1.0.3", + "classnames": "2.2.6", + "core-js": "3.6.5", + "date-fns": "2.14.0", + "dayzed": "3.1.0", + "format-string-by-pattern": "1.2.1", + "react-fast-compare": "3.2.0" + }, + "dependencies": { + "@babel/runtime": { + "version": "7.10.3", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.10.3.tgz", + "integrity": "sha512-RzGO0RLSdokm9Ipe/YD+7ww8X2Ro79qiXZF3HU9ljrM+qnJmH1Vqth+hbiQZy761LnMJTMitHDuKVYTk3k4dLw==", + "requires": { + "regenerator-runtime": "^0.13.4" + } + } + } + }, "read-pkg": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", diff --git a/package.json b/package.json index 70fd553..d24754c 100644 --- a/package.json +++ b/package.json @@ -15,6 +15,7 @@ "react-dom": "16.13.1", "react-router-dom": "5.2.0", "react-scripts": "3.4.1", + "react-semantic-ui-datepickers": "^2.8.0", "semantic-ui-css": "2.4.1", "semantic-ui-react": "1.0.0", "swr": "0.2.3", diff --git a/src/Navbar.tsx b/src/Navbar.tsx index 522bf16..b3c9717 100644 --- a/src/Navbar.tsx +++ b/src/Navbar.tsx @@ -1,7 +1,9 @@ -import React from "react"; +import React, { useState } from "react"; import { Link, useRouteMatch } from "react-router-dom"; -import { Menu } from "semantic-ui-react"; +import { Menu, Modal, Button, Form, Checkbox, Input } from "semantic-ui-react"; import { useUser } from "./useUser"; +import { AttendanceType } from "./attendance"; +import SemanticDatePicker from "react-semantic-ui-datepickers"; type ItemType = "log" | "history"; @@ -18,30 +20,95 @@ function useActiveItem(): ItemType { export const Navbar = () => { const activeItem = useActiveItem(); const { data } = useUser(); + const [isModalOpen, setIsModalOpen] = useState(false); + const [form, setForm] = useState({ + attendanceType: AttendanceType.Arrive, + occurredAt: new Date(), + }); + + const openAddModal = () => { + setIsModalOpen(true); + }; + + const closeAddModal = () => { + setIsModalOpen(false); + }; + + const handleFormChange = () => { + setForm({ ...form }); + }; + + const handleDateChange = (_: unknown, data: any) => { + setForm({...form, occurredAt: data.value}) + } return ( - - Attcy - - - - - - - - {data ? ( - <> - Welcome {data.userDetails} - - - - - ) : ( - - - - )} - - + <> + + Attcy + + + + + + + + {data ? ( + <> + Add + Welcome {data.userDetails} + + + + + ) : ( + + + + )} + + + + Add attendance + +
+ + + + + + + + +
+
+ + + - diff --git a/src/Navbar.tsx b/src/Navbar.tsx index b3c9717..715ceb8 100644 --- a/src/Navbar.tsx +++ b/src/Navbar.tsx @@ -1,9 +1,9 @@ import React, { useState } from "react"; import { Link, useRouteMatch } from "react-router-dom"; -import { Menu, Modal, Button, Form, Checkbox, Input } from "semantic-ui-react"; +import { Menu, Modal, Button } from "semantic-ui-react"; import { useUser } from "./useUser"; -import { AttendanceType } from "./attendance"; -import SemanticDatePicker from "react-semantic-ui-datepickers"; +import { AddForm, useAddForm } from "./AddForm"; +import { useLogAttendance } from "./useAttendances"; type ItemType = "log" | "history"; @@ -17,14 +17,23 @@ function useActiveItem(): ItemType { return "log"; } +const useAddFormSubmit = (userId: string | undefined) => { + const { logAttendance } = useLogAttendance(); + const submitAddForm = async (values: AddForm) => { + if (!userId) { + return; + } + await logAttendance(userId, values.attendanceType, new Date()); + }; + return submitAddForm; +}; + export const Navbar = () => { const activeItem = useActiveItem(); const { data } = useUser(); const [isModalOpen, setIsModalOpen] = useState(false); - const [form, setForm] = useState({ - attendanceType: AttendanceType.Arrive, - occurredAt: new Date(), - }); + const submitAddForm = useAddFormSubmit(data?.userId); + const addForm = useAddForm(submitAddForm); const openAddModal = () => { setIsModalOpen(true); @@ -34,14 +43,6 @@ export const Navbar = () => { setIsModalOpen(false); }; - const handleFormChange = () => { - setForm({ ...form }); - }; - - const handleDateChange = (_: unknown, data: any) => { - setForm({...form, occurredAt: data.value}) - } - return ( <> @@ -71,42 +72,15 @@ export const Navbar = () => { Add attendance -
- - - - - - - - -
+
-
From 4bb5c07a4ceac96df188278171c880807027c353 Mon Sep 17 00:00:00 2001 From: Otsuki Hitoshi Date: Sun, 26 Jul 2020 17:11:45 +0900 Subject: [PATCH 7/8] Send specified occurredAt time --- src/Navbar.tsx | 27 +++++++++++++++++++++------ src/time.ts | 9 +++++++++ src/useAttendances.ts | 2 +- 3 files changed, 31 insertions(+), 7 deletions(-) diff --git a/src/Navbar.tsx b/src/Navbar.tsx index 715ceb8..468ec3d 100644 --- a/src/Navbar.tsx +++ b/src/Navbar.tsx @@ -4,6 +4,7 @@ import { Menu, Modal, Button } from "semantic-ui-react"; import { useUser } from "./useUser"; import { AddForm, useAddForm } from "./AddForm"; import { useLogAttendance } from "./useAttendances"; +import { extractTimeInfo } from "./time"; type ItemType = "log" | "history"; @@ -18,21 +19,31 @@ function useActiveItem(): ItemType { } const useAddFormSubmit = (userId: string | undefined) => { - const { logAttendance } = useLogAttendance(); + const { logAttendance, loading } = useLogAttendance(); const submitAddForm = async (values: AddForm) => { if (!userId) { return; } - await logAttendance(userId, values.attendanceType, new Date()); + const date = values.occurredAt.date; + const { hour, minute, second } = extractTimeInfo(values.occurredAt.time); + const occurredAt = new Date( + date.getFullYear(), + date.getMonth(), + date.getDate(), + hour, + minute, + second + ); + await logAttendance(userId, values.attendanceType, occurredAt); }; - return submitAddForm; + return { submitAddForm, loading }; }; export const Navbar = () => { const activeItem = useActiveItem(); const { data } = useUser(); const [isModalOpen, setIsModalOpen] = useState(false); - const submitAddForm = useAddFormSubmit(data?.userId); + const { submitAddForm, loading } = useAddFormSubmit(data?.userId); const addForm = useAddForm(submitAddForm); const openAddModal = () => { @@ -75,10 +86,14 @@ export const Navbar = () => { - - diff --git a/src/time.ts b/src/time.ts index 720b0cf..0ffcd84 100644 --- a/src/time.ts +++ b/src/time.ts @@ -6,3 +6,12 @@ export function getTimePart(date: Date, withColon = true): string { const delimiter = withColon ? ":" : ""; return timeArray.map((timeStr) => timeStr.padStart(2, "0")).join(delimiter); } + +export function extractTimeInfo( + timeStr: string +): { hour: number; minute: number; second: number } { + const hour = +timeStr.substr(0, 2); + const minute = +timeStr.substr(2, 2); + const second = +timeStr.substr(4, 2); + return { hour, minute, second }; +} diff --git a/src/useAttendances.ts b/src/useAttendances.ts index 9e388fd..e9d838f 100644 --- a/src/useAttendances.ts +++ b/src/useAttendances.ts @@ -89,7 +89,7 @@ export const useLogAttendance = (): { type: AttendanceType[type], }; if (occurredAt) { - data.occurredAt = occurredAt.getTime(); + data.occurredAt = occurredAt.getTime() / 1000; } await fetch(endpoint, { method: "POST", From 50c8aca013ca4626521b9cec40f40815a81127e3 Mon Sep 17 00:00:00 2001 From: Otsuki Hitoshi Date: Sun, 26 Jul 2020 17:12:46 +0900 Subject: [PATCH 8/8] Do not show error panel when there is no error --- src/AddForm.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/AddForm.tsx b/src/AddForm.tsx index 0a7882a..c6de7ec 100644 --- a/src/AddForm.tsx +++ b/src/AddForm.tsx @@ -124,7 +124,7 @@ export const AddForm: React.FC = ({ onChange={handlers.changeAttendanceType} /> - {errorMessage} + {errorMessage && {errorMessage}} ); };