Skip to content

Commit

Permalink
feat(setting): request user confirmation on local data import
Browse files Browse the repository at this point in the history
As a part of this implement handier popup tooling

refs #56
  • Loading branch information
ygrishajev committed May 22, 2024
1 parent 34b1cf4 commit bf7445f
Show file tree
Hide file tree
Showing 7 changed files with 127 additions and 36 deletions.
4 changes: 2 additions & 2 deletions api/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

57 changes: 37 additions & 20 deletions deploy-web/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 6 additions & 5 deletions deploy-web/package.json
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
{
"name": "akash-console",
"version": "2.7.2",
"description": "Web UI to deploy on the Akash Network and view statistic about network usage.",
"author": "Akash Network",
"private": true,
"description": "Web UI to deploy on the Akash Network and view statistic about network usage.",
"license": "Apache-2.0",
"author": "Akash Network",
"scripts": {
"dev": "next -p 3000",
"build": "next build",
"build-analyze": "set ANALYZE=true&& next build",
"dev": "next -p 3000",
"pretty": "prettier --write \"./**/*.{js,jsx,ts,tsx,json}\"",
"start": "next start",
"type-check": "tsc",
"pretty": "prettier --write \"./**/*.{js,jsx,ts,tsx,json}\""
"type-check": "tsc"
},
"dependencies": {
"@akashnetwork/akash-api": "^1.3.0",
Expand Down Expand Up @@ -111,6 +111,7 @@
"react-use-websocket": "^3.0.0",
"rehype-highlight": "^6.0.0",
"remark-gfm": "^3.0.1",
"rxjs": "^7.8.1",
"sharp": "^0.30.3",
"stripe": "^10.14.0",
"tailwind-merge": "^2.0.0",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import React, { FC, useCallback, useRef } from "react";
import { Download, Upload } from "iconoir-react";

import { Button } from "@src/components/ui/button";
import { usePopup } from "@src/context/PopupProvider/PopupProvider";

export type LocalData = Record<string, any>;

Expand All @@ -12,9 +14,16 @@ interface LocalDataManagerProps {

export const LocalDataManagerComponent: FC<LocalDataManagerProps> = ({ read, write, onDone }) => {
const ref = useRef<HTMLInputElement>(null);
const { confirm } = usePopup();

const triggerFileUpload = useCallback(() => {
ref.current?.click();
const triggerFileUpload = useCallback(async () => {
const isConfirmed = await confirm({
title: "Import Local Data",
message: "Existing local data will be overwritten. Are you sure you want to proceed?"
});
if (isConfirmed) {
ref.current?.click();
}
}, [ref.current]);

const importLocalData = useCallback((event: React.ChangeEvent<HTMLInputElement>) => {
Expand Down
10 changes: 5 additions & 5 deletions deploy-web/src/components/shared/Popup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ type MessageProps = {
onValidate: () => void;
};

type ConfirmProps = {
export type ConfirmProps = {
variant: "confirm";
onValidate: () => void;
onCancel: () => void;
Expand All @@ -35,7 +35,7 @@ export type TOnCloseHandler = {
(event: any, reason: "backdropClick" | "escapeKeyDown" | "action"): void;
};

type CommonProps = {
export type CommonProps = {
title?: string | React.ReactNode;
message?: string;
open?: boolean;
Expand Down Expand Up @@ -131,8 +131,8 @@ export function Popup(props: React.PropsWithChildren<PopupProps>) {
<Button
variant="ghost"
onClick={() => {
onClose(null, "action");
props.onCancel();
onClose(null, "action");
}}
>
{CancelButtonLabel}
Expand All @@ -141,8 +141,8 @@ export function Popup(props: React.PropsWithChildren<PopupProps>) {
variant="default"
color="priamry"
onClick={() => {
onClose(null, "action");
props.onValidate();
onClose(null, "action");
}}
>
{ConfirmButtonLabel}
Expand Down Expand Up @@ -207,7 +207,7 @@ export function Popup(props: React.PropsWithChildren<PopupProps>) {
</Button>
));
component.push(
<DialogFooter className="flex justify-between space-x-2 sm:justify-between flex-row" key="DialogCustomActions">
<DialogFooter className="flex flex-row justify-between space-x-2 sm:justify-between" key="DialogCustomActions">
<div className="space-x-2">{leftButtons}</div>
<div className="space-x-2">{rightButtons}</div>
</DialogFooter>
Expand Down
62 changes: 62 additions & 0 deletions deploy-web/src/context/PopupProvider/PopupProvider.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import { Popup, PopupProps, CommonProps, ConfirmProps } from "@src/components/shared/Popup";
import React, { FC, useCallback, useMemo, useState } from "react";
import { firstValueFrom, Subject } from "rxjs";

type ConfirmPopupProps = string | (Omit<CommonProps, "onClose" | "open"> & Omit<ConfirmProps, "onValidate" | "onCancel" | "variant">);

type PopupProviderContext = {
confirm: (messageOrProps: ConfirmPopupProps) => Promise<boolean>;
};

const PopupContext = React.createContext<PopupProviderContext | undefined>(undefined);

export const PopupProvider: FC = ({ children }) => {
const [popupProps, setPopupProps] = useState<PopupProps | undefined>();

const confirm = useCallback(
(messageOrProps: ConfirmPopupProps) => {
let subject: Subject<boolean> | undefined = new Subject<boolean>();

const closeWithResult = (result: boolean) => () => {
if (subject) {
subject.next(result);
subject.complete();
setPopupProps(undefined);
subject = undefined;
}
};
const reject = closeWithResult(false);
const props = typeof messageOrProps === "string" ? { message: messageOrProps } : messageOrProps;

setPopupProps({
title: "Confirm",
...props,
open: true,
variant: "confirm",
onValidate: closeWithResult(true),
onCancel: reject,
onClose: reject
});

return firstValueFrom(subject);
},
[setPopupProps]
);

const context = useMemo(() => ({ confirm }), [confirm]);

return (
<PopupContext.Provider value={context}>
{children}
{popupProps && <Popup {...popupProps} />}
</PopupContext.Provider>
);
};

export const usePopup = () => {
const context = React.useContext(PopupContext);
if (!context) {
throw new Error("usePopup must be used within a PopupProvider");
}
return context;
};
6 changes: 4 additions & 2 deletions deploy-web/src/pages/_app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import { TooltipProvider } from "@src/components/ui/tooltip";
import { cn } from "@src/utils/styleUtils";
import { GeistSans } from "geist/font/sans";
import GoogleAnalytics from "@src/components/layout/CustomGoogleAnalytics";
import { PopupProvider } from "@src/context/PopupProvider/PopupProvider";

interface Props extends AppProps {}

Expand Down Expand Up @@ -70,8 +71,9 @@ const App: React.FunctionComponent<Props> = props => {
<TemplatesProvider>
<LocalNoteProvider>
<GoogleAnalytics />

<Component {...pageProps} />
<PopupProvider>
<Component {...pageProps} />
</PopupProvider>
</LocalNoteProvider>
</TemplatesProvider>
</BackgroundTaskProvider>
Expand Down

0 comments on commit bf7445f

Please sign in to comment.