diff --git a/src/common/backend/payments/index.ts b/src/common/backend/payments/index.ts
index 7709da9b..62da3e77 100644
--- a/src/common/backend/payments/index.ts
+++ b/src/common/backend/payments/index.ts
@@ -49,7 +49,6 @@ export type {
ServiceProviderMetadataField,
ServiceProviderMetadataForm,
PaymentSessionInfoMetadata,
- ServiceProviderIconMetadata,
MetadataTextLocalization,
ServiceProviderMetadataSelect,
ServiceProviderTitleMetadata,
diff --git a/src/common/backend/payments/serviceProviderMetadata.ts b/src/common/backend/payments/serviceProviderMetadata.ts
index a7794825..da86600d 100644
--- a/src/common/backend/payments/serviceProviderMetadata.ts
+++ b/src/common/backend/payments/serviceProviderMetadata.ts
@@ -41,12 +41,20 @@ export type ServiceProviderMetadataSelect = {
index?: number;
};
-export type ServiceProviderIconMetadata = {
+export type ServiceProviderMetadataImage = {
+ type?: 'image';
src: string;
width: string;
height: string;
};
+export type ServiceProviderMetadataBuildInIcon = {
+ type: 'buildInIcon';
+ name: 'HiCreditCard' | 'HiCash' | 'HiLibrary';
+};
+
+export type ServiceProviderMetadataLogo = ServiceProviderMetadataImage | ServiceProviderMetadataBuildInIcon;
+
export type ServiceProviderTitleMetadata = {
icon: 'wallets' | 'online-banking' | 'bank-card';
localization?: MetadataTextLocalization;
@@ -87,7 +95,7 @@ export type Addon = PinikleAddon;
export type CheckoutServiceProviderMetadata = {
form?: ServiceProviderMetadataForm;
- logo?: ServiceProviderIconMetadata;
+ logo?: ServiceProviderMetadataLogo;
title?: ServiceProviderTitleMetadata;
contactInfo?: ServiceProviderContactInfo;
userInteraction?: UserInteractionMetadata;
diff --git a/src/common/components/Pane/Pane.tsx b/src/common/components/Pane/Pane.tsx
index a2d01dee..ac177ab3 100644
--- a/src/common/components/Pane/Pane.tsx
+++ b/src/common/components/Pane/Pane.tsx
@@ -14,7 +14,7 @@ export function Pane(props: PaneProps) {
borderColor="chakra-border-color"
borderRadius="lg"
cursor="pointer"
- p={2}
+ p={4}
spacing={2}
{...rest}
>
diff --git a/src/common/components/Pane/PaneLogoBox.tsx b/src/common/components/Pane/PaneLogoBox.tsx
index 08ebdaca..699890af 100644
--- a/src/common/components/Pane/PaneLogoBox.tsx
+++ b/src/common/components/Pane/PaneLogoBox.tsx
@@ -2,7 +2,7 @@ import { Center, CenterProps, useColorModeValue } from '@chakra-ui/react';
export function PaneLogoBox(props: CenterProps) {
const { children, ...rest } = props;
- const bgColor = useColorModeValue('white', 'gray.100');
+ const bgColor = useColorModeValue('white', 'gray.200');
return (
diff --git a/src/common/components/Pane/PaneMetadataBuildInIcon.tsx b/src/common/components/Pane/PaneMetadataBuildInIcon.tsx
new file mode 100644
index 00000000..e28d799f
--- /dev/null
+++ b/src/common/components/Pane/PaneMetadataBuildInIcon.tsx
@@ -0,0 +1,29 @@
+import { HiCash, HiCreditCard, HiLibrary, HiQuestionMarkCircle } from 'react-icons/hi';
+
+import { ServiceProviderMetadataBuildInIcon } from 'checkout/backend/payments/serviceProviderMetadata';
+import { isNil } from 'checkout/utils';
+
+import { PaneLogo } from './PaneLogo';
+
+export type PaneMetadataBuildInIconProps = {
+ logo: ServiceProviderMetadataBuildInIcon;
+};
+
+export function PaneMetadataBuildInIcon({ logo: { name } }: PaneMetadataBuildInIconProps) {
+ const buildInIcons = {
+ HiCreditCard: HiCreditCard,
+ HiCash: HiCash,
+ HiLibrary: HiLibrary,
+ };
+ const icon = buildInIcons[name];
+
+ if (isNil(icon)) {
+ console.error(
+ `Build in icon: ${name} is not found. Supported icon list: [${Object.keys(
+ buildInIcons,
+ )}]. Default icon will be used.`,
+ );
+ }
+
+ return ;
+}
diff --git a/src/common/components/Pane/PaneMetadataImageLogo.tsx b/src/common/components/Pane/PaneMetadataImageLogo.tsx
new file mode 100644
index 00000000..2d6f22d7
--- /dev/null
+++ b/src/common/components/Pane/PaneMetadataImageLogo.tsx
@@ -0,0 +1,10 @@
+import { ImageProps, Image } from '@chakra-ui/react';
+
+import { ServiceProviderMetadataImage } from 'checkout/backend/payments/serviceProviderMetadata';
+
+export type PaneMetadataImageLogoProps = { logo: ServiceProviderMetadataImage } & ImageProps;
+
+export function PaneMetadataImageLogo(props: PaneMetadataImageLogoProps) {
+ const { logo, ...rest } = props;
+ return ;
+}
diff --git a/src/common/components/Pane/PaneMetadataLogo.tsx b/src/common/components/Pane/PaneMetadataLogo.tsx
index 6691d687..52904903 100644
--- a/src/common/components/Pane/PaneMetadataLogo.tsx
+++ b/src/common/components/Pane/PaneMetadataLogo.tsx
@@ -1,10 +1,47 @@
-import { ImageProps, Image } from '@chakra-ui/react';
+import { useMemo } from 'react';
+import { HiQuestionMarkCircle } from 'react-icons/hi';
-import { ServiceProviderIconMetadata } from 'checkout/backend/payments/serviceProviderMetadata';
+import {
+ ServiceProviderMetadataImage,
+ ServiceProviderMetadataLogo,
+} from 'checkout/backend/payments/serviceProviderMetadata';
+import { isNil } from 'checkout/utils';
-export type PaneMetadataLogoProps = { logo: ServiceProviderIconMetadata } & ImageProps;
+import { PaneLogo } from './PaneLogo';
+import { PaneMetadataBuildInIcon } from './PaneMetadataBuildInIcon';
+import { PaneMetadataImageLogo } from './PaneMetadataImageLogo';
-export function PaneMetadataLogo(props: PaneMetadataLogoProps) {
- const { logo, ...rest } = props;
- return ;
+export type PaneMetadataLogoProps = {
+ logo: ServiceProviderMetadataLogo;
+};
+
+const isServiceProviderMetadataImage = (logo: ServiceProviderMetadataLogo): logo is ServiceProviderMetadataImage => {
+ return isNil(logo.type) || logo.type === 'image';
+};
+
+export function PaneMetadataLogo({ logo }: PaneMetadataLogoProps) {
+ const metadataLogo = useMemo(() => {
+ if (isServiceProviderMetadataImage(logo)) {
+ const requiredImage: Required = {
+ ...logo,
+ type: 'image',
+ };
+ return requiredImage;
+ }
+ if (logo.type === 'buildInIcon') {
+ return logo;
+ }
+ console.error('ServiceProvider metadata logo is unsupported', logo);
+ return null;
+ }, [logo]);
+
+ return (
+ <>
+ {isNil(metadataLogo) && }
+ {!isNil(metadataLogo) && metadataLogo.type === 'image' && }
+ {!isNil(metadataLogo) && metadataLogo.type === 'buildInIcon' && (
+
+ )}
+ >
+ );
}
diff --git a/src/common/components/Pane/index.ts b/src/common/components/Pane/index.ts
index 35e75f2c..20e35046 100644
--- a/src/common/components/Pane/index.ts
+++ b/src/common/components/Pane/index.ts
@@ -3,5 +3,7 @@ export { PaneText } from './PaneText';
export { PaneLogoBox } from './PaneLogoBox';
export { PaneLogo } from './PaneLogo';
export { PaneMetadataLogo } from './PaneMetadataLogo';
+export { PaneMetadataImageLogo } from './PaneMetadataImageLogo';
export type { PaneMetadataLogoProps } from './PaneMetadataLogo';
+export type { PaneMetadataImageLogoProps } from './PaneMetadataImageLogo';
diff --git a/src/common/components/index.ts b/src/common/components/index.ts
index 1f46bfc8..db50c87a 100644
--- a/src/common/components/index.ts
+++ b/src/common/components/index.ts
@@ -1,8 +1,8 @@
export { ErrorAlert } from './ErrorAlert';
export { BackwardBox } from './BackwardBox';
export { GlobalSpinner } from './GlobalSpinner';
-export { Pane, PaneLogo, PaneLogoBox, PaneText, PaneMetadataLogo } from './Pane';
+export { Pane, PaneLogo, PaneLogoBox, PaneText, PaneMetadataLogo, PaneMetadataImageLogo } from './Pane';
export { StatusInputRightElement } from './StatusInputRightElement';
-export type { PaneMetadataLogoProps } from './Pane';
+export type { PaneMetadataImageLogoProps, PaneMetadataLogoProps } from './Pane';
export type { StatusInputRightElementProps } from './StatusInputRightElement';
diff --git a/src/common/utils/index.ts b/src/common/utils/index.ts
index 999cdfc0..c679e9c1 100644
--- a/src/common/utils/index.ts
+++ b/src/common/utils/index.ts
@@ -32,7 +32,6 @@ export { detectLocale } from './detectLocale';
export { createRegExpForMetaPattern } from './createRegExpForMetaPattern';
export { formatCard } from './formatCard';
export { truncate } from './truncate';
-export { isEmojiSupported } from './isEmojiSupported';
export type { URLParams } from './getUrlParams';
export type { CountrySubdivision, Country } from './countries';
diff --git a/src/common/utils/isEmojiSupported.test.ts b/src/common/utils/isEmojiSupported.test.ts
deleted file mode 100644
index 24e0e331..00000000
--- a/src/common/utils/isEmojiSupported.test.ts
+++ /dev/null
@@ -1,51 +0,0 @@
-import { isEmojiSupported } from './isEmojiSupported';
-
-describe('isEmojiSupported', () => {
- let ctx;
-
- beforeEach(() => {
- // Mock the canvas context
- ctx = {
- fillStyle: '',
- fillRect: jest.fn(),
- textBaseline: '',
- font: '',
- fillText: jest.fn(),
- getImageData: jest.fn(),
- };
- // Setup to return a fake image data array
- ctx.getImageData.mockReturnValue({
- data: new Uint8ClampedArray(32 * 32 * 4).fill(0), // All pixels transparent
- });
- // Mock canvas creation
- document.createElement = jest.fn().mockReturnValue({
- getContext: () => ctx,
- width: 32,
- height: 32,
- });
- });
-
- test('should detect supported emoji by checking non-transparent pixels', () => {
- // Mocking the context to simulate an emoji being supported (non-transparent pixels)
- ctx.getImageData.mockReturnValue({
- data: new Uint8ClampedArray(32 * 32 * 4).fill(255), // All pixels non-transparent
- });
-
- expect(isEmojiSupported('π')).toBe(true);
- });
-
- test('should detect unsupported emoji by checking all transparent pixels', () => {
- // Using the initial all-transparent setup by default
-
- expect(isEmojiSupported('π')).toBe(false);
- });
-
- test('should handle null canvas context gracefully', () => {
- // Simulate canvas context not being available
- (document.createElement as any).mockReturnValue({
- getContext: () => null,
- });
-
- expect(isEmojiSupported('π')).toBe(false);
- });
-});
diff --git a/src/common/utils/isEmojiSupported.ts b/src/common/utils/isEmojiSupported.ts
deleted file mode 100644
index a424cf0c..00000000
--- a/src/common/utils/isEmojiSupported.ts
+++ /dev/null
@@ -1,37 +0,0 @@
-import { isNil } from './isNil';
-
-// Tests flag emoji
-export function isEmojiSupported(emoji: string): boolean {
- if (isNil(emoji)) {
- return false;
- }
- const canvas = document.createElement('canvas');
- canvas.width = canvas.height = 32; // The size should be large enough to hold the emoji
- const ctx = canvas.getContext('2d');
- if (!ctx) {
- return false; // In case the browser doesn't support canvas
- }
-
- ctx.fillStyle = 'white'; // Background color
- ctx.fillRect(0, 0, 32, 32); // Fill the background
- ctx.textBaseline = 'top';
- ctx.font = '32px Arial'; // A common font that may not support the emoji
-
- ctx.fillText(emoji, 0, 0); // Draw the emoji on the canvas
-
- const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height).data;
-
- let isSupported = false;
-
- // Loop through pixel data; every four items in the array represent the RGBA values of a pixel
- for (let i = 0; i < imageData.length; i += 4) {
- const alpha = imageData[i + 3]; // Get the alpha value of the pixel
- if (alpha > 0) {
- // Check if the pixel is not completely transparent
- isSupported = true;
- break;
- }
- }
-
- return isSupported;
-}
diff --git a/src/components/ViewContainer/LocaleSelector.tsx b/src/components/ViewContainer/LocaleSelector.tsx
index c58566e2..c546e689 100644
--- a/src/components/ViewContainer/LocaleSelector.tsx
+++ b/src/components/ViewContainer/LocaleSelector.tsx
@@ -1,9 +1,7 @@
import { Flex, Menu, MenuButton, MenuItem, MenuList, Text } from '@chakra-ui/react';
-import { useMemo, useState } from 'react';
+import { useState } from 'react';
import { HiChevronDown } from 'react-icons/hi';
-import { isEmojiSupported } from 'checkout/utils';
-
const localeInfo = {
ar: {
flag: 'πΈπ¦',
@@ -59,17 +57,14 @@ export type LocaleSelectorProps = {
export function LocaleSelector({ initLocaleCode, onLocaleChange }: LocaleSelectorProps) {
const [activeLocaleCode, setActiveLocaleCode] = useState(initLocaleCode);
- const isEmojiAvailable = useMemo(() => isEmojiSupported('π³οΈ'), []);
return (