@opexa/portal-components 0.0.171 → 0.0.173
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import * as faceapi from 'face-api.js';
|
|
4
4
|
import { useEffect, useRef, useState } from 'react';
|
|
5
|
+
import { twMerge } from 'tailwind-merge';
|
|
5
6
|
import { useUploadImageFileMutation } from '../../client/hooks/useUploadImageFileMutation.js';
|
|
6
7
|
import { ArrowLeftIcon } from '../../icons/ArrowLeftIcon.js';
|
|
7
8
|
import { Camera01Icon } from '../../icons/Camera01Icon.js';
|
|
@@ -178,9 +179,15 @@ export function CaptureSelfie() {
|
|
|
178
179
|
videoStream.getTracks().forEach((track) => track.stop());
|
|
179
180
|
setVideoStream(null);
|
|
180
181
|
}
|
|
181
|
-
if (videoRef.current) {
|
|
182
|
+
if (videoRef.current && videoRef.current.srcObject) {
|
|
183
|
+
const stream = videoRef.current.srcObject;
|
|
184
|
+
stream.getTracks().forEach((track) => {
|
|
185
|
+
track.stop();
|
|
186
|
+
});
|
|
182
187
|
videoRef.current.srcObject = null;
|
|
183
188
|
videoRef.current.pause();
|
|
189
|
+
videoRef.current.currentTime = 0;
|
|
190
|
+
videoRef.current.load();
|
|
184
191
|
}
|
|
185
192
|
setCountdown(3);
|
|
186
193
|
}
|
|
@@ -247,5 +254,5 @@ export function CaptureSelfie() {
|
|
|
247
254
|
return (_jsxs("div", { className: "w-full p-4 lg:w-[640px] lg:px-12 lg:py-4xl", children: [_jsxs("button", { type: "button", className: "flex items-center gap-lg lg:absolute lg:right-5 lg:top-5 lg:p-md", onClick: () => {
|
|
248
255
|
stopCamera();
|
|
249
256
|
kyc.setCapturing(null);
|
|
250
|
-
}, children: [_jsx(XIcon, { className: "text-text-senary-300 hidden size-5 lg:block" }), _jsx(ArrowLeftIcon, { className: "text-text-senary-300 size-5 lg:hidden" }), _jsx("span", { className: "text-lg font-semibold lg:hidden", children: "Back" })] }), _jsx(Dialog.Title, { className: "mt-6 text-center text-lg font-semibold lg:mt-0", children: "Take a Selfie Holding Your ID" }), _jsx(Dialog.Description, { className: "text-text-tertiary-600 mx-auto mt-sm max-w-[19rem] text-center text-sm lg:max-w-full", children: "Make sure your face and ID are clearly visible, with no glare or blur." }), _jsx("div", { id: "parent", className: "border-border-disabled mt-6 aspect-video rounded-xl border bg-black lg:mt-8", children: captureInProgress ? (_jsxs("div", { className: "relative flex h-fit w-full flex-col items-center justify-center", children: [_jsx("video", { ref: videoRef, autoPlay: true, muted: true, className: "h-[60vh] w-full rounded-lg object-cover md:aspect-video md:h-[333px]", width: "100%", height: "100%" }), _jsx("canvas", { ref: faceCanvasRef, className: "absolute inset-0 h-[60vh] w-full object-cover md:aspect-video md:h-[333px] md:object-contain", width: "100%", height: "100%" }), isCapturing && (_jsx("span", { className: "absolute inset-x-0 bottom-8 flex items-center justify-center text-5xl font-bold text-[#713B12CC] md:bottom-4", children: countdown })), !isFaceCentered && (_jsx("span", { className: "absolute inset-x-0 bottom-12 mx-auto w-1/2 text-center text-xs text-white md:bottom-3", children: "Please center your face in the camera view. Make sure your ID is clearly visible next to your face." })), _jsx(PersonOverlayDesktop, { isFaceCentered: isFaceCentered, width: videoRef.current?.clientWidth || 543, height: videoRef.current?.clientHeight || 333 })] })) : (selectedImage && (_jsx("img", { src: selectedImage, alt: "Captured Photo", className: "h-full w-full rounded-lg object-cover md:aspect-video md:h-[333px]" }))) }), selectedImage && (_jsxs("div", { className: "flex flex-col items-center justify-center gap-2 md:flex-row", children: [_jsxs(Button, { className: "disabled:bg-bg-disabled disabled:text-text-disabled mx-auto mt-4 px-xl disabled:opacity-100", size: "sm", onClick: retakePhoto, type: "button", children: ["Rekate Photo", _jsx(Camera01Icon, { className: "size-5" })] }), _jsxs(Button, { className: "disabled:bg-bg-disabled disabled:text-text-disabled mx-auto mt-4 px-xl disabled:opacity-100", size: "sm", onClick: usePhoto, type: "button", disabled: isPending, children: ["Use Photo", _jsx(Camera01Icon, { className: "size-5" })] })] })), !
|
|
257
|
+
}, children: [_jsx(XIcon, { className: "text-text-senary-300 hidden size-5 lg:block" }), _jsx(ArrowLeftIcon, { className: "text-text-senary-300 size-5 lg:hidden" }), _jsx("span", { className: "text-lg font-semibold lg:hidden", children: "Back" })] }), _jsx(Dialog.Title, { className: "mt-6 text-center text-lg font-semibold lg:mt-0", children: "Take a Selfie Holding Your ID" }), _jsx(Dialog.Description, { className: "text-text-tertiary-600 mx-auto mt-sm max-w-[19rem] text-center text-sm lg:max-w-full", children: "Make sure your face and ID are clearly visible, with no glare or blur." }), _jsx("div", { id: "parent", className: "border-border-disabled mt-6 aspect-video rounded-xl border bg-black lg:mt-8", children: captureInProgress ? (_jsxs("div", { className: "relative flex h-fit w-full flex-col items-center justify-center", children: [_jsx("video", { ref: videoRef, autoPlay: true, muted: true, className: "h-[60vh] w-full rounded-lg object-cover md:aspect-video md:h-[333px]", width: "100%", height: "100%" }), _jsx("canvas", { ref: faceCanvasRef, className: "absolute inset-0 h-[60vh] w-full object-cover md:aspect-video md:h-[333px] md:object-contain", width: "100%", height: "100%" }), isCapturing && (_jsx("span", { className: "absolute inset-x-0 bottom-8 flex items-center justify-center text-5xl font-bold text-[#713B12CC] md:bottom-4", children: countdown })), !isFaceCentered && (_jsx("span", { className: "absolute inset-x-0 bottom-12 mx-auto w-1/2 text-center text-xs text-white md:bottom-3", children: "Please center your face in the camera view. Make sure your ID is clearly visible next to your face." })), _jsx(PersonOverlayDesktop, { isFaceCentered: isFaceCentered, width: videoRef.current?.clientWidth || 543, height: videoRef.current?.clientHeight || 333 })] })) : (selectedImage && (_jsx("img", { src: selectedImage, alt: "Captured Photo", className: "h-full w-full rounded-lg object-cover md:aspect-video md:h-[333px]" }))) }), selectedImage && (_jsxs("div", { className: "flex flex-col items-center justify-center gap-2 md:flex-row", children: [_jsxs(Button, { className: "disabled:bg-bg-disabled disabled:text-text-disabled mx-auto mt-4 px-xl disabled:opacity-100", size: "sm", onClick: retakePhoto, type: "button", children: ["Rekate Photo", _jsx(Camera01Icon, { className: "size-5" })] }), _jsxs(Button, { className: "disabled:bg-bg-disabled disabled:text-text-disabled mx-auto mt-4 px-xl disabled:opacity-100", size: "sm", onClick: usePhoto, type: "button", disabled: isPending, children: ["Use Photo", _jsx(Camera01Icon, { className: "size-5" })] })] })), !captureInProgress && (_jsxs(Button, { className: twMerge('mx-auto mt-6 px-xl lg:mt-8', selectedImage && 'hidden'), onClick: startCamera, disabled: !modelsLoaded, type: "button", children: ["Start Camera", _jsx(Camera01Icon, { className: "size-5" })] }))] }));
|
|
251
258
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import Image from 'next/image';
|
|
3
3
|
import Link from 'next/link';
|
|
4
|
-
import {
|
|
4
|
+
import { useState } from 'react';
|
|
5
5
|
import { useInterval } from 'usehooks-ts';
|
|
6
6
|
import { useShallow } from 'zustand/shallow';
|
|
7
7
|
import { useDisclosure } from '../../client/hooks/useDisclosure.js';
|
|
@@ -30,6 +30,10 @@ export function MessagesPopup() {
|
|
|
30
30
|
depositWithdrawal: ctx.depositWithdrawal,
|
|
31
31
|
})));
|
|
32
32
|
const markMessageAsReadMutation = useMarkMessageAsReadMutation();
|
|
33
|
+
const [paused, setPaused] = useState(false);
|
|
34
|
+
useInterval(() => {
|
|
35
|
+
setPaused(false);
|
|
36
|
+
}, paused ? 1000 * 15 : null);
|
|
33
37
|
const disclosure = useDisclosure({
|
|
34
38
|
onOpenChange(open) {
|
|
35
39
|
if (open) {
|
|
@@ -41,13 +45,11 @@ export function MessagesPopup() {
|
|
|
41
45
|
markMessageAsReadMutation.mutate(message.id);
|
|
42
46
|
}
|
|
43
47
|
else {
|
|
44
|
-
setPaused(true);
|
|
45
48
|
setIndex_(0);
|
|
49
|
+
setPaused(true);
|
|
46
50
|
}
|
|
47
51
|
},
|
|
48
52
|
});
|
|
49
|
-
const [paused, setPaused] = useState(false);
|
|
50
|
-
useInterval(() => setPaused(false), paused ? 1000 * 30 : null);
|
|
51
53
|
const messagesQuery = useMessagesQuery({
|
|
52
54
|
first: 10,
|
|
53
55
|
filter: {
|
|
@@ -65,7 +67,7 @@ export function MessagesPopup() {
|
|
|
65
67
|
!globalStore.message.open &&
|
|
66
68
|
!globalStore.kyc.open &&
|
|
67
69
|
!paused,
|
|
68
|
-
refetchInterval: disclosure.open ? undefined :
|
|
70
|
+
refetchInterval: disclosure.open ? undefined : 1000 * 10,
|
|
69
71
|
});
|
|
70
72
|
const messages = messagesQuery.data?.pages.flatMap((page) => page.edges.map((edge) => edge.node)) ?? [];
|
|
71
73
|
const [index, setIndex_] = useState(0);
|
|
@@ -78,16 +80,16 @@ export function MessagesPopup() {
|
|
|
78
80
|
return;
|
|
79
81
|
markMessageAsReadMutation.mutate(message.id);
|
|
80
82
|
};
|
|
81
|
-
|
|
82
|
-
if (messages.length
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
},
|
|
83
|
+
useInterval(() => {
|
|
84
|
+
if (messages.length <= 0)
|
|
85
|
+
return;
|
|
86
|
+
disclosure.setOpen(true);
|
|
87
|
+
}, disclosure.open || paused ? null : 2500);
|
|
86
88
|
return (_jsx(Dialog.Root, { open: disclosure.open, onOpenChange: (details) => {
|
|
87
89
|
disclosure.setOpen(details.open);
|
|
88
90
|
}, lazyMount: true, unmountOnExit: true, children: _jsxs(Portal, { children: [_jsx(Dialog.Backdrop, { className: "!z-[calc(var(--z-dialog)+3)]" }), _jsx(Dialog.Positioner, { className: "!z-[calc(var(--z-dialog)+4)] flex items-center justify-center", children: _jsxs(Dialog.Content, { className: "min-h-auto mx-auto min-w-[21.438rem] max-w-[21.438rem] rounded-xl p-3xl lg:min-w-[25rem] lg:max-w-[25rem]", children: [_jsx(Dialog.CloseTrigger, { children: _jsx(XIcon, {}) }), _jsxs(Carousel.Root, { page: index, onPageChange: (details) => {
|
|
89
91
|
setIndex(details.page);
|
|
90
|
-
}, slideCount: messages.length, allowMouseDrag: true, children: [_jsx(Carousel.ItemGroup, { children: messages.map((message, index) => (_jsxs(Carousel.Item, { index: index, className: "select-none", children: [_jsx("div", { className: "bg-bg-brand-secondary text-text-brand mx-auto flex size-12 items-center justify-center rounded-full", children: _jsx(MessageIcon, { type: message.icon, className: "size-6" }) }), _jsx("h2", { className: "mt-lg text-center text-lg font-semibold xl:mt-xl", children: message.title }), message.content && (_jsx("div", { dangerouslySetInnerHTML: { __html: message.content }, className: "text-text-secondary-700 mt-xs pb-5 text-center text-sm" })), message.image && (_jsx("div", { className: "mt-5 pb-5", children: _jsx(Image, { src: message.image, alt: "", width: 400, height: 250, loading: "lazy", unoptimized: true, className: "h-auto w-full rounded-sm" }) })), message.actions.length ? (_jsx("div", { className: "mt-3xl flex flex-col gap-2 text-center lg:mt-4xl", children: message.actions.map((action, index) => (_jsx(Button, { asChild: true, children: _jsx(Link, { href: normalizeActionUrl(action.url, {
|
|
92
|
+
}, slideCount: messages.length, allowMouseDrag: true, autoplay: false, children: [_jsx(Carousel.ItemGroup, { children: messages.map((message, index) => (_jsxs(Carousel.Item, { index: index, className: "select-none", children: [_jsx("div", { className: "bg-bg-brand-secondary text-text-brand mx-auto flex size-12 items-center justify-center rounded-full", children: _jsx(MessageIcon, { type: message.icon, className: "size-6" }) }), _jsx("h2", { className: "mt-lg text-center text-lg font-semibold xl:mt-xl", children: message.title }), message.content && (_jsx("div", { dangerouslySetInnerHTML: { __html: message.content }, className: "text-text-secondary-700 mt-xs pb-5 text-center text-sm" })), message.image && (_jsx("div", { className: "mt-5 pb-5", children: _jsx(Image, { src: message.image, alt: "", width: 400, height: 250, loading: "lazy", unoptimized: true, className: "h-auto w-full rounded-sm" }) })), message.actions.length ? (_jsx("div", { className: "mt-3xl flex flex-col gap-2 text-center lg:mt-4xl", children: message.actions.map((action, index) => (_jsx(Button, { asChild: true, children: _jsx(Link, { href: normalizeActionUrl(action.url, {
|
|
91
93
|
questsPageUrl,
|
|
92
94
|
transactionsPageUrl,
|
|
93
95
|
}), onClick: () => {
|
package/dist/handlers.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { addDays, addMinutes, subMinutes } from 'date-fns';
|
|
2
2
|
import { NextResponse } from 'next/server';
|
|
3
3
|
import { z } from 'zod';
|
|
4
|
-
import { ACCESS_TOKEN_COOKIE_NAME, DOMAIN_COOKIE_NAME, DOMAIN_HEADER_KEY,
|
|
4
|
+
import { ACCESS_TOKEN_COOKIE_NAME, DOMAIN_COOKIE_NAME, DOMAIN_HEADER_KEY, RECAPTCHA_HEADER_KEY, REFRESH_TOKEN_COOKIE_NAME, } from './constants/index.js';
|
|
5
5
|
import { authenticate, createSession, destroySession, refreshSession, } from './services/auth.js';
|
|
6
6
|
const CreateSessionDefinition = z.union([
|
|
7
7
|
z.object({
|
|
@@ -163,18 +163,17 @@ export const POST = async (request, { params }) => {
|
|
|
163
163
|
if (path === 'sessions') {
|
|
164
164
|
const body = await request.json();
|
|
165
165
|
const parsed = CreateSessionDefinition.safeParse(body);
|
|
166
|
-
const recaptcha = request.headers.get(RECAPTCHA_HEADER_KEY);
|
|
167
|
-
const domain = request.headers.get(DOMAIN_HEADER_KEY);
|
|
168
166
|
if (!parsed.success) {
|
|
169
167
|
return NextResponse.json({
|
|
170
168
|
ok: false,
|
|
171
169
|
message: parsed.error.issues[0].message,
|
|
172
170
|
}, { status: 400 });
|
|
173
171
|
}
|
|
172
|
+
const recaptcha = request.headers.get(RECAPTCHA_HEADER_KEY);
|
|
173
|
+
const domain = request.headers.get(DOMAIN_HEADER_KEY);
|
|
174
174
|
try {
|
|
175
175
|
const res = await createSession(parsed.data, {
|
|
176
176
|
headers: {
|
|
177
|
-
'Platform-Code': PLATFORM_CODE,
|
|
178
177
|
...(recaptcha && {
|
|
179
178
|
[RECAPTCHA_HEADER_KEY]: recaptcha,
|
|
180
179
|
}),
|
|
@@ -218,18 +217,17 @@ export const POST = async (request, { params }) => {
|
|
|
218
217
|
if (path === 'authenticate') {
|
|
219
218
|
const body = await request.json();
|
|
220
219
|
const parsed = AuthenticateDefinition.safeParse(body);
|
|
221
|
-
const recaptcha = request.headers.get(RECAPTCHA_HEADER_KEY);
|
|
222
|
-
const domain = request.headers.get(DOMAIN_HEADER_KEY);
|
|
223
220
|
if (!parsed.success) {
|
|
224
221
|
return NextResponse.json({
|
|
225
222
|
ok: false,
|
|
226
223
|
message: parsed.error.issues[0].message,
|
|
227
224
|
}, { status: 400 });
|
|
228
225
|
}
|
|
226
|
+
const recaptcha = request.headers.get(RECAPTCHA_HEADER_KEY);
|
|
227
|
+
const domain = request.headers.get(DOMAIN_HEADER_KEY);
|
|
229
228
|
try {
|
|
230
229
|
const res = await authenticate(parsed.data, {
|
|
231
230
|
headers: {
|
|
232
|
-
'Platform-Code': PLATFORM_CODE,
|
|
233
231
|
...(recaptcha && {
|
|
234
232
|
[RECAPTCHA_HEADER_KEY]: recaptcha,
|
|
235
233
|
}),
|
package/dist/middleware.js
CHANGED
|
@@ -12,13 +12,20 @@ export const middleware = async (req) => {
|
|
|
12
12
|
const accessToken = req.cookies.get(ACCESS_TOKEN_COOKIE_NAME)?.value;
|
|
13
13
|
const refreshToken = req.cookies.get(REFRESH_TOKEN_COOKIE_NAME)?.value;
|
|
14
14
|
const res = NextResponse.next();
|
|
15
|
-
if (req.nextUrl.searchParams.
|
|
15
|
+
if (req.nextUrl.searchParams.has('m')) {
|
|
16
16
|
res.cookies.set(DOMAIN_COOKIE_NAME, `${req.nextUrl.origin}/${req.nextUrl.searchParams.get('m')}`, {
|
|
17
17
|
expires: addDays(new Date(), 30),
|
|
18
18
|
httpOnly: true,
|
|
19
19
|
sameSite: 'strict',
|
|
20
20
|
});
|
|
21
21
|
}
|
|
22
|
+
if (!res.cookies.has(DOMAIN_COOKIE_NAME)) {
|
|
23
|
+
res.cookies.set(DOMAIN_COOKIE_NAME, req.nextUrl.origin, {
|
|
24
|
+
expires: addDays(new Date(), 30),
|
|
25
|
+
httpOnly: true,
|
|
26
|
+
sameSite: 'strict',
|
|
27
|
+
});
|
|
28
|
+
}
|
|
22
29
|
if (!accessToken && refreshToken) {
|
|
23
30
|
try {
|
|
24
31
|
const data = await refreshSession({
|