Skip to content

Commit

Permalink
Merge pull request #17 from The-Timeless-Tutor/dev
Browse files Browse the repository at this point in the history
feat:glassomorphism added on import wallet.
  • Loading branch information
13x54n authored Apr 28, 2024
2 parents af087fd + 23deeca commit 65457db
Show file tree
Hide file tree
Showing 10 changed files with 153 additions and 47 deletions.
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,15 @@
"@emotion/react": "^11.11.1",
"@emotion/styled": "^11.11.0",
"@faker-js/faker": "^8.1.0",
"@headlessui/react": "^1.7.19",
"@heroicons/react": "^2.1.3",
"@iconify/react": "^4.1.1",
"@mui/lab": "^5.0.0-alpha.147",
"@mui/material": "^5.14.12",
"apexcharts": "^3.43.0",
"clsx": "^2.1.1",
"date-fns": "^2.30.0",
"ethers": "^6.12.0",
"framer-motion": "^11.1.7",
"history": "^5.3.0",
"lodash": "^4.17.21",
Expand Down
2 changes: 1 addition & 1 deletion src/components/evervault-card/evervault-card.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ export const CardItem = ({
};

return (
<Tag ref={ref} className={`w-fit transition duration-200 ease-linear ${className}`} {...rest}>
<Tag ref={ref} className={`w-[100%] transition duration-200 ease-linear ${className}`} {...rest}>
{children}
</Tag>
);
Expand Down
78 changes: 78 additions & 0 deletions src/components/import-wallet/import-wallet.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import { Fragment, useRef } from 'react'
import { Dialog, Transition } from '@headlessui/react'
import { ExclamationTriangleIcon } from '@heroicons/react/24/outline'
import './styles/style.css'

export default function ImportWallet({open, setOpen}) {
const cancelButtonRef = useRef(null)

return (
<Transition.Root show={open} as={Fragment}>
<Dialog as="div" className="relative z-[1101]" initialFocus={cancelButtonRef} onClose={setOpen}>
<Transition.Child
as={Fragment}
enter="ease-in-out duration-400"
enterFrom="opacity-0"
enterTo="opacity-100"
leave="ease-in-out duration-400"
leaveFrom="opacity-100"
leaveTo="opacity-0"
>
<div className="fixed inset-0 bg-gray-500 bg-opacity-75 transition-opacity importWalletModal__container__glassEffect" />
</Transition.Child>

<div className="fixed inset-0 z-10 w-screen overflow-y-auto">
<div className="flex min-h-full items-end justify-center p-4 text-center sm:items-center sm:p-0">
<Transition.Child
as={Fragment}
enter="ease-out duration-300"
enterFrom="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
enterTo="opacity-100 translate-y-0 sm:scale-100"
leave="ease-in duration-200"
leaveFrom="opacity-100 translate-y-0 sm:scale-100"
leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
>
<Dialog.Panel className="relative transform overflow-hidden rounded-lg bg-white text-left shadow-xl transition-all sm:my-8 sm:w-full sm:max-w-lg">
<div className="bg-white px-4 pb-4 pt-5 sm:p-6 sm:pb-4">
<div className="sm:flex sm:items-start">
<div className="mx-auto flex h-12 w-12 flex-shrink-0 items-center justify-center rounded-full bg-red-100 sm:mx-0 sm:h-10 sm:w-10">
<ExclamationTriangleIcon className="h-6 w-6 text-red-600" aria-hidden="true" />
</div>
<div className="mt-3 text-center sm:ml-4 sm:mt-0 sm:text-left">
<Dialog.Title as="h3" className="text-base font-semibold leading-6 text-gray-900">
Deactivate account
</Dialog.Title>
<div className="mt-2">
<p className="text-sm text-gray-500">
Are you sure you want to deactivate your account? All of your data will be permanently
removed. This action cannot be undone.
</p>
</div>
</div>
</div>
</div>
<div className="bg-gray-50 px-4 py-3 sm:flex sm:flex-row-reverse sm:px-6">
<button
type="button"
className="inline-flex w-full justify-center rounded-md bg-red-600 px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-red-500 sm:ml-3 sm:w-auto"
onClick={() => setOpen(false)}
>
Deactivate
</button>
<button
type="button"
className="mt-3 inline-flex w-full justify-center rounded-md bg-white px-3 py-2 text-sm font-semibold text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 hover:bg-gray-50 sm:mt-0 sm:w-auto"
onClick={() => setOpen(false)}
ref={cancelButtonRef}
>
Cancel
</button>
</div>
</Dialog.Panel>
</Transition.Child>
</div>
</div>
</Dialog>
</Transition.Root>
)
}
1 change: 1 addition & 0 deletions src/components/import-wallet/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from './import-wallet';
8 changes: 8 additions & 0 deletions src/components/import-wallet/styles/style.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
.importWalletModal__container__glassEffect {
/* From https://css.glass */
background: rgba(255, 255, 255, 0.1);
border-radius: 16px;
box-shadow: 0 4px 30px rgba(0, 0, 0, 0.1);
backdrop-filter: blur(8.7px);
-webkit-backdrop-filter: blur(8.7px);
}/*# sourceMappingURL=style.css.map */
1 change: 1 addition & 0 deletions src/components/import-wallet/styles/style.css.map

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

8 changes: 8 additions & 0 deletions src/components/import-wallet/styles/style.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
.importWalletModal__container__glassEffect {
/* From https://css.glass */
background: rgba(255, 255, 255, 0.1);
border-radius: 16px;
box-shadow: 0 4px 30px rgba(0, 0, 0, 0.1);
backdrop-filter: blur(8.7px);
-webkit-backdrop-filter: blur(8.7px);
}
25 changes: 13 additions & 12 deletions src/middleware/apiMiddleware.js
Original file line number Diff line number Diff line change
@@ -1,27 +1,28 @@
import { refreshToken, getSession, isTokenExpired } from '../utils/authUtils';
import { getSession, refreshToken, isTokenExpired } from '../utils/authUtils';

export const apiMiddleware = async (endpoint, options = {}) => {
const backendUrl = process.env.REACT_APP_BACKEND_URL || "https://backend-service-rojjrgeqna-ue.a.run.app/";
let url = new URL(endpoint, backendUrl);
const backendUrl =
process.env.REACT_APP_BACKEND_URL || 'https://backend-service-rojjrgeqna-ue.a.run.app/';
const url = new URL(endpoint, backendUrl);

// Ensure options.headers is an object
options.headers = options.headers || {};

// Append query parameters if present
if (options.params) {
Object.keys(options.params).forEach(key => url.searchParams.append(key, options.params[key]));
Object.keys(options.params).forEach((key) => url.searchParams.append(key, options.params[key]));
}

// Handle token in headers
const session = getSession();
if (session.accessToken && isTokenExpired(session.accessTokenExpiry)) {
const success = await refreshAccessToken(backendUrl);
if (!success) throw new Error("Failed to refresh token. Please log in again.");
if (!success) throw new Error('Failed to refresh token. Please log in again.');
}

// Set Authorization header if access token is valid
if (session.accessToken) {
options.headers['Authorization'] = `Bearer ${session.accessToken}`;
options.headers.Authorization = `Bearer ${session.accessToken}`;
}

// Execute the request
Expand All @@ -30,13 +31,13 @@ export const apiMiddleware = async (endpoint, options = {}) => {
// Retry once if the first attempt fails due to an expired token
if (response.status === 401) {
const success = await refreshAccessToken(backendUrl);
if (!success) throw new Error("Failed to refresh token on retry. Please log in again.");
if (!success) throw new Error('Failed to refresh token on retry. Please log in again.');

// Refresh the session details after successful token refresh
const newSession = getSession();
options.headers['Authorization'] = `Bearer ${newSession.accessToken}`;
options.headers.Authorization = `Bearer ${newSession.accessToken}`;
// Retry the fetch with the new token
response = await fetch(url, options);
response = await fetch(url, options);
}

return response;
Expand All @@ -45,9 +46,9 @@ export const apiMiddleware = async (endpoint, options = {}) => {
async function refreshAccessToken(backendUrl) {
try {
// Assume refreshToken returns true on success
return await refreshToken(backendUrl);
return await refreshToken(backendUrl);
} catch (error) {
console.error("Error refreshing token:", error);
return false;
console.error('Error refreshing token:', error);
return false;
}
}
30 changes: 18 additions & 12 deletions src/sections/web3/view/web3-view.jsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
import { Container, Stack, Typography } from '@mui/material';
import React from 'react';
import React, { useState } from 'react';
import { CardBody, CardContainer, CardItem } from 'src/components/evervault-card/evervault-card';
import ImportWallet from 'src/components/import-wallet';

export default function Web3Page() {
const [isImportWalletModalOpen, setIsImportWalletModalOpen] = useState(false)
return (
<Container>
{
isImportWalletModalOpen && <ImportWallet open={isImportWalletModalOpen} setOpen={setIsImportWalletModalOpen}/>
}
<div style={{ display: 'flex', gap: 4 }}>
<Typography variant="h2">🌍</Typography>
<Stack direction="column" mb={3}>
Expand All @@ -13,9 +18,9 @@ export default function Web3Page() {
</Stack>
</div>

<div className='flex gap-4'>
<CardContainer className="inter-var">
<CardBody className="bg-gray-50 relative group/card border-black/[0.1] w-auto sm:w-[25rem] h-auto rounded-xl p-6 border ">
<div className='flex gap-4 flex-wrap items-start'>
<CardContainer className="inter-var w-[100%]">
<CardBody className="bg-gray-50 relative group/card border-black/[0.1] w-[100%] h-auto rounded-xl p-6 border ">
<CardItem translateZ="50" className="text-xl font-bold text-neutral-600">
💵 Import Wallet
</CardItem>
Expand All @@ -31,28 +36,29 @@ export default function Web3Page() {
alt="thumbnail"
/>
</CardItem>
<div className="flex justify-between items-center mt-5">
<div className="flex justify-between items-center mt-5 flex-wrap gap-3">
<CardItem
translateZ={20}
as="button"
className="px-4 py-2 rounded-xl bg-black text-white text-xs font-bold"
className="px-4 py-2 rounded-xl bg-black text-white text-xs font-bold cursor-pointer"
onClick={() => setIsImportWalletModalOpen(true)}
>
Import Account using Private Key
Import using Private Key
</CardItem>
<CardItem
translateZ={20}
as="a"
href="https://twitter.com/mannupaaji"
target="__blank"
className="px-4 py-2 rounded-xl text-xs font-normal"
className="px-4 py-2 rounded-xl text-xs font-bold bg-[#0001] text-center"
>
Learn More →
</CardItem>
</div>
</CardBody>
</CardContainer>
<CardContainer className="inter-var">
<CardBody className="bg-gray-50 relative group/card border-black/[0.1] w-auto sm:w-[25rem] h-auto rounded-xl p-6 border ">
<CardContainer className="inter-var w-[100%]">
<CardBody className="bg-gray-50 relative group/card border-black/[0.1] w-[100%] h-auto rounded-xl p-6 border ">
<CardItem translateZ="50" className="text-xl font-bold text-neutral-600">
🪛 Create Wallet
</CardItem>
Expand All @@ -68,7 +74,7 @@ export default function Web3Page() {
alt="thumbnail"
/>
</CardItem>
<div className="flex justify-between items-center mt-5">
<div className="flex justify-between items-center mt-5 flex-wrap gap-3">
<CardItem
translateZ={20}
as="button"
Expand All @@ -81,7 +87,7 @@ export default function Web3Page() {
as="a"
href="https://twitter.com/mannupaaji"
target="__blank"
className="px-4 py-2 rounded-xl text-xs font-normal"
className="px-4 py-2 rounded-xl text-xs font-bold bg-[#0001] text-center"
>
Learn More →
</CardItem>
Expand Down
44 changes: 22 additions & 22 deletions src/utils/authUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,39 +30,39 @@ export const getSession = () => ({
});

// Attempts to refresh the access token using the refresh token
export const refreshToken = async (backendUrl) => {
export const refreshTokens = async (backendUrl) => {
const { refreshToken, refreshTokenExpiry } = getSession();

// Check if the refresh token is valid
if (!refreshToken || new Date() >= new Date(refreshTokenExpiry)) {
clearSession();
throw new Error('Refresh token is expired or not available. Please log in again.');
clearSession();
throw new Error('Refresh token is expired or not available. Please log in again.');
}

try {
const response = await fetch(`${backendUrl}api/token_refresh`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ refresh_token: refreshToken }),
});
const response = await fetch(`${backendUrl}api/token_refresh`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ refresh_token: refreshToken }),
});

if (!response.ok) {
throw new Error('Failed to refresh access token');
}
if (!response.ok) {
throw new Error('Failed to refresh access token');
}

const data = await response.json();
const data = await response.json();

setSession({
access_token: data.data.access_token,
refresh_token: data.data.refresh_token, // Use new refresh token if provided
access_token_expiry: data.data.access_token_expiry,
refresh_token_expiry: data.data.refresh_token_expiry || refreshTokenExpiry, // Use existing expiry if new one isn't provided
});
setSession({
access_token: data.data.access_token,
refresh_token: data.data.refresh_token, // Use new refresh token if provided
access_token_expiry: data.data.access_token_expiry,
refresh_token_expiry: data.data.refresh_token_expiry || refreshTokenExpiry, // Use existing expiry if new one isn't provided
});

return data.data.access_token; // Return the new access token
return data.data.access_token; // Return the new access token
} catch (error) {
console.error('Error refreshing token:', error);
clearSession(); // Clear session on failure
throw error; // Re-throw the error for handling elsewhere
console.error('Error refreshing token:', error);
clearSession(); // Clear session on failure
throw error; // Re-throw the error for handling elsewhere
}
};

0 comments on commit 65457db

Please sign in to comment.