Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TECH-292 - Allow the user to select the pass type #81

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions src/civic_sign_frontend_demo/package.json
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
{
"dependencies": {
"@civic/icp-gateway-react-ui": "^0.0.1-beta.5",
"@civic/icp-gateway-react-ui": "^0.0.3",
"@dfinity/auth-client": "^2.0.0",
"@dfinity/candid": "^2.0.0",
"@dfinity/identity": "^2.0.0",
"@dfinity/principal": "^2.0.0",
"@dfinity/candid": "^2.0.0",
"@dfinity/verifiable-credentials": "^0.0.2",
"axios": "^1.7.2",
"jwt-decode": "^4.0.0",
"lucide-react": "^0.429.0",
"react": "^18.2.0",
"react-dom": "^18.2.0"
},
Expand All @@ -18,11 +19,14 @@
"@types/react": "^18.2.14",
"@types/react-dom": "^18.2.6",
"@vitejs/plugin-react": "^4.0.1",
"autoprefixer": "^10.4.20",
"cross-fetch": "^3.1.6",
"dotenv": "^16.3.1",
"jsdom": "^22.1.0",
"postcss": "^8.4.41",
"react-icons": "^5.2.1",
"sass": "^1.63.6",
"tailwindcss": "^3.4.10",
"typescript": "^5.1.3",
"vite": "^4.3.9",
"vite-plugin-environment": "^1.1.3",
Expand Down
6 changes: 6 additions & 0 deletions src/civic_sign_frontend_demo/postcss.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export default {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
}
83 changes: 70 additions & 13 deletions src/civic_sign_frontend_demo/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
import React, { useEffect, useState, useCallback, useMemo } from 'react';
import { Principal } from '@dfinity/principal';
import { PrincipalService } from './service/PrincipalService.js';
import { config } from './config.js';
import { config, GatekeeperNetwork } from './config.js';
import ICPCredentialCheckButton, { CredentialCheckResponse } from '@civic/icp-gateway-react-ui';
import { ChevronDown } from 'lucide-react';

function App() {
const [principal, setPrincipal] = useState<Principal | undefined>(undefined);
const { gatekeeperNetwork } = config;

const [urlCode, setUrlCode] = useState<string | null>(null);
const [selectedGatekeeperNetwork, setSelectedGatekeeperNetwork] = useState<GatekeeperNetwork>(config.gatekeeperNetworks[0]);

// Assume we have an array of available gatekeeperNetworks
const gatekeeperNetworks = useMemo(() => config.gatekeeperNetworks, []);

useEffect(() => {
const urlParams = new URLSearchParams(window.location.search);
Expand All @@ -24,7 +27,6 @@ function App() {
const principalService = new PrincipalService({
identityProvider: config.internetIdentityUrl,
});

try {
const userPrincipal = await principalService.requestPrincipal();
if (userPrincipal) {
Expand All @@ -39,17 +41,72 @@ function App() {
console.log('handleCredentialCheck', credential, error);
}, []);

const handleGatekeeperNetworkChange = useCallback((event: React.ChangeEvent<HTMLSelectElement>) => {
const selectedNetwork = gatekeeperNetworks.find((network) => network.name === event.target.value);
console.log('Selected network:', selectedNetwork);
setSelectedGatekeeperNetwork(selectedNetwork || gatekeeperNetworks[0]);
}, []);

return (
<main>
<img src="/logo2.svg" alt="DFINITY logo" />
{principal && <h1>Welcome to the ICP Relying Canister</h1>}
{principal && <p>Logged in as {principal?.toText()}</p>}
{principal
? <ICPCredentialCheckButton principal={principal} gatekeeperNetwork={gatekeeperNetwork} onCredentialCheck={handleCredentialCheck} />
: urlCode ? <></> : <button onClick={handleLogin}>Login</button>}
{urlCode && <img src={'https://www.icegif.com/wp-content/uploads/2023/01/icegif-162.gif'} alt="Cool GIF for active status" style={{ width: '100px', height: '100px' }} />}
<main className="min-h-screen bg-gray-100 flex flex-col items-center justify-center p-4">
<div className="bg-white rounded-lg shadow-lg p-8 max-w-md w-full">
<img src="/logo2.svg" alt="DFINITY logo" className="mx-auto mb-8 w-32" />

{principal ? (
<div className="flex flex-col items-center justify-center">
<h1 className="text-2xl font-bold text-center mb-4">Welcome to the ICP Relying Canister</h1>
<p className="text-center mb-6">Logged in as <span className="font-mono bg-gray-100 p-1 rounded">{principal?.toText()}</span></p>
<ICPCredentialCheckButton
principal={principal}
gatekeeperNetwork={selectedGatekeeperNetwork.address}
onCredentialCheck={handleCredentialCheck}
config={{ stage: 'dev' }}
/>
</div>
) : (
<>
<h2 className="text-xl font-semibold mb-4">Select Gatekeeper Network</h2>
<div className="relative mb-6">
<select
id="gatekeeperNetwork"
value={selectedGatekeeperNetwork.name}
onChange={handleGatekeeperNetworkChange}
className="block appearance-none w-full bg-white border border-gray-300 text-gray-700 py-3 px-4 pr-8 rounded leading-tight focus:outline-none focus:bg-white focus:border-gray-500"
>
{gatekeeperNetworks.map((network) => (
<option key={network.name} value={network.name}>
{network.name}
</option>
))}
</select>
<div className="pointer-events-none absolute inset-y-0 right-0 flex items-center px-2 text-gray-700">
<ChevronDown size={20} />
</div>
</div>
{!urlCode && (
<button
onClick={handleLogin}
className="w-full bg-blue-500 hover:bg-blue-600 text-white font-bold py-2 px-4 rounded focus:outline-none focus:shadow-outline transition duration-300"
>
Login
</button>
)}
</>
)}

{urlCode && (
<div className="mt-6 text-center">
<img
src={'https://www.icegif.com/wp-content/uploads/2023/01/icegif-162.gif'}
alt="Cool GIF for active status"
className="w-24 h-24 mx-auto"
/>
<p className="mt-2 text-sm text-gray-600">Success!</p>
</div>
)}
</div>
</main>
);
}

export default App;
export default App;
9 changes: 7 additions & 2 deletions src/civic_sign_frontend_demo/src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,12 @@ const civicBackendCanisterUrl = !isDev


const portalUrl = `https://icp-getpass.civic.com`;
const gatekeeperNetwork = "ta136ftcpd8RyTYu3FGBjstD7EMXGBWrcwotdScrAKu";
export type GatekeeperNetwork = { name: string, address: string };
const gatekeeperNetworks = [
{ name: 'Age 13', address: 'ta136ftcpd8RyTYu3FGBjstD7EMXGBWrcwotdScrAKu', },
{ name: 'Uniqueness', address: 'tunQheuPpHhjjsbrUDp4rikqYez9UXv4SXLRHf9Kzsv', },
{ name: 'Captcha', address: 'tigoYhp9SpCDoCQmXGj2im5xa3mnjR1zuXrpCJ5ZRmi', },
];

// This is for demo purposes but should be replaced with a more secure method
const dummyCivicSampleKey = new Uint8Array([
Expand All @@ -33,5 +38,5 @@ export const config = {
internetIdentityCanisterId,
dummyCivicSampleKey,
portalUrl,
gatekeeperNetwork,
gatekeeperNetworks,
};
4 changes: 4 additions & 0 deletions src/civic_sign_frontend_demo/src/index.scss
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
@tailwind base;
@tailwind components;
@tailwind utilities;

body {
font-family: sans-serif;
font-size: 1.5rem;
Expand Down
9 changes: 9 additions & 0 deletions src/civic_sign_frontend_demo/tailwind.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
module.exports = {
content: [
"./src/**/*.{js,jsx,ts,tsx}",
],
theme: {
extend: {},
},
plugins: [],
}