Skip to content

Commit

Permalink
feat: add success screen
Browse files Browse the repository at this point in the history
  • Loading branch information
im-adithya committed Dec 27, 2023
1 parent 5279211 commit a5f354d
Show file tree
Hide file tree
Showing 6 changed files with 211 additions and 7 deletions.
13 changes: 8 additions & 5 deletions frontend/src/components/QRCode.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import ReactQRCode from "react-qr-code";
import { useDarkMode } from "../hooks/useDarkMode";

export type Props = {
value: string;
Expand All @@ -16,11 +17,11 @@ export type Props = {
level?: "Q" | undefined;
};

export default function QRCode({ value, size, level, className }: Props) {
// TODO: Theme option in settings?
const isDark = window.matchMedia("(prefers-color-scheme: dark)").matches
const fgColor = isDark ? "#FFFFFF" : "#000000";
const bgColor = isDark ? "#000000" : "#FFFFFF";
function QRCode({ value, size, level, className }: Props) {
const isDarkMode = useDarkMode();
console.log(isDarkMode);
const fgColor = isDarkMode ? "#FFFFFF" : "#242424";
const bgColor = isDarkMode ? "#242424" : "#FFFFFF";

return (
<ReactQRCode
Expand All @@ -33,3 +34,5 @@ export default function QRCode({ value, size, level, className }: Props) {
/>
);
}

export default QRCode;
17 changes: 17 additions & 0 deletions frontend/src/components/icons/CopyIcon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { SVGAttributes } from "react";

export function CopyIcon(props: SVGAttributes<SVGElement>) {
return (
<svg
width="24"
height="24"
viewBox="0 0 24 24"
fill="currentColor"
xmlns="http://www.w3.org/2000/svg"
{...props}
>
<rect width="10" height="14" x="6" y="6" rx="1.5" />
<path d="M8.064 5.064A1.5 1.5 0 018.5 5h7A1.5 1.5 0 0117 6.5v11a1.5 1.5 0 01-.064.436A1.5 1.5 0 0018 16.5v-11A1.5 1.5 0 0016.5 4h-7a1.5 1.5 0 00-1.436 1.064z" />
</svg>
);
}
21 changes: 21 additions & 0 deletions frontend/src/components/icons/EyeIcon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { SVGAttributes } from "react";

export function EyeIcon(props: SVGAttributes<SVGElement>) {
return (
<svg
width="24"
height="24"
viewBox="0 0 24 24"
fill="currentColor"
xmlns="http://www.w3.org/2000/svg"
{...props}
>
<path d="M12 14a2 2 0 100-4 2 2 0 000 4z" />
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M21 12c0 2.761-4.03 5-9 5s-9-2.239-9-5 4.03-5 9-5 9 2.239 9 5zm-5 0a4 4 0 11-8 0 4 4 0 018 0z"
/>
</svg>
);
}
21 changes: 21 additions & 0 deletions frontend/src/components/icons/LogoIcon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { SVGAttributes } from "react";

export function LogoIcon(props: SVGAttributes<SVGElement>) {
return (
<svg
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
{...props}
>
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M13.6281 5.03035L20.9945 12.43L20.9956 12.431C21.4028 12.84 21.8601 13.0639 22.279 13.1062C22.6711 13.1459 23.0667 13.0322 23.4219 12.6949L19.4029 2.22631C18.9491 1.2345 17.6421 0.998839 16.8705 1.7739L13.6281 5.03035ZM20.5966 12.8277L20.5967 12.8278L20.5965 12.828C21.5558 13.7914 22.8871 14.0212 23.8507 13.0622L20.5884 16.3091L19.0591 17.8312L17.9915 18.8938L16.1182 17.0137C17.026 15.6333 16.8781 13.76 15.6662 12.5406L14.3908 11.2573C14.2095 11.0748 13.9176 11.074 13.7351 11.2553L13.1055 11.8809L11.5093 10.2748C11.2323 9.99609 10.7744 10.0126 10.5176 10.3196C10.2928 10.5907 10.3315 10.9906 10.5786 11.2392L12.1549 12.8252L10.9035 14.0685L9.3073 12.4624C9.03028 12.1837 8.5705 12.1981 8.31561 12.5072C8.0928 12.7764 8.13155 13.1762 8.37864 13.4249L9.95488 15.0109L9.32725 15.6346C9.14479 15.8159 9.14392 16.1077 9.32522 16.2902L10.6006 17.5735C11.8123 18.7927 13.6847 18.9526 15.0709 18.054L16.9452 19.9351L16.3577 20.5197L14.3527 22.5153C13.3889 23.4743 11.8301 23.4707 10.8708 22.5072L0.717064 12.3077C-0.242097 11.344 -0.238627 9.78546 0.725161 8.82627L6.96087 2.61994C7.92465 1.66089 9.4834 1.66451 10.4427 2.62803L20.5966 12.8277Z"
fill="currentColor"
/>
</svg>
);
}
142 changes: 140 additions & 2 deletions frontend/src/screens/apps/AppCreated.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,146 @@
import { useLocation } from "react-router-dom";
import { useEffect, useRef, useState } from "react";
import { useLocation, Navigate } from "react-router-dom";
import { CreateAppResponse } from "../../types";

import { EyeIcon } from "../../components/icons/EyeIcon";
import { CopyIcon } from "../../components/icons/CopyIcon";
import { LogoIcon } from "../../components/icons/LogoIcon";
import QRCode from "../../components/QRCode";

export default function AppCreated() {
const { state } = useLocation();
const createAppResponse = state as CreateAppResponse;
return <p>Pairing URI: {createAppResponse.pairingUri}</p>;

const [copied, setCopied] = useState(false);
const [isPopupVisible, setPopupVisible] = useState(false);
const popupRef = useRef<HTMLDivElement>(null);

useEffect(() => {
const handleClickOutside = (event: MouseEvent) => {
if (
popupRef.current &&
!popupRef.current.contains(event.target as Node)
) {
setPopupVisible(false);
}
};
document.addEventListener("mousedown", handleClickOutside);
return () => {
document.removeEventListener("mousedown", handleClickOutside);
};
}, []);

if (!createAppResponse) {
return <Navigate to="/apps/new" state={{ from: "/apps/success" }} />;
}

const pairingUri = createAppResponse.pairingUri;

const copyToClipboard = () => {
if (navigator.clipboard && window.isSecureContext) {
navigator.clipboard.writeText(pairingUri);
} else {
// Fallback for older browsers
const textArea = document.createElement("textarea");
textArea.value = pairingUri;
textArea.style.position = "absolute";
textArea.style.opacity = "0";
document.body.appendChild(textArea);
textArea.select();
new Promise((res, rej) => {
document.execCommand("copy") ? res(pairingUri) : rej();
textArea.remove();
});
}
setCopied(true);
setTimeout(() => {
setCopied(false);
}, 2000);
};

const togglePopup = () => {
setPopupVisible(!isPopupVisible);
};

return (
<div className="w-full max-w-screen-sm mx-auto">
<h2 className="font-bold text-2xl font-headline mb-2 dark:text-white text-center">
🚀 Almost there!
</h2>
<div className="font-medium text-center mb-8 dark:text-white">
Complete the last step of the setup by pasting or scanning your
connection's pairing secret in the desired app to finalise the
connection.
</div>

<div className="flex flex-col">
<a
href={pairingUri}
className="w-full inline-flex bg-purple-700 cursor-pointer duration-150 focus:outline-none hover:bg-purple-900 items-center justify-center px-5 py-4 rounded-md shadow text-white transition mb-2"
>
<LogoIcon className="inline w-6 mr-2" />
<p className="font-medium">Open in supported app</p>
</a>
<div className="text-center text-xs text-gray-600 dark:text-neutral-500">
Only connect with apps you trust!
</div>

<div className="dark:text-white text-sm text-center mt-8 mb-1">
Manually pair app ↓
</div>
<button
id="copy-button"
className={`w-full inline-flex items-center justify-center px-3 py-2 cursor-pointer duration-150 transition border dark:border-white/10 ${
copied
? "bg-green-600 text-white"
: "bg-white dark:bg-surface-02dp text-purple-700 dark:text-neutral-200 hover:bg-gray-50 dark:hover:bg-surface-16dp"
} bg-origin-border rounded-md focus:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:ring-purple-700 my-2`}
onClick={copyToClipboard}
>
<CopyIcon className="inline w-6 mr-2" />
<span id="copy-text">
{copied ? "Copied to clipboard!" : "Copy pairing secret"}
</span>
</button>

<button
id="copy-button"
className={`w-full inline-flex items-center justify-center px-3 py-2 cursor-pointer duration-150 transition border dark:border-white/10 bg-white dark:bg-surface-02dp text-purple-700 dark:text-neutral-200 hover:bg-gray-50 dark:hover:bg-surface-16dp bg-origin-border rounded-md focus:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:ring-purple-700 mb-2`}
onClick={togglePopup}
>
<EyeIcon className="inline w-6 mr-2" />
<span id="copy-text">QR Code</span>
</button>
{/* ... Remaining JSX conversion for QR code and other elements */}
</div>
<div
className={`fixed inset-0 items-center justify-center ${
isPopupVisible ? "flex" : "hidden"
}`}
>
<div
onClick={togglePopup}
className="fixed inset-0 bg-gray-900 opacity-50"
></div>
<div className="bg-white dark:bg-surface-02dp p-4 lg:px-6 rounded shadow relative">
<h2 className="mb-4 font-semibold text-lg lg:text-xl font-headline dark:text-white">
Scan QR Code in the app to pair
</h2>
<a
href={pairingUri}
target="_blank"
className="block border-4 border-purple-600 rounded-lg p-4 lg:p-6"
>
<QRCode value={pairingUri} size={256} />
</a>
<button
onClick={togglePopup}
className="w-full inline-flex font-semibold items-center justify-center px-3 py-2 cursor-pointer duration-150 transition bg-white text-gray-700 dark:bg-surface-02dp dark:text-neutral-200 dark:border-neutral-800 hover:bg-gray-50 dark:hover:bg-surface-16dp bg-origin-border shadow rounded-md focus:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:ring-purple-700 mt-4"
>
Close
</button>
</div>
</div>
</div>
);
}
4 changes: 4 additions & 0 deletions frontend/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -105,5 +105,9 @@ export interface InfoResponse {
}

export interface CreateAppResponse {
name: string;
pairingUri: string;
pairingPublicKey: string;
pairingSecretKey: string;
returnTo: string;
}

0 comments on commit a5f354d

Please sign in to comment.