Skip to content

Commit 3f22775

Browse files
committed
feat: add QR code generation for user subscription URL
- Integrate uqr library for QR code rendering - Add "Show QR" button in user details modal - Update localization files with new QR-related translations
1 parent 899528c commit 3f22775

File tree

6 files changed

+63
-8
lines changed

6 files changed

+63
-8
lines changed

package-lock.json

Lines changed: 11 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@
4545
"@mantine/nprogress": "^7.17.1",
4646
"@monaco-editor/react": "^4.7.0",
4747
"@paralleldrive/cuid2": "2.2.2",
48-
"@remnawave/backend-contract": "0.3.6",
48+
"@remnawave/backend-contract": "0.3.7",
4949
"@stablelib/base64": "^2.0.1",
5050
"@stablelib/x25519": "^2.0.1",
5151
"@tabler/icons-react": "^3.31.0",
@@ -79,6 +79,7 @@
7979
"react-router-dom": "6.27.0",
8080
"recharts": "^2.15.1",
8181
"tiny-invariant": "^1.3.3",
82+
"uqr": "^0.1.2",
8283
"vite-plugin-deadfile": "^1.3.0",
8384
"xbytes": "^1.9.1",
8485
"zod": "^3.23.8",

public/locales/en/remnawave.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -257,7 +257,10 @@
257257
"user-details": "User details",
258258
"loading-user-data": "Loading user data...",
259259
"edit-user": "Edit user",
260-
"never": "Never"
260+
"never": "Never",
261+
"show-qr": "Show QR",
262+
"subscription-qr-code": "Subscription QR Code",
263+
"close": "Close"
261264
}
262265
},
263266
"base-api-token-form": {

public/locales/fa/remnawave.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -257,7 +257,10 @@
257257
"user-details": "جزئیات کاربر",
258258
"loading-user-data": "در حال بارگذاری اطلاعات کاربر...",
259259
"edit-user": "ویرایش کاربر",
260-
"never": "هرگز"
260+
"never": "هرگز",
261+
"close": "نزدیک",
262+
"show-qr": "نمایش QR",
263+
"subscription-qr-code": "اشتراک کد QR"
261264
}
262265
},
263266
"base-api-token-form": {

public/locales/ru/remnawave.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -257,7 +257,10 @@
257257
"user-details": "Информация о пользователе",
258258
"loading-user-data": "Загрузка данных пользователя...",
259259
"edit-user": "Редактировать пользователя",
260-
"never": "Никогда"
260+
"never": "Никогда",
261+
"close": "Закрыть",
262+
"show-qr": "Показать QR",
263+
"subscription-qr-code": "QR-код ссылки-подписки"
261264
}
262265
},
263266
"base-api-token-form": {

src/widgets/dashboard/users/view-user-modal/view-user-modal.widget.tsx

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,16 @@ import {
2323
PiCopy,
2424
PiFloppyDiskDuotone,
2525
PiLinkDuotone,
26+
PiQrCodeDuotone,
2627
PiUserDuotone
2728
} from 'react-icons/pi'
2829
import { UpdateUserCommand } from '@remnawave/backend-contract'
2930
import { useForm, zodResolver } from '@mantine/form'
3031
import { DateTimePicker } from '@mantine/dates'
3132
import { useTranslation } from 'react-i18next'
3233
import { useEffect, useMemo } from 'react'
34+
import { modals } from '@mantine/modals'
35+
import { renderSVG } from 'uqr'
3336
import dayjs from 'dayjs'
3437

3538
import {
@@ -383,6 +386,41 @@ export const ViewUserModal = () => {
383386
</ActionIcon.Group>
384387
</Group>
385388
<Group>
389+
<Button
390+
leftSection={<PiQrCodeDuotone size="1rem" />}
391+
onClick={() => {
392+
const subscriptionQrCode = renderSVG(
393+
user?.subscriptionUrl ?? '',
394+
{
395+
whiteColor: '#161B22',
396+
blackColor: '#3CC9DB'
397+
}
398+
)
399+
modals.open({
400+
centered: true,
401+
title: t('view-user-modal.widget.subscription-qr-code'),
402+
children: (
403+
<>
404+
<div
405+
dangerouslySetInnerHTML={{
406+
__html: subscriptionQrCode
407+
}}
408+
/>
409+
<Button
410+
fullWidth
411+
mt="md"
412+
onClick={() => modals.closeAll()}
413+
>
414+
{t('view-user-modal.widget.close')}
415+
</Button>
416+
</>
417+
)
418+
})
419+
}}
420+
size="md"
421+
>
422+
{t('view-user-modal.widget.show-qr')}
423+
</Button>
386424
{user && <ToggleUserStatusButtonFeature user={user} />}
387425
<Button
388426
color="blue"

0 commit comments

Comments
 (0)