misc: added timer

This commit is contained in:
Sheen Capadngan
2024-11-21 04:09:19 +08:00
parent bce3f3d676
commit 00dcadbc08
2 changed files with 71 additions and 8 deletions
@@ -65,7 +65,10 @@ export const TotpProvider = (): TDynamicProviderFns => {
authenticatorInstance.options = { step: period }; authenticatorInstance.options = { step: period };
} }
return { entityId, data: { TOTP: authenticatorInstance.generate(secret) } }; return {
entityId,
data: { TOTP: authenticatorInstance.generate(secret), TIME_REMAINING: authenticatorInstance.timeRemaining() }
};
}; };
const revoke = async (_inputs: unknown, entityId: string) => { const revoke = async (_inputs: unknown, entityId: string) => {
@@ -1,4 +1,4 @@
import { ReactNode, useEffect } from "react"; import { ReactNode, useEffect, useState } from "react";
import { Controller, useForm } from "react-hook-form"; import { Controller, useForm } from "react-hook-form";
import { faCheck, faCopy } from "@fortawesome/free-solid-svg-icons"; import { faCheck, faCopy } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
@@ -62,7 +62,60 @@ const OutputDisplay = ({
); );
}; };
const renderOutputForm = (provider: DynamicSecretProviders, data: unknown) => { const TotpOutputDisplay = ({
totp,
remainingSeconds,
triggerLeaseCreation
}: {
totp: string;
remainingSeconds: number;
triggerLeaseCreation: (details: { ttl?: string }) => Promise<void>;
}) => {
const [remainingTime, setRemainingTime] = useState(remainingSeconds);
const [shouldShowRegenerate, setShouldShowRegenerate] = useToggle(false);
useEffect(() => {
setRemainingTime(remainingSeconds);
setShouldShowRegenerate.off();
// Set up countdown interval
const intervalId = setInterval(() => {
setRemainingTime((prevTime) => {
if (prevTime <= 1) {
clearInterval(intervalId);
setShouldShowRegenerate.on();
return 0;
}
return prevTime - 1;
});
}, 1000);
// Cleanup interval on unmount or when totp changes
return () => clearInterval(intervalId);
}, [totp, remainingSeconds]);
return (
<div>
<OutputDisplay label="Time-based one-time password" value={totp} />
{remainingTime > 0 && (
<div>
Valid for {remainingTime} {remainingTime > 1 ? "seconds" : "second"}
</div>
)}
{shouldShowRegenerate && (
<Button colorSchema="secondary" className="mt-2" onClick={() => triggerLeaseCreation({})}>
Regenerate
</Button>
)}
</div>
);
};
const renderOutputForm = (
provider: DynamicSecretProviders,
data: unknown,
triggerLeaseCreation: (details: { ttl?: string }) => Promise<void>
) => {
if ( if (
provider === DynamicSecretProviders.SqlDatabase || provider === DynamicSecretProviders.SqlDatabase ||
provider === DynamicSecretProviders.Cassandra || provider === DynamicSecretProviders.Cassandra ||
@@ -251,14 +304,17 @@ const renderOutputForm = (provider: DynamicSecretProviders, data: unknown) => {
} }
if (provider === DynamicSecretProviders.Totp) { if (provider === DynamicSecretProviders.Totp) {
const { TOTP } = data as { const { TOTP, TIME_REMAINING } = data as {
TOTP: string; TOTP: string;
TIME_REMAINING: number;
}; };
return ( return (
<div> <TotpOutputDisplay
<OutputDisplay label="Time-based one-time password" value={TOTP} /> totp={TOTP}
</div> remainingSeconds={TIME_REMAINING}
triggerLeaseCreation={triggerLeaseCreation}
/>
); );
} }
@@ -391,7 +447,11 @@ export const CreateDynamicSecretLease = ({
animate={{ opacity: 1, translateX: 0 }} animate={{ opacity: 1, translateX: 0 }}
exit={{ opacity: 0, translateX: 30 }} exit={{ opacity: 0, translateX: 30 }}
> >
{renderOutputForm(provider, createDynamicSecretLease.data?.data)} {renderOutputForm(
provider,
createDynamicSecretLease.data?.data,
handleDynamicSecretLeaseCreate
)}
</motion.div> </motion.div>
)} )}
</AnimatePresence> </AnimatePresence>