Skip to content

Commit

Permalink
Merge master and fix conflicts
Browse files Browse the repository at this point in the history
  • Loading branch information
gkatrakazas committed Jan 14, 2025
2 parents 4bca103 + c6d4a78 commit d39cce6
Show file tree
Hide file tree
Showing 35 changed files with 406 additions and 303 deletions.
28 changes: 1 addition & 27 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -314,30 +314,4 @@ Explore the [Tailwind CSS documentation](https://tailwindcss.com/docs/installati

## 💡Contributing

We welcome contributions from the community to help improve the wwWallet Frontend repository. If you'd like to contribute, follow these steps:
1. **Create a New Branch:**
Create a new branch for your feature or bug fix
```bash
git checkout -b my-feature
```
Replace my-feature with a descriptive name.
2. **Make Changes:**
Make the necessary changes in your code editor.
3. **Commit Changes:**
Commit your changes with a descriptive commit message:
```bash
git commit -m "Add new feature"
```
4. **Push Changes:**
Push your changes to your new branrch:
```bash
git push --set-upstream origin my-feature
```
5. **Create a Pull Request:**
Open a pull request on the original repository. Provide a detailed description of your changes and their purpose.
6. **Review and Merge:**
Your pull request will be reviewed by the maintainers. Make any requested changes and address feedback. Once approved, your changes will be merged into master branch of the project.
Want to contribute? Check out our [Contribution Guidelines](https://github.com/wwWallet/.github/blob/main/CONTRIBUTING.md) for more details!
8 changes: 4 additions & 4 deletions src/UriHandler.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@ import React, { useEffect, useState, useContext } from "react";
import { useLocation } from "react-router-dom";
import { checkForUpdates } from './offlineRegistrationSW';
import StatusContext from "./context/StatusContext";
import { useOpenID4VCI } from "./lib/services/OpenID4VCI/OpenID4VCI";
import SessionContext from "./context/SessionContext";
import { BackgroundTasksContext } from "./context/BackgroundTasksContext";
import { useTranslation } from "react-i18next";
import { HandleAuthorizationRequestError } from "./lib/interfaces/IOpenID4VP";
import { useOpenID4VP } from "./lib/services/OpenID4VP/OpenID4VP";
import OpenID4VCIContext from "./context/OpenID4VCIContext";
import OpenID4VPContext from "./context/OpenID4VPContext";

const MessagePopup = React.lazy(() => import('./components/Popups/MessagePopup'));
const PinInputPopup = React.lazy(() => import('./components/Popups/PinInput'));
Expand All @@ -21,8 +21,8 @@ export const UriHandler = ({ children }) => {
const location = useLocation();
const [url, setUrl] = useState(window.location.href);

const openID4VCI = useOpenID4VCI();
const openID4VP = useOpenID4VP();
const { openID4VCI } = useContext(OpenID4VCIContext);
const { openID4VP } = useContext(OpenID4VPContext);

const [showPinInputPopup, setShowPinInputPopup] = useState<boolean>(false);

Expand Down
Binary file added src/assets/images/logo_christmas.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/assets/images/wallet_white_christmas.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 2 additions & 4 deletions src/components/Auth/LoginLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,14 @@ import React from 'react';
import { Trans, useTranslation } from 'react-i18next';

import * as config from '../../config';
import logo from '../../assets/images/logo.png';
import Logo from '../Logo/Logo';

export default function LoginLayout({ children, heading }: { children: React.ReactNode, heading: React.ReactNode }) {
const { t } = useTranslation();
return (
<section className="bg-gray-100 dark:bg-gray-900 min-h-dvh flex flex-col">
<div className="flex-grow flex flex-col items-center justify-center px-6 py-8">
<a href="/" className="flex justify-center mb-6 text-2xl font-semibold text-gray-900 dark:text-white">
<img className="w-40" src={logo} alt="logo" />
</a>
<Logo aClassName='mb-6' imgClassName='w-40' />

<h1 className="text-3xl mb-7 font-bold leading-tight tracking-tight text-gray-900 text-center dark:text-white">
{heading}
Expand Down
15 changes: 11 additions & 4 deletions src/components/ChristmasAnimation/Snowfalling.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,20 @@ const Snowfalling = () => {

useEffect(() => {
const checkSeason = () => {
const today = new Date();
const today = new Date(); // Use new Date() for real-time or new Date(new Date().getFullYear(), 0, 1) for testing January 1st
const currentYear = today.getFullYear();

const start = new Date(currentYear, 11, 20);
const end = new Date(currentYear + 1, 0, 6);
// Christmas season part 1: December 1st to December 20th of the current year
const christmasStart = new Date(currentYear, 11, 20); // December 20
const christmasEnd = new Date(currentYear, 11, 31); // December 31

return today >= start && today <= end;
// Christmas season part 2: January 1st to January 6th of the next year
const newYearStart = new Date(currentYear, 0, 1); // January 1
const newYearEnd = new Date(currentYear, 0, 6); // January 6

// Check if today is within either part of the Christmas season
return (today >= christmasStart && today <= christmasEnd) ||
(today >= newYearStart && today <= newYearEnd);
};

setIsChristmasSeason(checkSeason());
Expand Down
2 changes: 1 addition & 1 deletion src/components/Credentials/CredentialImage.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ const CredentialImage = ({ parsedCredential, className, onClick, showRibbon = tr
{parsedCredential && (
<img src={parsedCredential.credentialImage.credentialImageURL} alt={"Credential"} className={className} onClick={onClick} />
)}
{showRibbon &&
{parsedCredential && showRibbon &&
<ExpiredRibbon parsedCredential={parsedCredential} />
}
{vcEntityInstances && showRibbon &&
Expand Down
2 changes: 1 addition & 1 deletion src/components/Credentials/CredentialLayout.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ const CredentialLayout = ({ children, title = null }) => {
if (vcEntity) {
setZeroSigCount(vcEntity.instances.filter(instance => instance.sigCount === 0).length || 0);
setSigTotal(vcEntity.instances.length);
setIsExpired(CheckExpired(vcEntity.parsedCredential.beautifiedForm.expiry_date))
setIsExpired(CheckExpired(vcEntity.parsedCredential.beautifiedForm.expiry_date ?? vcEntity.parsedCredential.beautifiedForm.expiry_date))
setCredentialFriendlyName(vcEntity.parsedCredential.credentialFriendlyName);

}
Expand Down
4 changes: 2 additions & 2 deletions src/components/Credentials/ExpiredRibbon.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ const ExpiredRibbon = ({ parsedCredential }) => {

return (
<>
{parsedCredential && CheckExpired(parsedCredential.expiry_date) &&
<div className={`absolute bottom-0 right-0 text-white text-xs py-1 px-3 rounded-tl-lg rounded-br-2xl border-t border-l border-white ${CheckExpired(parsedCredential.expirationDate) ? 'bg-red-600' : 'bg-green-500'}`}>
{parsedCredential && CheckExpired(parsedCredential.exp ?? parsedCredential.expiry_date) &&
<div className={`absolute bottom-0 right-0 text-white text-xs py-1 px-3 rounded-tl-lg rounded-br-2xl border-t border-l border-white ${CheckExpired(parsedCredential.exp ?? parsedCredential.expiry_date) ? 'bg-red-600' : 'bg-green-500'}`}>
{t('expiredRibbon.expired')}
</div>
}
Expand Down
2 changes: 1 addition & 1 deletion src/components/Credentials/RenderCustomSvgTemplate.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ const renderCustomSvgTemplate = async ({ beautifiedForm, name, description, logo
.replace(/{{textColor}}/g, textColor)
.replace(/{{description}}/g, description);

const expiryDate = jsonpointer.get(beautifiedForm, "/expiry_date");
const expiryDate = jsonpointer.get(beautifiedForm, "/expiry_date") ?? new Date(jsonpointer.get(beautifiedForm, "/exp") * 1000).toISOString();
svgContent = svgContent.replace(/{{\/expiry_date}}/g, expiryDate ? `Expiry Date: ${formatDate(expiryDate, 'date')}` : '');

return `data:image/svg+xml;utf8,${encodeURIComponent(svgContent)}`;
Expand Down
5 changes: 4 additions & 1 deletion src/components/History/HistoryDetailContent.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,13 @@ import Slider from '../Shared/Slider';
import CredentialImage from '../Credentials/CredentialImage';
import CredentialInfo from '../Credentials/CredentialInfo';

import useScreenType from '../../hooks/useScreenType';

const HistoryDetailContent = ({ historyItem }) => {
const [currentSlide, setCurrentSlide] = React.useState(1);
const [parsedCredentials, setParsedCredentials] = useState([]);
const { parseCredential } = useContext(CredentialParserContext);
const screenType = useScreenType();

// Parse all the credentials when historyItem changes
useEffect(() => {
Expand Down Expand Up @@ -55,7 +58,7 @@ const HistoryDetailContent = ({ historyItem }) => {

{/* Render details of the currently selected credential */}
{parsedCredentials[currentSlide - 1] && (
<div className="pt-5">
<div className={`pt-5 ${screenType !== 'mobile' ? 'overflow-y-auto items-center custom-scrollbar max-h-[30vh]' : ''} `}>
<CredentialInfo parsedCredential={parsedCredentials[currentSlide - 1]} />
</div>
)}
Expand Down
13 changes: 1 addition & 12 deletions src/components/History/HistoryList.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import useScreenType from '../../hooks/useScreenType';
import { formatDate } from '../../functions/DateFormat';
import { H3 } from '../Shared/Heading';
import HistoryDetailPopup from '../Popups/HistoryDetailPopup';
import { fromBase64 } from '../../util';
import { extractPresentations } from '../../pages/History/HistoryDetail';

const HistoryList = ({ credentialId = null, history, title = '', limit = null }) => {

Expand All @@ -22,17 +22,6 @@ const HistoryList = ({ credentialId = null, history, title = '', limit = null })
}, [history, credentialId, limit]);

const handleHistoryItemClick = async (item) => {
const extractPresentations = (item) => {
if (item.presentation.startsWith("b64:") && (new TextDecoder().decode(fromBase64(item.presentation.replace("b64:", "")))).includes("[")) {
return JSON.parse(new TextDecoder().decode(fromBase64(item.presentation.replace("b64:", ""))));
}
else if (item.presentation.startsWith("b64:")) {
return [ new TextDecoder().decode(fromBase64(item.presentation.replace("b64:", ""))) ];
}
else {
return [ item.presentation ];
}
}
setMatchingCredentials(extractPresentations(item));
if (screenType === 'mobile') {
navigate(`/history/${item.id}`);
Expand Down
21 changes: 2 additions & 19 deletions src/components/Layout/Header.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
import React, { useState, useEffect } from 'react';
import { useNavigate, useLocation } from 'react-router-dom';
import { useTranslation } from 'react-i18next';
import ConnectionStatusIcon from './Navigation/ConnectionStatusIcon';
import logo from '../../assets/images/wallet_white.png';
import Logo from '../Logo/Logo';

const Header = () => {
const navigate = useNavigate();
const location = useLocation();
const { t } = useTranslation();
const [isScrolled, setIsScrolled] = useState(false);

Expand All @@ -26,25 +23,11 @@ const Header = () => {
};
}, [isScrolled]);

const handleNavigate = (path) => {
if (location.pathname === path) {
window.location.reload();
} else {
navigate(path);
}
};

return (
<header className={`sticky top-0 z-50 w-full bg-primary dark:bg-primary-hover text-white flex items-center justify-between shadow-md md:hidden rounded-b-lg transition-all duration-300 ${isScrolled ? 'p-3' : 'p-4'}`}>
<ConnectionStatusIcon size={isScrolled ? 'small' : 'normal'} className="transition-all duration-300" />
<div className="flex items-center">
<button className='mr-2' onClick={() => handleNavigate('/')}>
<img
src={logo}
alt="Logo"
className={`cursor-pointer transition-all duration-300 ${isScrolled ? 'w-7' : 'w-10'}`}
/>
</button>
<Logo type='white' aClassName='mr-2' imgClassName={`cursor-pointer transition-all duration-300 ${isScrolled ? 'w-7' : 'w-10'}`} />
<a href="/" className={`text-white font-bold cursor-pointer transition-all duration-300 ${isScrolled ? 'text-sm' : 'text-xl'}`}>
{t('common.walletName')}
</a>
Expand Down
14 changes: 3 additions & 11 deletions src/components/Layout/Navigation/Sidebar.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { FaWallet, FaUserCircle } from "react-icons/fa";
import { IoIosTime, IoIosAddCircle, IoIosSend, IoMdSettings } from "react-icons/io";
import { useLocation, useNavigate } from 'react-router-dom';
import useScreenType from '../../../hooks/useScreenType';
import logo from '../../../assets/images/wallet_white.png';
import Logo from '../../Logo/Logo';
import { Trans, useTranslation } from 'react-i18next';
import StatusContext from '../../../context/StatusContext';
import SessionContext from '../../../context/SessionContext';
Expand Down Expand Up @@ -65,9 +65,7 @@ const Sidebar = ({ isOpen, toggle }) => {
<div style={{ display: 'flex', flexDirection: 'column' }} className="flex flex-col space-between">
<div className="md:hidden flex items-center justify-between mb-4">
<div className='flex items-center'>
<button className='mr-2' onClick={() => handleNavigate('/')}>
<img src={logo} alt="Logo" className="w-10 h-auto cursor-pointer" />
</button>
<Logo type='white' aClassName='mr-2' imgClassName='w-10 h-auto' />
<a href={('/')}
className="text-white text-xl font-bold cursor-pointer"
>
Expand All @@ -77,13 +75,7 @@ const Sidebar = ({ isOpen, toggle }) => {
</div>
<div>
<div className="hidden md:flex justify-between items-center">
<button className='mb-2 mr-2' onClick={() => handleNavigate('/')}>
<img
src={logo}
alt="Logo"
className="w-20 h-22 cursor-pointer"
/>
</button>
<Logo type='white' aClassName='mb-2 mr-2' imgClassName='w-20 h-22' />
<a href={('/')}
className="text-white text-xl font-bold cursor-pointer"
>
Expand Down
59 changes: 59 additions & 0 deletions src/components/Logo/Logo.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import React, { useEffect, useState } from 'react';
import logoClassic from '../../assets/images/logo.png';
import logoWhite from '../../assets/images/wallet_white.png';
import logoClassicChristmas from '../../assets/images/logo_christmas.png';
import logoWhiteChristmas from '../../assets/images/wallet_white_christmas.png';
import { useTranslation } from 'react-i18next';

interface LogoProps {
type?: string; // Determines the type of logo (classic or white)
aClassName?: string; // Class for the <a> element
imgClassName?: string; // Class for the <img> element
}

const Logo: React.FC<LogoProps> = ({
type = 'classic',
aClassName = '',
imgClassName = '',
}) => {
const [isChristmasSeason, setIsChristmasSeason] = useState(false);
const { t } = useTranslation();

useEffect(() => {
const checkSeason = () => {
const today = new Date(); // Use new Date() for real-time or new Date(new Date().getFullYear(), 0, 1) for testing January 1st
const currentYear = today.getFullYear();

// Christmas season part 1: December 1st to December 31st of the current year
const christmasStart = new Date(currentYear, 11, 1); // December 1
const christmasEnd = new Date(currentYear, 11, 31); // December 31

// Christmas season part 2: January 1st to January 2nd of the next year
const newYearStart = new Date(currentYear, 0, 1); // January 1
const newYearEnd = new Date(currentYear, 0, 2); // January 2

// Check if today is within either part of the Christmas season
return (today >= christmasStart && today <= christmasEnd) ||
(today >= newYearStart && today <= newYearEnd);
};

const seasonActive = checkSeason();
setIsChristmasSeason(seasonActive);
}, []);

// Determine which logo to use
const logoSrc = (() => {
if (isChristmasSeason) {
return type === 'white' ? logoWhiteChristmas : logoClassicChristmas;
}
return type === 'white' ? logoWhite : logoClassic;
})();

return (
<a href="/" className={aClassName} aria-label={t('common.walletName')}>
<img src={logoSrc} alt={t('common.walletName')} className={imgClassName} />
</a>
);
};

export default Logo;
13 changes: 8 additions & 5 deletions src/components/Notifications/HandlerNotification.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import React, { useState, useEffect, useCallback } from 'react';
import React, { useState, useEffect, useCallback, useContext } from 'react';
import toast, { Toaster } from 'react-hot-toast';
import { onMessageListener } from '../../firebase';
import { AiOutlineClose } from 'react-icons/ai';
import logo from '../../assets/images/logo.png';
import Logo from '../Logo/Logo';
import CredentialsContext from '../../context/CredentialsContext';

const ToastDisplay = ({ id, notification }) => {
return (
Expand All @@ -11,7 +12,7 @@ const ToastDisplay = ({ id, notification }) => {
onClick={() => window.location.href = '/'}
>
<div className="w-1/3 flex items-center justify-start mr-6">
<img src={logo} alt="Logo" className="" />
<Logo />
</div>
<div className="flex-grow text-center">
<p className="font-bold text-lg">{notification?.title}</p>
Expand All @@ -31,6 +32,7 @@ const ToastDisplay = ({ id, notification }) => {

const HandlerNotification = () => {
const [notification, setNotification] = useState({ title: '', body: '' });
const { getData } = useContext(CredentialsContext);

const showToast = useCallback(
() => toast((t) => <ToastDisplay id={t.id} notification={notification} />),
Expand All @@ -50,6 +52,7 @@ const HandlerNotification = () => {
title: payload?.notification?.title,
body: payload?.notification?.body,
});
getData();
})
.catch((err) => {
console.log('Failed to receive message:', err);
Expand All @@ -60,10 +63,10 @@ const HandlerNotification = () => {
messageListener();
}
};
}, []);
}, [getData]);

return (
<Toaster />
<Toaster />
);
};

Expand Down
1 change: 0 additions & 1 deletion src/context/ContainerContext.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import React, { createContext } from "react";
import { withOpenID4VPContext } from "./OpenID4VPContext";
import { withCredentialParserContext } from "./CredentialParserContext";

export type ContainerContextValue = {}
Expand Down
2 changes: 1 addition & 1 deletion src/context/CredentialParserContext.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { createContext, useEffect, useMemo, useCallback, useContext } from "react";
import React, { createContext, useEffect, useMemo, useCallback } from "react";
import { ICredentialParser, ICredentialParserRegistry } from "../lib/interfaces/ICredentialParser";
import { useCredentialParserRegistry } from "../lib/services/CredentialParserRegistry";
import { parseSdJwtCredential } from "../functions/parseSdJwtCredential";
Expand Down
Loading

0 comments on commit d39cce6

Please sign in to comment.