uibee 2.8.6 → 2.9.0
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.
- package/dist/src/components/confirm/confirmPopup.d.ts +12 -0
- package/dist/src/components/confirm/confirmPopup.js +18 -0
- package/dist/src/components/index.d.ts +1 -0
- package/dist/src/components/index.js +2 -0
- package/dist/src/globals.css +97 -0
- package/dist/src/utils/auth/callback.d.ts +1 -1
- package/dist/src/utils/auth/callback.js +5 -3
- package/dist/src/utils/auth/getDomain.d.ts +2 -0
- package/dist/src/utils/auth/getDomain.js +5 -0
- package/dist/src/utils/auth/login.d.ts +1 -1
- package/dist/src/utils/auth/login.js +4 -2
- package/dist/src/utils/auth/logout.d.ts +1 -1
- package/dist/src/utils/auth/logout.js +4 -2
- package/dist/src/utils/auth/token.d.ts +1 -1
- package/dist/src/utils/auth/token.js +5 -3
- package/package.json +1 -1
- package/src/components/confirm/confirmPopup.tsx +103 -0
- package/src/components/index.ts +4 -1
- package/src/types/components.d.ts +12 -0
- package/src/types/utils.d.ts +7 -7
- package/src/utils/auth/callback.ts +6 -4
- package/src/utils/auth/getDomain.ts +7 -0
- package/src/utils/auth/login.ts +4 -2
- package/src/utils/auth/logout.ts +4 -2
- package/src/utils/auth/token.ts +5 -3
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
type ConfirmPopupProps = {
|
|
2
|
+
isOpen: boolean;
|
|
3
|
+
header: string;
|
|
4
|
+
description?: string;
|
|
5
|
+
confirmText?: string;
|
|
6
|
+
cancelText?: string;
|
|
7
|
+
onConfirm: () => void;
|
|
8
|
+
onCancel: () => void;
|
|
9
|
+
variant?: 'danger' | 'warning' | 'default';
|
|
10
|
+
};
|
|
11
|
+
export default function ConfirmPopup({ isOpen, header, description, confirmText, cancelText, onConfirm, onCancel, variant, }: ConfirmPopupProps): import("react/jsx-runtime").JSX.Element | null;
|
|
12
|
+
export {};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { TriangleAlert } from 'lucide-react';
|
|
4
|
+
export default function ConfirmPopup({ isOpen, header, description, confirmText = 'Confirm', cancelText = 'Cancel', onConfirm, onCancel, variant = 'default', }) {
|
|
5
|
+
if (!isOpen)
|
|
6
|
+
return null;
|
|
7
|
+
const confirmBg = variant === 'danger'
|
|
8
|
+
? 'bg-red-700/80 outline-red-700 hover:bg-red-700'
|
|
9
|
+
: variant === 'warning'
|
|
10
|
+
? 'bg-yellow-600/80 outline-yellow-600 hover:bg-yellow-600'
|
|
11
|
+
: 'bg-login/70 outline-login hover:bg-login/90';
|
|
12
|
+
return (_jsxs("div", { role: 'dialog', "aria-modal": 'true', "aria-labelledby": 'confirm-popup-header', className: 'fixed inset-0 z-50 flex items-center justify-center', onClick: onCancel, children: [_jsx("div", { className: 'absolute inset-0 bg-black/60 backdrop-blur-sm' }), _jsxs("div", { className: '\n relative z-10 w-full max-w-md mx-4\n bg-login-800 border border-login-500/50 rounded-xl\n shadow-2xl p-6 flex flex-col gap-4\n ', onClick: (e) => e.stopPropagation(), children: [_jsxs("div", { className: 'flex items-center gap-3', children: [variant !== 'default' && (_jsx(TriangleAlert, { className: `w-6 h-6 shrink-0 ${variant === 'danger' ? 'stroke-red-400' : 'stroke-yellow-400'}` })), _jsx("h2", { id: 'confirm-popup-header', className: 'text-login-50 text-lg font-bold leading-snug', children: header })] }), description && (_jsx("p", { className: 'text-login-100 text-sm leading-relaxed', children: description })), _jsxs("div", { className: 'flex justify-end gap-3 mt-1', children: [_jsx("button", { type: 'button', onClick: onCancel, className: '\n cursor-pointer px-4 py-1.5 rounded-md text-sm font-medium\n bg-login-500/60 text-login-50 outline outline-login-500/60\n hover:bg-login-500/90 focus:outline-none select-none\n transition-colors duration-150\n ', children: cancelText }), _jsx("button", { type: 'button', onClick: onConfirm, className: `
|
|
13
|
+
cursor-pointer px-4 py-1.5 rounded-md text-sm font-bold
|
|
14
|
+
text-white outline focus:outline-none select-none
|
|
15
|
+
transition-colors duration-150
|
|
16
|
+
${confirmBg}
|
|
17
|
+
`, children: confirmText })] })] })] }));
|
|
18
|
+
}
|
|
@@ -20,3 +20,4 @@ export { default as LoginPage } from './login/loginPage';
|
|
|
20
20
|
export { default as Toaster, toast } from './toast/toaster';
|
|
21
21
|
export { default as Button } from './buttons/button';
|
|
22
22
|
export { default as Alert } from './alert/alert';
|
|
23
|
+
export { default as ConfirmPopup } from './confirm/confirmPopup';
|
package/dist/src/globals.css
CHANGED
|
@@ -10,8 +10,11 @@
|
|
|
10
10
|
--color-red-200: oklch(88.5% 0.062 18.334);
|
|
11
11
|
--color-red-400: oklch(70.4% 0.191 22.216);
|
|
12
12
|
--color-red-500: oklch(63.7% 0.237 25.331);
|
|
13
|
+
--color-red-700: oklch(50.5% 0.213 27.518);
|
|
13
14
|
--color-red-900: oklch(39.6% 0.141 25.723);
|
|
15
|
+
--color-yellow-400: oklch(85.2% 0.199 91.936);
|
|
14
16
|
--color-yellow-500: oklch(79.5% 0.184 86.047);
|
|
17
|
+
--color-yellow-600: oklch(68.1% 0.162 75.834);
|
|
15
18
|
--color-green-500: oklch(72.3% 0.219 149.579);
|
|
16
19
|
--color-blue-500: oklch(62.3% 0.214 259.815);
|
|
17
20
|
--color-blue-600: oklch(54.6% 0.245 262.881);
|
|
@@ -46,6 +49,8 @@
|
|
|
46
49
|
--font-weight-bold: 700;
|
|
47
50
|
--font-weight-extrabold: 800;
|
|
48
51
|
--tracking-tight: -0.025em;
|
|
52
|
+
--leading-snug: 1.375;
|
|
53
|
+
--leading-relaxed: 1.625;
|
|
49
54
|
--radius-xs: 0.125rem;
|
|
50
55
|
--radius-sm: 0.25rem;
|
|
51
56
|
--radius-md: 0.375rem;
|
|
@@ -53,6 +58,7 @@
|
|
|
53
58
|
--radius-xl: 0.75rem;
|
|
54
59
|
--ease-out: cubic-bezier(0, 0, 0.2, 1);
|
|
55
60
|
--ease-in-out: cubic-bezier(0.4, 0, 0.2, 1);
|
|
61
|
+
--blur-sm: 8px;
|
|
56
62
|
--blur-xl: 24px;
|
|
57
63
|
--default-transition-duration: 150ms;
|
|
58
64
|
--default-transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
|
|
@@ -377,6 +383,9 @@
|
|
|
377
383
|
.m-auto {
|
|
378
384
|
margin: auto;
|
|
379
385
|
}
|
|
386
|
+
.mx-4 {
|
|
387
|
+
margin-inline: calc(var(--spacing) * 4);
|
|
388
|
+
}
|
|
380
389
|
.mx-auto {
|
|
381
390
|
margin-inline: auto;
|
|
382
391
|
}
|
|
@@ -1442,6 +1451,12 @@
|
|
|
1442
1451
|
.border-login-500 {
|
|
1443
1452
|
border-color: var(--color-login-500);
|
|
1444
1453
|
}
|
|
1454
|
+
.border-login-500\/50 {
|
|
1455
|
+
border-color: color-mix(in srgb, #323232 50%, transparent);
|
|
1456
|
+
@supports (color: color-mix(in lab, red, red)) {
|
|
1457
|
+
border-color: color-mix(in oklab, var(--color-login-500) 50%, transparent);
|
|
1458
|
+
}
|
|
1459
|
+
}
|
|
1445
1460
|
.border-red-500 {
|
|
1446
1461
|
border-color: var(--color-red-500);
|
|
1447
1462
|
}
|
|
@@ -1454,6 +1469,12 @@
|
|
|
1454
1469
|
.bg-\[\#18181899\] {
|
|
1455
1470
|
background-color: #18181899;
|
|
1456
1471
|
}
|
|
1472
|
+
.bg-black\/60 {
|
|
1473
|
+
background-color: color-mix(in srgb, #000 60%, transparent);
|
|
1474
|
+
@supports (color: color-mix(in lab, red, red)) {
|
|
1475
|
+
background-color: color-mix(in oklab, var(--color-black) 60%, transparent);
|
|
1476
|
+
}
|
|
1477
|
+
}
|
|
1457
1478
|
.bg-blue-600 {
|
|
1458
1479
|
background-color: var(--color-blue-600);
|
|
1459
1480
|
}
|
|
@@ -1478,6 +1499,12 @@
|
|
|
1478
1499
|
background-color: color-mix(in oklab, var(--color-login-500) 50%, transparent);
|
|
1479
1500
|
}
|
|
1480
1501
|
}
|
|
1502
|
+
.bg-login-500\/60 {
|
|
1503
|
+
background-color: color-mix(in srgb, #323232 60%, transparent);
|
|
1504
|
+
@supports (color: color-mix(in lab, red, red)) {
|
|
1505
|
+
background-color: color-mix(in oklab, var(--color-login-500) 60%, transparent);
|
|
1506
|
+
}
|
|
1507
|
+
}
|
|
1481
1508
|
.bg-login-500\/70 {
|
|
1482
1509
|
background-color: color-mix(in srgb, #323232 70%, transparent);
|
|
1483
1510
|
@supports (color: color-mix(in lab, red, red)) {
|
|
@@ -1514,6 +1541,12 @@
|
|
|
1514
1541
|
background-color: color-mix(in oklab, var(--color-login) 70%, transparent);
|
|
1515
1542
|
}
|
|
1516
1543
|
}
|
|
1544
|
+
.bg-red-700\/80 {
|
|
1545
|
+
background-color: color-mix(in srgb, oklch(50.5% 0.213 27.518) 80%, transparent);
|
|
1546
|
+
@supports (color: color-mix(in lab, red, red)) {
|
|
1547
|
+
background-color: color-mix(in oklab, var(--color-red-700) 80%, transparent);
|
|
1548
|
+
}
|
|
1549
|
+
}
|
|
1517
1550
|
.bg-red-900 {
|
|
1518
1551
|
background-color: var(--color-red-900);
|
|
1519
1552
|
}
|
|
@@ -1523,6 +1556,12 @@
|
|
|
1523
1556
|
.bg-white {
|
|
1524
1557
|
background-color: var(--color-white);
|
|
1525
1558
|
}
|
|
1559
|
+
.bg-yellow-600\/80 {
|
|
1560
|
+
background-color: color-mix(in srgb, oklch(68.1% 0.162 75.834) 80%, transparent);
|
|
1561
|
+
@supports (color: color-mix(in lab, red, red)) {
|
|
1562
|
+
background-color: color-mix(in oklab, var(--color-yellow-600) 80%, transparent);
|
|
1563
|
+
}
|
|
1564
|
+
}
|
|
1526
1565
|
.bg-linear-to-r {
|
|
1527
1566
|
--tw-gradient-position: to right;
|
|
1528
1567
|
@supports (background-image: linear-gradient(in lab, red, red)) {
|
|
@@ -1576,6 +1615,12 @@
|
|
|
1576
1615
|
.stroke-login-50 {
|
|
1577
1616
|
stroke: var(--color-login-50);
|
|
1578
1617
|
}
|
|
1618
|
+
.stroke-red-400 {
|
|
1619
|
+
stroke: var(--color-red-400);
|
|
1620
|
+
}
|
|
1621
|
+
.stroke-yellow-400 {
|
|
1622
|
+
stroke: var(--color-yellow-400);
|
|
1623
|
+
}
|
|
1579
1624
|
.stroke-\[3\.5px\] {
|
|
1580
1625
|
stroke-width: 3.5px;
|
|
1581
1626
|
}
|
|
@@ -1597,6 +1642,9 @@
|
|
|
1597
1642
|
.p-4 {
|
|
1598
1643
|
padding: calc(var(--spacing) * 4);
|
|
1599
1644
|
}
|
|
1645
|
+
.p-6 {
|
|
1646
|
+
padding: calc(var(--spacing) * 6);
|
|
1647
|
+
}
|
|
1600
1648
|
.p-8 {
|
|
1601
1649
|
padding: calc(var(--spacing) * 8);
|
|
1602
1650
|
}
|
|
@@ -1718,6 +1766,14 @@
|
|
|
1718
1766
|
--tw-leading: calc(var(--spacing) * 8);
|
|
1719
1767
|
line-height: calc(var(--spacing) * 8);
|
|
1720
1768
|
}
|
|
1769
|
+
.leading-relaxed {
|
|
1770
|
+
--tw-leading: var(--leading-relaxed);
|
|
1771
|
+
line-height: var(--leading-relaxed);
|
|
1772
|
+
}
|
|
1773
|
+
.leading-snug {
|
|
1774
|
+
--tw-leading: var(--leading-snug);
|
|
1775
|
+
line-height: var(--leading-snug);
|
|
1776
|
+
}
|
|
1721
1777
|
.font-bold {
|
|
1722
1778
|
--tw-font-weight: var(--font-weight-bold);
|
|
1723
1779
|
font-weight: var(--font-weight-bold);
|
|
@@ -1757,6 +1813,12 @@
|
|
|
1757
1813
|
.text-login\! {
|
|
1758
1814
|
color: var(--color-login) !important;
|
|
1759
1815
|
}
|
|
1816
|
+
.text-login-50 {
|
|
1817
|
+
color: var(--color-login-50);
|
|
1818
|
+
}
|
|
1819
|
+
.text-login-100 {
|
|
1820
|
+
color: var(--color-login-100);
|
|
1821
|
+
}
|
|
1760
1822
|
.text-login-200 {
|
|
1761
1823
|
color: var(--color-login-200);
|
|
1762
1824
|
}
|
|
@@ -1807,6 +1869,10 @@
|
|
|
1807
1869
|
.opacity-100 {
|
|
1808
1870
|
opacity: 100%;
|
|
1809
1871
|
}
|
|
1872
|
+
.shadow-2xl {
|
|
1873
|
+
--tw-shadow: 0 25px 50px -12px var(--tw-shadow-color, rgb(0 0 0 / 0.25));
|
|
1874
|
+
box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
|
|
1875
|
+
}
|
|
1810
1876
|
.shadow-\[0_0\.1rem_0\.5rem_rgba\(3\,3\,3\,0\.5\)\] {
|
|
1811
1877
|
--tw-shadow: 0 0.1rem 0.5rem var(--tw-shadow-color, rgba(3,3,3,0.5));
|
|
1812
1878
|
box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
|
|
@@ -1846,6 +1912,23 @@
|
|
|
1846
1912
|
.outline-login-500 {
|
|
1847
1913
|
outline-color: var(--color-login-500);
|
|
1848
1914
|
}
|
|
1915
|
+
.outline-login-500\/60 {
|
|
1916
|
+
outline-color: color-mix(in srgb, #323232 60%, transparent);
|
|
1917
|
+
@supports (color: color-mix(in lab, red, red)) {
|
|
1918
|
+
outline-color: color-mix(in oklab, var(--color-login-500) 60%, transparent);
|
|
1919
|
+
}
|
|
1920
|
+
}
|
|
1921
|
+
.outline-red-700 {
|
|
1922
|
+
outline-color: var(--color-red-700);
|
|
1923
|
+
}
|
|
1924
|
+
.outline-yellow-600 {
|
|
1925
|
+
outline-color: var(--color-yellow-600);
|
|
1926
|
+
}
|
|
1927
|
+
.backdrop-blur-sm {
|
|
1928
|
+
--tw-backdrop-blur: blur(var(--blur-sm));
|
|
1929
|
+
-webkit-backdrop-filter: var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);
|
|
1930
|
+
backdrop-filter: var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);
|
|
1931
|
+
}
|
|
1849
1932
|
.backdrop-blur-xl {
|
|
1850
1933
|
--tw-backdrop-blur: blur(var(--blur-xl));
|
|
1851
1934
|
-webkit-backdrop-filter: var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);
|
|
@@ -2215,6 +2298,20 @@
|
|
|
2215
2298
|
}
|
|
2216
2299
|
}
|
|
2217
2300
|
}
|
|
2301
|
+
.hover\:bg-red-700 {
|
|
2302
|
+
&:hover {
|
|
2303
|
+
@media (hover: hover) {
|
|
2304
|
+
background-color: var(--color-red-700);
|
|
2305
|
+
}
|
|
2306
|
+
}
|
|
2307
|
+
}
|
|
2308
|
+
.hover\:bg-yellow-600 {
|
|
2309
|
+
&:hover {
|
|
2310
|
+
@media (hover: hover) {
|
|
2311
|
+
background-color: var(--color-yellow-600);
|
|
2312
|
+
}
|
|
2313
|
+
}
|
|
2314
|
+
}
|
|
2218
2315
|
.hover\:text-login-200 {
|
|
2219
2316
|
&:hover {
|
|
2220
2317
|
@media (hover: hover) {
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import type { AuthCallbackProps } from 'uibee/utils';
|
|
2
|
-
export default function authCallback({ req, tokenURL, clientID, clientSecret,
|
|
2
|
+
export default function authCallback({ req, tokenURL, clientID, clientSecret, redirectPath, userInfoURL, tokenRedirectPath }: AuthCallbackProps): Promise<Response>;
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { NextResponse } from 'next/server';
|
|
2
|
-
|
|
2
|
+
import { getDomain } from './getDomain';
|
|
3
|
+
export default async function authCallback({ req, tokenURL, clientID, clientSecret, redirectPath, userInfoURL, tokenRedirectPath }) {
|
|
4
|
+
const domain = getDomain(req);
|
|
3
5
|
const searchParams = new URL(req.url).searchParams;
|
|
4
6
|
if (!searchParams) {
|
|
5
7
|
return NextResponse.json({ error: 'No search parameters found.' }, { status: 400 });
|
|
@@ -17,7 +19,7 @@ export default async function authCallback({ req, tokenURL, clientID, clientSecr
|
|
|
17
19
|
client_id: clientID,
|
|
18
20
|
client_secret: clientSecret,
|
|
19
21
|
code: code,
|
|
20
|
-
redirect_uri:
|
|
22
|
+
redirect_uri: `${domain}${redirectPath}`,
|
|
21
23
|
grant_type: 'authorization_code',
|
|
22
24
|
}).toString()
|
|
23
25
|
});
|
|
@@ -41,7 +43,7 @@ export default async function authCallback({ req, tokenURL, clientID, clientSecr
|
|
|
41
43
|
});
|
|
42
44
|
}
|
|
43
45
|
const userInfo = await userInfoResponse.json();
|
|
44
|
-
const redirectUrl = new URL(
|
|
46
|
+
const redirectUrl = new URL(`${domain}${tokenRedirectPath}`);
|
|
45
47
|
const params = new URLSearchParams({
|
|
46
48
|
id: userInfo.sub,
|
|
47
49
|
name: userInfo.name,
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import { NextResponse } from 'next/server';
|
|
2
2
|
import type { AuthLoginProps } from 'uibee/utils';
|
|
3
|
-
export default function AuthLogin({ clientID,
|
|
3
|
+
export default function AuthLogin({ req, clientID, redirectPath, authURL }: AuthLoginProps): Promise<NextResponse<unknown>>;
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { NextResponse } from 'next/server';
|
|
2
|
-
|
|
2
|
+
import { getDomain } from './getDomain';
|
|
3
|
+
export default async function AuthLogin({ req, clientID, redirectPath, authURL }) {
|
|
4
|
+
const domain = getDomain(req);
|
|
3
5
|
const state = Math.random().toString(36).substring(5);
|
|
4
6
|
const authQueryParams = new URLSearchParams({
|
|
5
7
|
client_id: clientID,
|
|
6
|
-
redirect_uri:
|
|
8
|
+
redirect_uri: `${domain}${redirectPath}`,
|
|
7
9
|
response_type: 'code',
|
|
8
10
|
scope: 'openid profile email',
|
|
9
11
|
state: state,
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import { NextResponse } from 'next/server';
|
|
2
2
|
import type { AuthLogoutProps } from 'uibee/utils';
|
|
3
|
-
export default function AuthLogout({
|
|
3
|
+
export default function AuthLogout({ req, path }: AuthLogoutProps): Promise<NextResponse<unknown>>;
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { NextResponse } from 'next/server';
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
import { getDomain } from './getDomain';
|
|
3
|
+
export default async function AuthLogout({ req, path }) {
|
|
4
|
+
const domain = getDomain(req);
|
|
5
|
+
const response = NextResponse.redirect(new URL(path || '/', domain));
|
|
4
6
|
const cookiesToRemove = [
|
|
5
7
|
'access_token',
|
|
6
8
|
'user_id',
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import { NextResponse } from 'next/server';
|
|
2
2
|
import type { AuthTokenProps } from 'uibee/utils';
|
|
3
|
-
export default function AuthToken({ req,
|
|
3
|
+
export default function AuthToken({ req, redirectPath }: AuthTokenProps): Promise<NextResponse<unknown>>;
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { NextResponse } from 'next/server';
|
|
2
|
-
|
|
2
|
+
import { getDomain } from './getDomain';
|
|
3
|
+
export default async function AuthToken({ req, redirectPath }) {
|
|
4
|
+
const domain = getDomain(req);
|
|
3
5
|
const url = new URL(req.url);
|
|
4
6
|
const token = url.searchParams.get('access_token');
|
|
5
7
|
const btg = url.searchParams.get('btg');
|
|
@@ -9,7 +11,7 @@ export default async function AuthToken({ req, frontendURL, redirectPath }) {
|
|
|
9
11
|
return NextResponse.json({ error: 'No access token provided' }, { status: 400 });
|
|
10
12
|
}
|
|
11
13
|
if (btg) {
|
|
12
|
-
return NextResponse.redirect(new URL(redirect,
|
|
14
|
+
return NextResponse.redirect(new URL(redirect, domain));
|
|
13
15
|
}
|
|
14
16
|
const accessToken = url.searchParams.get('access_token');
|
|
15
17
|
const userID = url.searchParams.get('id');
|
|
@@ -17,7 +19,7 @@ export default async function AuthToken({ req, frontendURL, redirectPath }) {
|
|
|
17
19
|
const userNickname = url.searchParams.get('username');
|
|
18
20
|
const userEmail = url.searchParams.get('email');
|
|
19
21
|
const userGroups = url.searchParams.get('groups');
|
|
20
|
-
const response = NextResponse.redirect(new URL(redirect,
|
|
22
|
+
const response = NextResponse.redirect(new URL(redirect, domain));
|
|
21
23
|
response.cookies.set('access_token', accessToken);
|
|
22
24
|
response.cookies.set('user_id', userID);
|
|
23
25
|
response.cookies.set('user_name', username);
|
package/package.json
CHANGED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import { TriangleAlert } from 'lucide-react'
|
|
4
|
+
|
|
5
|
+
type ConfirmPopupProps = {
|
|
6
|
+
isOpen: boolean
|
|
7
|
+
header: string
|
|
8
|
+
description?: string
|
|
9
|
+
confirmText?: string
|
|
10
|
+
cancelText?: string
|
|
11
|
+
onConfirm: () => void
|
|
12
|
+
onCancel: () => void
|
|
13
|
+
variant?: 'danger' | 'warning' | 'default'
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export default function ConfirmPopup({
|
|
17
|
+
isOpen,
|
|
18
|
+
header,
|
|
19
|
+
description,
|
|
20
|
+
confirmText = 'Confirm',
|
|
21
|
+
cancelText = 'Cancel',
|
|
22
|
+
onConfirm,
|
|
23
|
+
onCancel,
|
|
24
|
+
variant = 'default',
|
|
25
|
+
}: ConfirmPopupProps) {
|
|
26
|
+
if (!isOpen) return null
|
|
27
|
+
|
|
28
|
+
const confirmBg =
|
|
29
|
+
variant === 'danger'
|
|
30
|
+
? 'bg-red-700/80 outline-red-700 hover:bg-red-700'
|
|
31
|
+
: variant === 'warning'
|
|
32
|
+
? 'bg-yellow-600/80 outline-yellow-600 hover:bg-yellow-600'
|
|
33
|
+
: 'bg-login/70 outline-login hover:bg-login/90'
|
|
34
|
+
|
|
35
|
+
return (
|
|
36
|
+
<div
|
|
37
|
+
role='dialog'
|
|
38
|
+
aria-modal='true'
|
|
39
|
+
aria-labelledby='confirm-popup-header'
|
|
40
|
+
className='fixed inset-0 z-50 flex items-center justify-center'
|
|
41
|
+
onClick={onCancel}
|
|
42
|
+
>
|
|
43
|
+
<div className='absolute inset-0 bg-black/60 backdrop-blur-sm' />
|
|
44
|
+
|
|
45
|
+
<div
|
|
46
|
+
className='
|
|
47
|
+
relative z-10 w-full max-w-md mx-4
|
|
48
|
+
bg-login-800 border border-login-500/50 rounded-xl
|
|
49
|
+
shadow-2xl p-6 flex flex-col gap-4
|
|
50
|
+
'
|
|
51
|
+
onClick={(e) => e.stopPropagation()}
|
|
52
|
+
>
|
|
53
|
+
<div className='flex items-center gap-3'>
|
|
54
|
+
{variant !== 'default' && (
|
|
55
|
+
<TriangleAlert
|
|
56
|
+
className={`w-6 h-6 shrink-0 ${variant === 'danger' ? 'stroke-red-400' : 'stroke-yellow-400'}`}
|
|
57
|
+
/>
|
|
58
|
+
)}
|
|
59
|
+
<h2
|
|
60
|
+
id='confirm-popup-header'
|
|
61
|
+
className='text-login-50 text-lg font-bold leading-snug'
|
|
62
|
+
>
|
|
63
|
+
{header}
|
|
64
|
+
</h2>
|
|
65
|
+
</div>
|
|
66
|
+
|
|
67
|
+
{description && (
|
|
68
|
+
<p className='text-login-100 text-sm leading-relaxed'>
|
|
69
|
+
{description}
|
|
70
|
+
</p>
|
|
71
|
+
)}
|
|
72
|
+
|
|
73
|
+
<div className='flex justify-end gap-3 mt-1'>
|
|
74
|
+
<button
|
|
75
|
+
type='button'
|
|
76
|
+
onClick={onCancel}
|
|
77
|
+
className='
|
|
78
|
+
cursor-pointer px-4 py-1.5 rounded-md text-sm font-medium
|
|
79
|
+
bg-login-500/60 text-login-50 outline outline-login-500/60
|
|
80
|
+
hover:bg-login-500/90 focus:outline-none select-none
|
|
81
|
+
transition-colors duration-150
|
|
82
|
+
'
|
|
83
|
+
>
|
|
84
|
+
{cancelText}
|
|
85
|
+
</button>
|
|
86
|
+
|
|
87
|
+
<button
|
|
88
|
+
type='button'
|
|
89
|
+
onClick={onConfirm}
|
|
90
|
+
className={`
|
|
91
|
+
cursor-pointer px-4 py-1.5 rounded-md text-sm font-bold
|
|
92
|
+
text-white outline focus:outline-none select-none
|
|
93
|
+
transition-colors duration-150
|
|
94
|
+
${confirmBg}
|
|
95
|
+
`}
|
|
96
|
+
>
|
|
97
|
+
{confirmText}
|
|
98
|
+
</button>
|
|
99
|
+
</div>
|
|
100
|
+
</div>
|
|
101
|
+
</div>
|
|
102
|
+
)
|
|
103
|
+
}
|
package/src/components/index.ts
CHANGED
|
@@ -36,4 +36,7 @@ export { default as Toaster, toast } from './toast/toaster'
|
|
|
36
36
|
export { default as Button } from './buttons/button'
|
|
37
37
|
|
|
38
38
|
// Alert
|
|
39
|
-
export { default as Alert } from './alert/alert'
|
|
39
|
+
export { default as Alert } from './alert/alert'
|
|
40
|
+
|
|
41
|
+
// Confirm
|
|
42
|
+
export { default as ConfirmPopup } from './confirm/confirmPopup'
|
|
@@ -45,4 +45,16 @@ declare module 'uibee/components' {
|
|
|
45
45
|
}
|
|
46
46
|
export default function LanguageToggle(props: { lang: Language }): JSX.Element;
|
|
47
47
|
export default function ThemeSwitch(props: { className?: string }): JSX.Element;
|
|
48
|
+
|
|
49
|
+
export interface ConfirmPopupProps {
|
|
50
|
+
isOpen: boolean
|
|
51
|
+
header: string
|
|
52
|
+
description?: string
|
|
53
|
+
confirmText?: string
|
|
54
|
+
cancelText?: string
|
|
55
|
+
onConfirm: () => void
|
|
56
|
+
onCancel: () => void
|
|
57
|
+
variant?: 'danger' | 'warning' | 'default'
|
|
58
|
+
}
|
|
59
|
+
export function ConfirmPopup(props: ConfirmPopupProps): JSX.Element | null;
|
|
48
60
|
}
|
package/src/types/utils.d.ts
CHANGED
|
@@ -2,30 +2,30 @@
|
|
|
2
2
|
import { NextRequest } from 'next/server'
|
|
3
3
|
declare module 'uibee/utils' {
|
|
4
4
|
export interface AuthLoginProps {
|
|
5
|
+
req: NextRequest
|
|
5
6
|
clientID: string
|
|
6
|
-
|
|
7
|
+
redirectPath: string
|
|
7
8
|
authURL: string
|
|
8
9
|
}
|
|
9
10
|
|
|
10
11
|
export interface AuthCallbackProps {
|
|
11
|
-
req:
|
|
12
|
+
req: NextRequest
|
|
12
13
|
tokenURL: string
|
|
13
14
|
clientID: string
|
|
14
15
|
clientSecret: string
|
|
15
|
-
|
|
16
|
+
redirectPath: string
|
|
16
17
|
userInfoURL: string
|
|
17
|
-
|
|
18
|
+
tokenRedirectPath: string
|
|
18
19
|
}
|
|
19
20
|
|
|
20
21
|
export interface AuthTokenProps {
|
|
21
22
|
req: NextRequest
|
|
22
|
-
frontendURL: string
|
|
23
23
|
redirectPath?: string
|
|
24
24
|
}
|
|
25
|
+
|
|
25
26
|
export interface AuthLogoutProps {
|
|
26
|
-
|
|
27
|
+
req: NextRequest
|
|
27
28
|
path?: string
|
|
28
|
-
frontendURL: string
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
export default async function authLogin(props: AuthLoginProps): Promise<Response>;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { NextResponse } from 'next/server'
|
|
2
2
|
import type { AuthCallbackProps } from 'uibee/utils'
|
|
3
|
+
import { getDomain } from './getDomain'
|
|
3
4
|
|
|
4
5
|
type UserInfo = {
|
|
5
6
|
sub: string
|
|
@@ -14,10 +15,11 @@ export default async function authCallback({
|
|
|
14
15
|
tokenURL,
|
|
15
16
|
clientID,
|
|
16
17
|
clientSecret,
|
|
17
|
-
|
|
18
|
+
redirectPath,
|
|
18
19
|
userInfoURL,
|
|
19
|
-
|
|
20
|
+
tokenRedirectPath
|
|
20
21
|
}: AuthCallbackProps) {
|
|
22
|
+
const domain = getDomain(req)
|
|
21
23
|
const searchParams = new URL(req.url).searchParams
|
|
22
24
|
|
|
23
25
|
if (!searchParams) {
|
|
@@ -38,7 +40,7 @@ export default async function authCallback({
|
|
|
38
40
|
client_id: clientID,
|
|
39
41
|
client_secret: clientSecret,
|
|
40
42
|
code: code as string,
|
|
41
|
-
redirect_uri:
|
|
43
|
+
redirect_uri: `${domain}${redirectPath}`,
|
|
42
44
|
grant_type: 'authorization_code',
|
|
43
45
|
}).toString()
|
|
44
46
|
})
|
|
@@ -69,7 +71,7 @@ export default async function authCallback({
|
|
|
69
71
|
|
|
70
72
|
const userInfo = await userInfoResponse.json() as UserInfo
|
|
71
73
|
|
|
72
|
-
const redirectUrl = new URL(
|
|
74
|
+
const redirectUrl = new URL(`${domain}${tokenRedirectPath}`)
|
|
73
75
|
const params = new URLSearchParams({
|
|
74
76
|
id: userInfo.sub,
|
|
75
77
|
name: userInfo.name,
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { NextRequest } from 'next/server'
|
|
2
|
+
|
|
3
|
+
export function getDomain(req: NextRequest): string {
|
|
4
|
+
const proto = req.headers.get('x-forwarded-proto') ?? new URL(req.url).protocol.replace(':', '')
|
|
5
|
+
const host = req.headers.get('x-forwarded-host') ?? req.headers.get('host') ?? new URL(req.url).host
|
|
6
|
+
return `${proto}://${host}`
|
|
7
|
+
}
|
package/src/utils/auth/login.ts
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { NextResponse } from 'next/server'
|
|
2
2
|
import type { AuthLoginProps } from 'uibee/utils'
|
|
3
|
+
import { getDomain } from './getDomain'
|
|
3
4
|
|
|
4
|
-
export default async function AuthLogin({ clientID,
|
|
5
|
+
export default async function AuthLogin({ req, clientID, redirectPath, authURL }: AuthLoginProps) {
|
|
6
|
+
const domain = getDomain(req)
|
|
5
7
|
const state = Math.random().toString(36).substring(5)
|
|
6
8
|
const authQueryParams = new URLSearchParams({
|
|
7
9
|
client_id: clientID,
|
|
8
|
-
redirect_uri:
|
|
10
|
+
redirect_uri: `${domain}${redirectPath}`,
|
|
9
11
|
response_type: 'code',
|
|
10
12
|
scope: 'openid profile email',
|
|
11
13
|
state: state,
|
package/src/utils/auth/logout.ts
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { NextResponse } from 'next/server'
|
|
2
2
|
import type { AuthLogoutProps } from 'uibee/utils'
|
|
3
|
+
import { getDomain } from './getDomain'
|
|
3
4
|
|
|
4
|
-
export default async function AuthLogout({
|
|
5
|
-
const
|
|
5
|
+
export default async function AuthLogout({ req, path }: AuthLogoutProps) {
|
|
6
|
+
const domain = getDomain(req)
|
|
7
|
+
const response = NextResponse.redirect(new URL(path || '/', domain))
|
|
6
8
|
|
|
7
9
|
const cookiesToRemove = [
|
|
8
10
|
'access_token',
|
package/src/utils/auth/token.ts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { NextResponse } from 'next/server'
|
|
2
2
|
import type { AuthTokenProps } from 'uibee/utils'
|
|
3
|
+
import { getDomain } from './getDomain'
|
|
3
4
|
|
|
4
|
-
export default async function AuthToken({ req,
|
|
5
|
+
export default async function AuthToken({ req, redirectPath }: AuthTokenProps) {
|
|
6
|
+
const domain = getDomain(req)
|
|
5
7
|
const url = new URL(req.url)
|
|
6
8
|
const token = url.searchParams.get('access_token')
|
|
7
9
|
const btg = url.searchParams.get('btg')
|
|
@@ -13,7 +15,7 @@ export default async function AuthToken({ req, frontendURL, redirectPath }: Auth
|
|
|
13
15
|
}
|
|
14
16
|
|
|
15
17
|
if (btg) {
|
|
16
|
-
return NextResponse.redirect(new URL(redirect,
|
|
18
|
+
return NextResponse.redirect(new URL(redirect, domain))
|
|
17
19
|
}
|
|
18
20
|
|
|
19
21
|
const accessToken = url.searchParams.get('access_token')!
|
|
@@ -23,7 +25,7 @@ export default async function AuthToken({ req, frontendURL, redirectPath }: Auth
|
|
|
23
25
|
const userEmail = url.searchParams.get('email')!
|
|
24
26
|
const userGroups = url.searchParams.get('groups')!
|
|
25
27
|
|
|
26
|
-
const response = NextResponse.redirect(new URL(redirect,
|
|
28
|
+
const response = NextResponse.redirect(new URL(redirect, domain))
|
|
27
29
|
response.cookies.set('access_token', accessToken)
|
|
28
30
|
response.cookies.set('user_id', userID)
|
|
29
31
|
response.cookies.set('user_name', username)
|