diff --git a/web/apps/payments/package.json b/web/apps/payments/package.json index 2f31e6aec..e73f26c6c 100644 --- a/web/apps/payments/package.json +++ b/web/apps/payments/package.json @@ -5,7 +5,6 @@ "dependencies": { "@/next": "*", "@stripe/stripe-js": "^1.17.0", - "axios": "^1.6.7", - "bootstrap": "4.6.0" + "axios": "^1.6.7" } } diff --git a/web/apps/payments/src/components/EnteSpinner.tsx b/web/apps/payments/src/components/EnteSpinner.tsx index 277857e0e..d65c73614 100644 --- a/web/apps/payments/src/components/EnteSpinner.tsx +++ b/web/apps/payments/src/components/EnteSpinner.tsx @@ -1,10 +1,5 @@ import * as React from "react"; -import { Spinner } from "react-bootstrap"; -export const EnteSpinner: React.FC = () => { - return ( - - Loading... - - ); +export const Spinner: React.FC = () => { + return
; }; diff --git a/web/apps/payments/src/pages/_app.tsx b/web/apps/payments/src/pages/_app.tsx index bc7be4839..34713277c 100644 --- a/web/apps/payments/src/pages/_app.tsx +++ b/web/apps/payments/src/pages/_app.tsx @@ -1,4 +1,3 @@ -import "bootstrap/dist/css/bootstrap.min.css"; import type { AppProps } from "next/app"; import Head from "next/head"; import constants from "utils/strings"; diff --git a/web/apps/payments/src/pages/index.tsx b/web/apps/payments/src/pages/index.tsx index 69288efa7..93535f9c5 100644 --- a/web/apps/payments/src/pages/index.tsx +++ b/web/apps/payments/src/pages/index.tsx @@ -1,5 +1,5 @@ import { Container } from "components/Container"; -import { EnteSpinner } from "components/EnteSpinner"; +import { Spinner } from "components/EnteSpinner"; import * as React from "react"; import { parseAndHandleRequest } from "services/billingService"; import { CUSTOM_ERROR } from "utils/error"; @@ -35,7 +35,7 @@ export default function Home() { {errorMessageView ? (
{constants.SOMETHING_WENT_WRONG}
) : ( - loading && + loading && )} ); diff --git a/web/apps/payments/src/styles/globals.css b/web/apps/payments/src/styles/globals.css index d0d1ccf23..e75d7598d 100644 --- a/web/apps/payments/src/styles/globals.css +++ b/web/apps/payments/src/styles/globals.css @@ -20,3 +20,19 @@ body { display: flex; flex-direction: column; } + +.loading-spinner { + color: #28a745; + width: 2rem; + height: 2rem; + border: 0.25em solid currentColor; + border-right-color: transparent; + border-radius: 50%; + animation: 0.75s linear infinite spinner-border; +} + +@keyframes spinner-border { + 100% { + transform: rotate(360deg); + } +} diff --git a/web/apps/photos/package.json b/web/apps/photos/package.json index 0be17f3e2..deac7ad04 100644 --- a/web/apps/photos/package.json +++ b/web/apps/photos/package.json @@ -18,7 +18,6 @@ "@tensorflow/tfjs-tflite": "0.0.1-alpha.7", "bip39": "^3.0.4", "blazeface-back": "^0.0.9", - "bootstrap": "^4.5.2", "bs58": "^5.0.0", "chrono-node": "^2.2.6", "comlink": "^4.3.0", @@ -45,7 +44,6 @@ "photoswipe": "file:./thirdparty/photoswipe", "piexifjs": "^1.0.6", "pure-react-carousel": "^1.30.1", - "react-bootstrap": "^1.3.0", "react-datepicker": "^4.16.0", "react-dropzone": "^11.2.4", "react-otp-input": "^2.3.1", diff --git a/web/apps/photos/src/components/FixCreationTime.tsx b/web/apps/photos/src/components/FixCreationTime.tsx index 6814cdf0e..62c31539a 100644 --- a/web/apps/photos/src/components/FixCreationTime.tsx +++ b/web/apps/photos/src/components/FixCreationTime.tsx @@ -1,32 +1,43 @@ -import { Row, Value } from "@ente/shared/components/Container"; import DialogBox from "@ente/shared/components/DialogBox/"; -import { Button, LinearProgress } from "@mui/material"; -import EnteDateTimePicker from "components/EnteDateTimePicker"; +import { + Button, + FormControl, + FormControlLabel, + FormLabel, + LinearProgress, + Radio, + RadioGroup, +} from "@mui/material"; import { ComfySpan } from "components/ExportInProgress"; -import { Formik } from "formik"; +import { useFormik } from "formik"; import { t } from "i18next"; import { GalleryContext } from "pages/gallery"; -import React, { ChangeEvent, useContext, useEffect, useState } from "react"; -import { Form } from "react-bootstrap"; +import React, { useContext, useEffect, useState } from "react"; import { updateCreationTimeWithExif } from "services/updateCreationTimeWithExif"; import { EnteFile } from "types/file"; +import EnteDateTimePicker from "./EnteDateTimePicker"; export interface FixCreationTimeAttributes { files: EnteFile[]; } -type Step = "running" | "completed" | "error"; +type Step = "running" | "completed" | "completed-with-errors"; -export enum FIX_OPTIONS { - DATE_TIME_ORIGINAL, - DATE_TIME_DIGITIZED, - METADATA_DATE, - CUSTOM_TIME, -} +export type FixOption = + | "date-time-original" + | "date-time-digitized" + | "metadata-date" + | "custom-time"; -interface formValues { - option: FIX_OPTIONS; - customTime: Date; +interface FormValues { + option: FixOption; + /** + * Date.toISOString() + * + * Formik doesn't have native support for JS dates, so we instead keep the + * corresponding date's ISO string representation as the form state. + */ + customTimeString: string; } interface FixCreationTimeProps { @@ -52,22 +63,19 @@ const FixCreationTime: React.FC = (props) => { } }, [props.isOpen]); - const startFix = async (option: FIX_OPTIONS, customTime: Date) => { + const onSubmit = async (values: FormValues) => { + console.log({ values }); setStep("running"); - const failed = await updateCreationTimeWithExif( + const completedWithErrors = await updateCreationTimeWithExif( props.attributes.files, - option, - customTime, + values.option, + new Date(values.customTimeString), setProgressTracker, ); - setStep(failed ? "error" : "completed"); + setStep(completedWithErrors ? "completed-with-errors" : "completed"); await galleryContext.syncWithRemote(); }; - const onSubmit = (values: formValues) => { - startFix(Number(values.option), new Date(values.customTime)); - }; - const title = step === "running" ? t("FIX_CREATION_TIME_IN_PROGRESS") @@ -96,34 +104,10 @@ const FixCreationTime: React.FC = (props) => { {message &&
{message}
} {step === "running" && ( - + )} - - initialValues={{ - option: FIX_OPTIONS.DATE_TIME_ORIGINAL, - customTime: new Date(), - }} - validateOnBlur={false} - onSubmit={onSubmit} - > - {({ values, handleChange, handleSubmit }) => ( - <> - {(step === undefined || step === "error") && ( -
- -
- )} - - - )} - + + ); @@ -134,101 +118,82 @@ export default FixCreationTime; const messageForStep = (step?: Step) => { switch (step) { case undefined: - return t("UPDATE_CREATION_TIME_NOT_STARTED"); + return undefined; case "running": return undefined; case "completed": return t("UPDATE_CREATION_TIME_COMPLETED"); - case "error": + case "completed-with-errors": return t("UPDATE_CREATION_TIME_COMPLETED_WITH_ERROR"); } }; -const Option = ({ - value, - selected, - onChange, - label, -}: { - value: FIX_OPTIONS; - selected: FIX_OPTIONS; - onChange: (e: string | ChangeEvent) => void; - label: string; -}) => ( - - - - {label} - - -); - -function FixCreationTimeOptions({ handleChange, values }) { - return ( -
- - - - - - - - - - {Number(values.option) === FIX_OPTIONS.CUSTOM_TIME && ( - - - handleChange("customTime")(x.toUTCString()) - } - /> - - )} - -
- ); +interface OptionsFormProps { + step?: Step; + onSubmit: (values: FormValues) => void | Promise; + hide: () => void; } -const FixCreationTimeFooter = ({ step, startFix, ...props }) => { +const OptionsForm: React.FC = ({ step, onSubmit, hide }) => { + const { values, handleChange, handleSubmit } = useFormik({ + initialValues: { + option: "date-time-original", + customTimeString: new Date().toISOString(), + }, + validateOnBlur: false, + onSubmit, + }); + + return ( + <> + {(step === undefined || step === "completed-with-errors") && ( +
+
+ + + {t("UPDATE_CREATION_TIME_NOT_STARTED")} + + + + } + label={t("DATE_TIME_ORIGINAL")} + /> + } + label={t("DATE_TIME_DIGITIZED")} + /> + } + label={t("METADATA_DATE")} + /> + } + label={t("CUSTOM_TIME")} + /> + + {values.option === "custom-time" && ( + + handleChange("customTimeString")( + d.toISOString(), + ) + } + /> + )} + +
+ )} +