Skip to content
Merged
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
25 changes: 24 additions & 1 deletion packages/aziface/src/module/aziface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@ import { FaceTecSDK as FaceTecSDKType } from '../types/FaceTecSDK';
import { SessionError } from '../errors/errors';
import { SessionRequestProcessor } from '../services/request-processor';
import { applyTheme, getBackgroundColor } from '../styles/theme';
import { getInitializationErrorCauseByCode } from '../utils';
import {
getInitializationErrorCauseByCode,
applyResponsiveStyles,
} from '../utils';
import {
Controller,
DisposeCallback,
Expand All @@ -30,6 +33,8 @@ export class AzifaceController implements Controller {
public static baseUrl: string = '';
public static headers: InitializeHeaders = {} as InitializeHeaders;
private faceTecSDKInstance: FaceTecSDKInstance | null = null;
private internalID: number | undefined = undefined;

public initialize = (
init: Initialize,
callback: InitializeCallback,
Expand Down Expand Up @@ -200,6 +205,9 @@ export class AzifaceController implements Controller {
AzifaceController.baseUrl = '';
AzifaceController.headers = {} as InitializeHeaders;

window.removeEventListener('click', applyResponsiveStyles);
window.clearInterval(this.internalID);

this.withTheme();
};

Expand All @@ -216,6 +224,9 @@ export class AzifaceController implements Controller {
private onInitializationError = (): void => this.cleanup();

private onComplete = (faceTecSessionStatus: FaceTecSessionStatus): void => {
window.removeEventListener('click', applyResponsiveStyles);
window.clearInterval(this.internalID);

const isError =
faceTecSessionStatus !== FaceTecSDK.FaceTecSessionStatus.SessionCompleted;
if (isError) {
Expand All @@ -233,6 +244,18 @@ export class AzifaceController implements Controller {
} else {
throw new SessionError(MethodError.NotInitialized);
}

window.addEventListener('click', applyResponsiveStyles);

const windowClickEvent = new MouseEvent('click', {
bubbles: true,
cancelable: true,
view: window,
});

this.internalID = window.setInterval(() => {
window.dispatchEvent(windowClickEvent);
}, 250);
};
}

Expand Down
34 changes: 26 additions & 8 deletions packages/aziface/src/styles/aziface.css
Original file line number Diff line number Diff line change
@@ -1,13 +1,31 @@
#DOM_FT_PRIMARY_TOPLEVEL_mainContainer
> #DOM_FT_overlayContainer
> #DOM_FT_idScanDesktopSubframeInterfaceContainer
> #DOM_FT_idScanButtonContainer {
#DOM_FT_idScanButtonContainer {
border: none !important;
}

#DOM_FT_PRIMARY_TOPLEVEL_mainContainer
> #DOM_FT_orientationContainer
> #DOM_FT_orientationContentContainer
> #DOM_FT_orientationImageContainer {
#DOM_FT_orientationImageContainer {
margin: 0 auto !important;
}

#DOM_FT_mainInterfaceNonOverlayContainer {
@media (max-width: 768px) {
border: none !important;
}
}

#DOM_FT_readyScreenHeaderElement {
@media (max-width: 768px) {
font-size: 1rem !important;
}
}

#DOM_FT_readyScreenSubtextElement {
@media (max-width: 768px) {
font-size: 0.75rem !important;
}
}

#DOM_FT_yourAppLogoContainer {
@media (max-width: 768px) {
height: calc(100% - 360px) !important;
}
}
157 changes: 157 additions & 0 deletions packages/aziface/src/utils/styles.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,169 @@
import { CancelLocation } from '../types/aziface';
import type { FaceTecCancelButtonLocation } from '../types/FaceTecCustomization';

const PREFIX = 'DOM_FT_';
const SAFE_MARGIN = 48;
const CANCEL_BUTTON_LOCATION = {
Disabled: 0 as FaceTecCancelButtonLocation,
TopLeft: 1 as FaceTecCancelButtonLocation,
TopRight: 2 as FaceTecCancelButtonLocation,
} as const;

function getElementById(id: string): HTMLElement | null {
return document.getElementById(id);
}

function getStyle(id: string): string {
const element = getElementById(id);
return element ? element.getAttribute('style') || '' : '';
}

function setStyle(id: string, style: string): void {
const element = getElementById(id);
if (element) element.setAttribute('style', style);
}

function isMobile(): boolean {
return window.innerWidth <= 768;
}

function isRequestingPermission(): boolean {
const id = `${PREFIX}cameraPermissionsScreen`;
const currentStyle = getStyle(id);
return currentStyle.includes('display: flex;');
}

function adjustFrameContainer(): void {
if (!isMobile()) return;

const id = `${PREFIX}frameContainer`;
if (!!getElementById(id)) {
const currentStyle = getStyle(id);
const newStyle = 'top: 0px !important; left: 0px !important;';
const isRequesting = isRequestingPermission();
const hasStyle = currentStyle.includes(newStyle);

if (!hasStyle && !isRequesting) {
setStyle(id, `${currentStyle} ${newStyle}`);
} else if (hasStyle && isRequesting) {
const replatedStyle = currentStyle.replace(
newStyle,
'top: -2px !important; left: -2px !important;',
);
setStyle(id, replatedStyle);
}
}
}

function adjustCancelButtonElementBase(id: string, style: string): void {
if (!isMobile() || !getElementById(id)) return;

if (isRequestingPermission()) {
setStyle(id, style);
} else {
const left = window.innerWidth > 400 ? '20%' : '22%';
const newStyle = `left: ${left} !important;`;
const currentStyle = getStyle(id);
if (!currentStyle.includes(newStyle)) {
setStyle(id, `${currentStyle} ${newStyle}`);
}
}
}

function adjustCancelButtonElement(): void {
adjustCancelButtonElementBase(
`${PREFIX}cancelButtonElement`,
'left: 0px !important; height: 16px; width: 16px; padding: 15px; margin: 0px; opacity: 1; display: block; transition: opacity 500ms;',
);
adjustCancelButtonElementBase(
`${PREFIX}idScanCancelButtonElement`,
'height: 16px; width: 16px; padding: 8px; margin: 8px; top: 0px; left: 0px; opacity: 1; display: flex; transition: opacity 2000ms;',
);
}

function adjustIdScanMask(): void {
if (!isMobile()) return;

const startY = '12px';
const mask = getElementById(`${PREFIX}idScanCaptureFrameMask`);
if (mask) {
const [, rect] = mask.children;
rect.setAttribute('style', '');
rect.setAttribute('y', startY);
}

const rectId = `${PREFIX}idScanCaptureFrameRect`;
const rect = getElementById(rectId);
if (rect) {
setStyle(rectId, '');
rect.setAttribute('y', startY);
}
}

function adjustOCRFormContainer(): void {
if (!isMobile()) return;

const id = `${PREFIX}ocrFormContainer`;
const element = getElementById(id);
if (element) {
const [form] = element.children;

for (const child of form.children) {
if (child.tagName === 'SECTION') {
for (const sectionChild of child.children) {
if (sectionChild.tagName === 'DIV') {
const width = window.innerWidth - SAFE_MARGIN;
const currentStyle = sectionChild.getAttribute('style') || '';
const newStyle = `margin: 0px auto; display: block; width: ${width}px;`;
if (!currentStyle.includes(newStyle)) {
sectionChild.setAttribute('style', newStyle);
}
}
}
}
}
}
}

function generateDPath(): string | null {
if (!isMobile()) return null;

const VIEW_BOX = 640;
const OVAL = 158;
const displacement = OVAL.toFixed(1);
const rx = (79).toFixed(1);
const ry = (116).toFixed(1);
const width = (VIEW_BOX / 2 - OVAL / 2).toFixed(1);

return `m${width} 180 a${rx} ${ry} 0 1 0 ${displacement} 0 a${rx} ${ry} 0 1 0 -${displacement} 0`;
}

function removeElementById(id: string): void {
if (!isMobile()) return;

const element = getElementById(id);
if (element) element.remove();
}

function setDPath(id: string): void {
const element = getElementById(id);
const d = generateDPath();
if (element && d) element.setAttribute('d', d);
}

export function applyResponsiveStyles(): void {
removeElementById(`${PREFIX}ovalSpinner1`);
removeElementById(`${PREFIX}ovalSpinner2`);

adjustCancelButtonElement();
adjustFrameContainer();
adjustIdScanMask();
adjustOCRFormContainer();

setDPath(`${PREFIX}frameGetReadyOvalPath`);
setDPath(`${PREFIX}frameOvalPath`);
}

export function resolveCancelLocation(
location?: CancelLocation,
): FaceTecCancelButtonLocation {
Expand Down
Loading