From 92c7cb1b4e09800d40188918376ef18c968596a6 Mon Sep 17 00:00:00 2001 From: Rakib Ansary Date: Fri, 22 Mar 2024 01:18:35 +0600 Subject: [PATCH 01/15] fix: username/handle is more appropriate Signed-off-by: Rakib Ansary --- .circleci/config.yml | 2 +- src/apps/wallet-admin/src/home/tabs/payments/PaymentsTab.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index eb97a7ce7..d9b8f6456 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -257,7 +257,7 @@ workflows: branches: only: - dev - - feat/wallet-admin + - LVT-256 - deployQa: context: org-global diff --git a/src/apps/wallet-admin/src/home/tabs/payments/PaymentsTab.tsx b/src/apps/wallet-admin/src/home/tabs/payments/PaymentsTab.tsx index ed3167d6b..3c98823ca 100644 --- a/src/apps/wallet-admin/src/home/tabs/payments/PaymentsTab.tsx +++ b/src/apps/wallet-admin/src/home/tabs/payments/PaymentsTab.tsx @@ -263,7 +263,7 @@ const ListView: FC = (props: ListViewProps) => { filters={[ { key: 'winnerIds', - label: 'User ID', + label: 'Username/Handle', type: 'member_autocomplete', }, // { From 36c6df9e7a1661a5dbc1fc454d6bd5e525492ce0 Mon Sep 17 00:00:00 2001 From: Rakib Ansary Date: Fri, 22 Mar 2024 01:33:47 +0600 Subject: [PATCH 02/15] fix: include challenge id and title in edit and detailed view Signed-off-by: Rakib Ansary --- .../src/home/tabs/payments/PaymentsTab.tsx | 1 + .../components/payment-edit/PaymentEdit.tsx | 18 +++++++++++++----- .../components/payment-view/PaymentView.tsx | 18 +++++++++++++----- .../src/lib/models/WinningDetail.ts | 1 + 4 files changed, 28 insertions(+), 10 deletions(-) diff --git a/src/apps/wallet-admin/src/home/tabs/payments/PaymentsTab.tsx b/src/apps/wallet-admin/src/home/tabs/payments/PaymentsTab.tsx index 3c98823ca..3d2093abe 100644 --- a/src/apps/wallet-admin/src/home/tabs/payments/PaymentsTab.tsx +++ b/src/apps/wallet-admin/src/home/tabs/payments/PaymentsTab.tsx @@ -138,6 +138,7 @@ const ListView: FC = (props: ListViewProps) => { datePaid: payment.details[0].datePaid ? formatIOSDateString(payment.details[0].datePaid) : '-', description: payment.description, details: payment.details, + externalId: payment.externalId, handle: handleMap.get(parseInt(payment.winnerId, 10)) ?? payment.winnerId, id: payment.id, netPayment: formatCurrency(payment.details[0].totalAmount, payment.details[0].currency), diff --git a/src/apps/wallet-admin/src/lib/components/payment-edit/PaymentEdit.tsx b/src/apps/wallet-admin/src/lib/components/payment-edit/PaymentEdit.tsx index 9e061a12b..9af1a5e28 100644 --- a/src/apps/wallet-admin/src/lib/components/payment-edit/PaymentEdit.tsx +++ b/src/apps/wallet-admin/src/lib/components/payment-edit/PaymentEdit.tsx @@ -4,6 +4,7 @@ import { min } from 'date-fns' import React, { useEffect, useMemo, useState } from 'react' +import { TOPCODER_URL } from '~/config/environments/default.env' import { InputDatePicker, InputSelect, InputText } from '~/libs/ui' import { Winning } from '../../models/WinningDetail' @@ -154,9 +155,21 @@ const PaymentEdit: React.FC = (props: PaymentEditFormProps } }, [dirty, auditNote, props, netAmountErrorString.length, netAmount, paymentStatus, releaseDate, initialValues]) + const getLink = (externalId: string): string => `${TOPCODER_URL}/challenges/${externalId}` + return (
+ +
+ Payment ID +

{props.payment.id}

+
Handle

{props.payment.handle}

@@ -167,11 +180,6 @@ const PaymentEdit: React.FC = (props: PaymentEditFormProps

{props.payment.type}

-
- Description -

{props.payment.description}

-
- = (props: PaymentViewProps) => { return action } + const getLink = (externalId: string): string => `${TOPCODER_URL}/challenges/${externalId}` + return (
{view === 'details' && ( <> + +
+ Payment ID +

{props.payment.id}

+
Handle

{props.payment.handle}

@@ -87,11 +100,6 @@ const PaymentView: React.FC = (props: PaymentViewProps) => {

{props.payment.type}

-
- Description -

{props.payment.description}

-
-
Net Payment

{props.payment.netPaymentNumber.toLocaleString(undefined, { currency: 'USD', style: 'currency' })}

diff --git a/src/apps/wallet-admin/src/lib/models/WinningDetail.ts b/src/apps/wallet-admin/src/lib/models/WinningDetail.ts index cd4a2ff5e..5719c06c3 100644 --- a/src/apps/wallet-admin/src/lib/models/WinningDetail.ts +++ b/src/apps/wallet-admin/src/lib/models/WinningDetail.ts @@ -12,6 +12,7 @@ export interface PaymentDetail { export interface Winning { id: string description: string + externalId: string type: string handle: string; createDate: string From 3e1d82d3333b95645df0c2388dec4c440cb5c1db Mon Sep 17 00:00:00 2001 From: Rakib Ansary Date: Fri, 22 Mar 2024 07:47:19 +0600 Subject: [PATCH 03/15] fix(wallet-admin): add status filter Signed-off-by: Rakib Ansary --- .../src/home/tabs/payments/PaymentsTab.tsx | 46 +++++++++---------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/src/apps/wallet-admin/src/home/tabs/payments/PaymentsTab.tsx b/src/apps/wallet-admin/src/home/tabs/payments/PaymentsTab.tsx index 3d2093abe..a520b4b5b 100644 --- a/src/apps/wallet-admin/src/home/tabs/payments/PaymentsTab.tsx +++ b/src/apps/wallet-admin/src/home/tabs/payments/PaymentsTab.tsx @@ -309,29 +309,29 @@ const ListView: FC = (props: ListViewProps) => { // ], // type: 'dropdown', // }, - // { - // key: 'status', - // label: 'Status', - // options: [ - // { - // label: 'Available', - // value: 'OWED', - // }, - // { - // label: 'On Hold', - // value: 'ON_HOLD', - // }, - // { - // label: 'Paid', - // value: 'PAID', - // }, - // { - // label: 'Cancelled', - // value: 'CANCELLED', - // }, - // ], - // type: 'dropdown', - // }, + { + key: 'status', + label: 'Status', + options: [ + { + label: 'Owed', + value: 'OWED', + }, + { + label: 'On Hold', + value: 'ON_HOLD_ADMIN', + }, + { + label: 'Paid', + value: 'PAID', + }, + { + label: 'Cancelled', + value: 'CANCELLED', + }, + ], + type: 'dropdown', + }, { key: 'pageSize', label: 'Payments per page', From de1d9bf414b2a37125d8582ee7782675da98ec51 Mon Sep 17 00:00:00 2001 From: Rakib Ansary Date: Fri, 22 Mar 2024 10:10:08 +0600 Subject: [PATCH 04/15] feat(wallet-admin): add tax forms tab Signed-off-by: Rakib Ansary --- .../src/home/tabs/WalletAdminTabs.tsx | 3 + .../home/tabs/config/wallet-tabs-config.ts | 20 +- .../src/home/tabs/payments/PaymentsTab.tsx | 18 +- .../tabs/tax-forms/TaxFormsTab.module.scss | 35 +++ .../src/home/tabs/tax-forms/TaxFormsTab.tsx | 222 ++++++++++++++++++ .../src/home/tabs/tax-forms/index.ts | 1 + .../wallet-admin/src/lib/components/index.ts | 2 +- .../components/otp-modal/OtpModal.module.scss | 87 ------- .../src/lib/components/otp-modal/OtpModal.tsx | 140 ----------- .../src/lib/components/otp-modal/index.ts | 1 - .../PaymentProviderCard.module.scss | 90 ------- .../PaymentProviderCard.tsx | 173 -------------- .../components/payment-provider-card/index.ts | 1 - .../SettingSection.module.scss | 26 -- .../setting-section/SettingSection.tsx | 30 --- .../lib/components/setting-section/index.ts | 1 - .../tax-form-card/TaxFormCard.module.scss | 46 ---- .../components/tax-form-card/TaxFormCard.tsx | 83 ------- .../src/lib/components/tax-form-card/index.ts | 1 - .../tax-form-detail/TaxFormDetail.module.scss | 92 -------- .../tax-form-detail/TaxFormDetail.tsx | 140 ----------- .../lib/components/tax-form-detail/index.ts | 1 - .../tax-forms-table/TaxFormTable.module.scss | 109 +++++++++ .../tax-forms-table/TaxFormTable.tsx | 127 ++++++++++ .../lib/components/tax-forms-table/index.ts | 1 + src/apps/wallet-admin/src/lib/index.ts | 1 + .../src/lib/models/OtpVerificationResponse.ts | 3 - .../wallet-admin/src/lib/models/TaxForm.ts | 22 +- .../wallet-admin/src/lib/services/wallet.ts | 98 ++++---- .../src/lib/util/FormatISODateString.ts | 15 ++ src/apps/wallet-admin/src/lib/util/index.ts | 1 + 31 files changed, 578 insertions(+), 1012 deletions(-) create mode 100644 src/apps/wallet-admin/src/home/tabs/tax-forms/TaxFormsTab.module.scss create mode 100644 src/apps/wallet-admin/src/home/tabs/tax-forms/TaxFormsTab.tsx create mode 100644 src/apps/wallet-admin/src/home/tabs/tax-forms/index.ts delete mode 100644 src/apps/wallet-admin/src/lib/components/otp-modal/OtpModal.module.scss delete mode 100644 src/apps/wallet-admin/src/lib/components/otp-modal/OtpModal.tsx delete mode 100644 src/apps/wallet-admin/src/lib/components/otp-modal/index.ts delete mode 100644 src/apps/wallet-admin/src/lib/components/payment-provider-card/PaymentProviderCard.module.scss delete mode 100644 src/apps/wallet-admin/src/lib/components/payment-provider-card/PaymentProviderCard.tsx delete mode 100644 src/apps/wallet-admin/src/lib/components/payment-provider-card/index.ts delete mode 100644 src/apps/wallet-admin/src/lib/components/setting-section/SettingSection.module.scss delete mode 100644 src/apps/wallet-admin/src/lib/components/setting-section/SettingSection.tsx delete mode 100644 src/apps/wallet-admin/src/lib/components/setting-section/index.ts delete mode 100644 src/apps/wallet-admin/src/lib/components/tax-form-card/TaxFormCard.module.scss delete mode 100644 src/apps/wallet-admin/src/lib/components/tax-form-card/TaxFormCard.tsx delete mode 100644 src/apps/wallet-admin/src/lib/components/tax-form-card/index.ts delete mode 100644 src/apps/wallet-admin/src/lib/components/tax-form-detail/TaxFormDetail.module.scss delete mode 100644 src/apps/wallet-admin/src/lib/components/tax-form-detail/TaxFormDetail.tsx delete mode 100644 src/apps/wallet-admin/src/lib/components/tax-form-detail/index.ts create mode 100644 src/apps/wallet-admin/src/lib/components/tax-forms-table/TaxFormTable.module.scss create mode 100644 src/apps/wallet-admin/src/lib/components/tax-forms-table/TaxFormTable.tsx create mode 100644 src/apps/wallet-admin/src/lib/components/tax-forms-table/index.ts delete mode 100644 src/apps/wallet-admin/src/lib/models/OtpVerificationResponse.ts create mode 100644 src/apps/wallet-admin/src/lib/util/FormatISODateString.ts create mode 100644 src/apps/wallet-admin/src/lib/util/index.ts diff --git a/src/apps/wallet-admin/src/home/tabs/WalletAdminTabs.tsx b/src/apps/wallet-admin/src/home/tabs/WalletAdminTabs.tsx index a26d94225..3b047c47c 100644 --- a/src/apps/wallet-admin/src/home/tabs/WalletAdminTabs.tsx +++ b/src/apps/wallet-admin/src/home/tabs/WalletAdminTabs.tsx @@ -7,6 +7,7 @@ import { PageTitle, TabsNavbar, TabsNavItem } from '~/libs/ui' import { getHashFromTabId, getTabIdFromHash, WalletAdminTabsConfig, WalletAdminTabViews } from './config' import { PaymentsTab } from './payments' import { HomeTab } from './home' +import { TaxFormsTab } from './tax-forms' import styles from './WalletAdminTabs.module.scss' interface WalletHomeProps { @@ -44,6 +45,8 @@ const WalletAdminTabs: FC = (props: WalletHomeProps) => { {activeTab === WalletAdminTabViews.home && } {activeTab === WalletAdminTabViews.payments && } + + {activeTab === WalletAdminTabViews.taxforms && }
) } diff --git a/src/apps/wallet-admin/src/home/tabs/config/wallet-tabs-config.ts b/src/apps/wallet-admin/src/home/tabs/config/wallet-tabs-config.ts index afeb83052..568a1e481 100644 --- a/src/apps/wallet-admin/src/home/tabs/config/wallet-tabs-config.ts +++ b/src/apps/wallet-admin/src/home/tabs/config/wallet-tabs-config.ts @@ -3,7 +3,7 @@ import { TabsNavItem } from '~/libs/ui' export enum WalletAdminTabViews { home = '0', payments = '1', - // taxforms = '2', + taxforms = '2', // withdrawalmethods = '3', } @@ -20,10 +20,10 @@ export const WalletAdminTabsConfig: TabsNavItem[] = [ // id: WalletAdminTabViews.withdrawalmethods, // title: 'Withdrawal Methods', // }, - // { - // id: WalletAdminTabViews.taxforms, - // title: 'Tax Forms', - // }, + { + id: WalletAdminTabViews.taxforms, + title: 'Tax Forms', + }, ] export function getHashFromTabId(tabId: string): string { @@ -32,8 +32,8 @@ export function getHashFromTabId(tabId: string): string { return '#home' case WalletAdminTabViews.payments: return '#payments' - // case WalletAdminTabViews.taxforms: - // return '#tax-forms' + case WalletAdminTabViews.taxforms: + return '#tax-forms' // case WalletAdminTabViews.withdrawalmethods: // return '#withdrawal-methods' default: @@ -43,10 +43,10 @@ export function getHashFromTabId(tabId: string): string { export function getTabIdFromHash(hash: string): string { switch (hash) { - case '#winnings': + case '#payments': return WalletAdminTabViews.payments - // case '#tax-forms': - // return WalletAdminTabViews.taxforms + case '#tax-forms': + return WalletAdminTabViews.taxforms // case '#withdrawal-methods': // return WalletAdminTabViews.withdrawalmethods default: diff --git a/src/apps/wallet-admin/src/home/tabs/payments/PaymentsTab.tsx b/src/apps/wallet-admin/src/home/tabs/payments/PaymentsTab.tsx index a520b4b5b..205f1df4e 100644 --- a/src/apps/wallet-admin/src/home/tabs/payments/PaymentsTab.tsx +++ b/src/apps/wallet-admin/src/home/tabs/payments/PaymentsTab.tsx @@ -8,7 +8,7 @@ import { UserProfile } from '~/libs/core' import { editPayment, getMemberHandle, getPayments } from '../../../lib/services/wallet' import { Winning, WinningDetail } from '../../../lib/models/WinningDetail' -import { FilterBar, PaymentView } from '../../../lib' +import { FilterBar, formatIOSDateString, PaymentView } from '../../../lib' import { ConfirmFlowData } from '../../../lib/models/ConfirmFlowData' import { PaginationInfo } from '../../../lib/models/PaginationInfo' import PaymentEditForm from '../../../lib/components/payment-edit/PaymentEdit' @@ -21,22 +21,6 @@ interface ListViewProps { profile: UserProfile } -function formatIOSDateString(iosDateString: string): string { - const date = new Date(iosDateString) - - if (Number.isNaN(date.getTime())) { - throw new Error('Invalid date string') - } - - const options: Intl.DateTimeFormatOptions = { - day: '2-digit', - month: '2-digit', - year: 'numeric', - } - - return date.toLocaleDateString('en-GB', options) -} - function formatStatus(status: string): string { switch (status) { case 'ON_HOLD': diff --git a/src/apps/wallet-admin/src/home/tabs/tax-forms/TaxFormsTab.module.scss b/src/apps/wallet-admin/src/home/tabs/tax-forms/TaxFormsTab.module.scss new file mode 100644 index 000000000..4d5773ab0 --- /dev/null +++ b/src/apps/wallet-admin/src/home/tabs/tax-forms/TaxFormsTab.module.scss @@ -0,0 +1,35 @@ +@import '@libs/ui/styles/includes'; + +.container { + background-color: $black-5; + padding: $sp-6; + margin: $sp-8 0; + border-radius: 6px; + + @include ltelg { + padding: $sp-4; + } + + .header { + display: flex; + justify-content: flex-start; + gap: 5px; + align-items: center; + + @include ltelg { + flex-direction: column; + } + } + + .content { + background-color: $tc-white; + border-radius: 4px; + margin-top: $sp-4; + .centered { + height: 200px; + display: flex; + justify-content: space-around; + align-items: center; + } + } +} diff --git a/src/apps/wallet-admin/src/home/tabs/tax-forms/TaxFormsTab.tsx b/src/apps/wallet-admin/src/home/tabs/tax-forms/TaxFormsTab.tsx new file mode 100644 index 000000000..977a79c27 --- /dev/null +++ b/src/apps/wallet-admin/src/home/tabs/tax-forms/TaxFormsTab.tsx @@ -0,0 +1,222 @@ +/* eslint-disable max-len */ +/* eslint-disable react/jsx-no-bind */ +import { toast } from 'react-toastify' +import React, { FC, useCallback, useEffect } from 'react' + +import { Collapsible, ConfirmModal, LoadingCircles } from '~/libs/ui' +import { UserProfile } from '~/libs/core' +import { downloadBlob } from '~/libs/shared' + +import { deleteTaxForm, downloadTaxForm, getMemberHandle, getTaxForms } from '../../../lib/services/wallet' +import { TaxForm } from '../../../lib/models/TaxForm' +import { FilterBar, formatIOSDateString, TaxFormTable } from '../../../lib' +import { PaginationInfo } from '../../../lib/models/PaginationInfo' + +import styles from './TaxFormsTab.module.scss' + +interface ListViewProps { + // eslint-disable-next-line react/no-unused-prop-types + profile: UserProfile +} + +// eslint-disable-next-line @typescript-eslint/no-unused-vars +const ListView: FC = (props: ListViewProps) => { + const [confirmFlow, setConfirmFlow] = React.useState<{ + form: TaxForm + } | undefined>(undefined) + const [isLoading, setIsLoading] = React.useState(false) + const [filters, setFilters] = React.useState>({}) + const [forms, setForms] = React.useState([]) + const [userIds, setUserIds] = React.useState([]) + const [pagination, setPagination] = React.useState({ + currentPage: 1, + pageSize: 10, + totalItems: 0, + totalPages: 0, + }) + + const fetchTaxForms = useCallback(async () => { + if (isLoading) { + return + } + + setIsLoading(true) + try { + + const taxFormsResponse = await getTaxForms(pagination.pageSize, (pagination.currentPage - 1) * pagination.pageSize, userIds) + const tmpUserIds = taxFormsResponse.forms.map(form => form.userId) + const handleMap = await getMemberHandle(tmpUserIds) + + const taxForms = taxFormsResponse.forms.map((form: TaxForm) => ({ ...form, dateFiled: form.dateFiled ? formatIOSDateString(form.dateFiled) : '-', handle: handleMap.get(parseInt(form.userId, 10)) ?? form.userId })) + + setForms(taxForms) + setPagination(taxFormsResponse.pagination) + } catch (apiError) { + console.error('Failed to fetch winnings:', apiError) + } finally { + setIsLoading(false) + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [pagination.pageSize, pagination.currentPage, userIds]) + + useEffect(() => { + fetchTaxForms() + }, [fetchTaxForms]) + + return ( + <> +
+
+

Member Tax Forms

+
+
+ Tax Forms Listing}> + { + const newPagination = { + ...pagination, + currentPage: 1, + } + if (key === 'pageSize') { + newPagination.pageSize = parseInt(value[0], 10) + } + + if (key === 'userIds') { + setUserIds(value) + } + + setPagination(newPagination) + setFilters({ + ...filters, + [key]: value, + }) + }} + onResetFilters={() => { + setPagination({ + ...pagination, + currentPage: 1, + pageSize: 10, + }) + setFilters({}) + }} + /> + {isLoading && } + {!isLoading && forms.length > 0 && ( + { + setPagination({ + ...pagination, + currentPage: pagination.currentPage - 1, + }) + }} + onNextPageClick={() => { + setPagination({ + ...pagination, + currentPage: pagination.currentPage + 1, + }) + }} + onPageClick={(pageNumber: number) => { + setPagination({ + ...pagination, + currentPage: pageNumber, + }) + }} + onDownloadClick={async (form: TaxForm) => { + toast.success('Downloading tax form. Please wait...', { position: 'bottom-right' }) + try { + downloadBlob( + await downloadTaxForm(form.userId, form.id), + `tax-form-${form.userId}-${new Date() + .getTime()}.pdf`, + ) + } catch (err) { + toast.error('Failed to download tax form. Please try again later', { position: 'bottom-right' }) + } + }} + onDeleteClick={async (form: TaxForm) => { + setConfirmFlow({ form }) + }} + /> + )} + {!isLoading && forms.length === 0 && ( +
+

+ {Object.keys(filters).length === 0 + ? 'Member earnings will appear here.' + : 'No payments match your filters.'} +

+
+ )} +
+
+
+ {confirmFlow && ( + { + setConfirmFlow(undefined) + }} + onConfirm={async () => { + const userId = confirmFlow.form.userId + const formId = confirmFlow.form.id + setConfirmFlow(undefined) + + toast.success('Deleting tax form. Please wait...', { position: 'bottom-right' }) + try { + await deleteTaxForm(userId, formId) + toast.success('Successfully deleted tax-form.', { position: 'bottom-right' }) + } catch (err) { + toast.error('Failed to delete users tax-form. Please try again later', { position: 'bottom-right' }) + } + + fetchTaxForms() + }} + open={confirmFlow !== undefined} + > +
+

+ Are you sure you want to reset the tax-form of the member + {' '} + {confirmFlow.form.handle} + ? +

+
+

This action cannot be undone.

+
+
+ )} + + ) +} + +export default ListView diff --git a/src/apps/wallet-admin/src/home/tabs/tax-forms/index.ts b/src/apps/wallet-admin/src/home/tabs/tax-forms/index.ts new file mode 100644 index 000000000..08eb9c245 --- /dev/null +++ b/src/apps/wallet-admin/src/home/tabs/tax-forms/index.ts @@ -0,0 +1 @@ +export { default as TaxFormsTab } from './TaxFormsTab' diff --git a/src/apps/wallet-admin/src/lib/components/index.ts b/src/apps/wallet-admin/src/lib/components/index.ts index 2beab614a..eb2f27235 100644 --- a/src/apps/wallet-admin/src/lib/components/index.ts +++ b/src/apps/wallet-admin/src/lib/components/index.ts @@ -1,6 +1,6 @@ -export * from './setting-section' export * from './info-row' export * from './chip' export * from './filter-bar' export * from './payment-edit' export * from './payment-view' +export * from './tax-forms-table' diff --git a/src/apps/wallet-admin/src/lib/components/otp-modal/OtpModal.module.scss b/src/apps/wallet-admin/src/lib/components/otp-modal/OtpModal.module.scss deleted file mode 100644 index 9c5d0a5a2..000000000 --- a/src/apps/wallet-admin/src/lib/components/otp-modal/OtpModal.module.scss +++ /dev/null @@ -1,87 +0,0 @@ -@import '@libs/ui/styles/includes'; - -.otp-modal { - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - padding: 20px; - padding-bottom: 0; - - .error { - color: red; - } - - .otpInput { - width: 48px !important; - height: 48px; - margin: 5px; - text-align: center; - font-size: 1rem; - border: 2px solid #ccc; - border-radius: 4px; - - &::-webkit-inner-spin-button, - &::-webkit-outer-spin-button { - -webkit-appearance: none; - margin: 0; - } - - &::-moz-focus-inner { - border: 0; - } - - &[type='number'] { - -moz-appearance: textfield; - } - - &::-ms-clear, - &::-ms-reveal { - display: none; - width: 0; - height: 0; - } - - &[type='number']::placeholder { - color: transparent; - } - - &:focus { - outline: none; - border-color: #007bff; - } - } - - h3 { - font-size: 1.5rem; - text-align: center; - margin-bottom: 20px; - } - - .otpInputStyle { - width: 40px; - height: 50px; - margin: 0 5px; - text-align: center; - font-size: 2rem; - border: 1px solid #ccc; - border-radius: 4px; - - &:focus { - outline: none; - border-color: blue; - } - } - - .otpInputFocusStyle { - border-color: #007bff; - } - - p { - font-size: 0.9rem; - color: #666; - text-align: center; - margin-top: $sp-1; - margin-bottom: $sp-4; - } -} diff --git a/src/apps/wallet-admin/src/lib/components/otp-modal/OtpModal.tsx b/src/apps/wallet-admin/src/lib/components/otp-modal/OtpModal.tsx deleted file mode 100644 index d91a0e976..000000000 --- a/src/apps/wallet-admin/src/lib/components/otp-modal/OtpModal.tsx +++ /dev/null @@ -1,140 +0,0 @@ -import { toast } from 'react-toastify' -import OTPInput, { InputProps } from 'react-otp-input' -import React, { FC } from 'react' - -import { BaseModal, LinkButton, LoadingCircles } from '~/libs/ui' -import { resendOtp, verifyOtp } from '~/apps/wallet/src/lib/services/wallet' - -import { OtpVerificationResponse } from '../../models/OtpVerificationResponse' - -import styles from './OtpModal.module.scss' - -const RESEND_OTP_TIMEOUT = 60000 - -interface OtpModalProps { - isOpen: boolean - key: string - transactionId: string - userEmail?: string - isBlob?: boolean - onClose: () => void - onOtpVerified: (data: unknown) => void -} - -const OtpModal: FC = (props: OtpModalProps) => { - const [otp, setOtp] = React.useState('') - const [loading, setLoading] = React.useState(false) - const [error, setError] = React.useState('') - const [showResendButton, setShowResendButton] = React.useState(false) - - // eslint-disable-next-line consistent-return - React.useEffect(() => { - let timer: NodeJS.Timeout | undefined - if (props.isOpen) { - setShowResendButton(false) - timer = setTimeout(() => { - setShowResendButton(true) - }, RESEND_OTP_TIMEOUT) - } - - return () => { - if (timer) { - clearTimeout(timer) - } - } - }, [props.isOpen]) - - React.useEffect(() => { - if (!props.isOpen) { - setOtp('') - setError('') - } - }, [props.isOpen]) - - function handleChange(code: string): void { - setOtp(code) - if (code.length === 6) { - setLoading(true) - verifyOtp(props.transactionId, code, props.isBlob) - .then((response: OtpVerificationResponse | Blob) => { - setLoading(false) - props.onOtpVerified(response) - }) - .catch((err: Error) => { - setLoading(false) - setError(err.message) - }) - } else if (code.length < 6) { - setError('') - } - } - - return ( - -
- {error &&

{error}

} -

- For added security we’ve sent a 6-digit code to your - {' '} - {props.userEmail ?? '***@gmail.com'} - {' '} - email. The code - expires shortly, so please enter it soon. -

- } - onChange={handleChange} - inputType='number' - shouldAutoFocus - inputStyle={styles.otpInput} - /> - -

Can't find the code? Check your spam folder.

- {loading && } - {!loading && showResendButton && ( - { - setShowResendButton(true) - }, RESEND_OTP_TIMEOUT) - toast.success( - 'OTP sent successfully.', - { position: toast.POSITION.BOTTOM_RIGHT }, - ) - } catch (err: unknown) { - toast.error( - (err as Error).message ?? 'Something went wrong. Please try again.', - { position: toast.POSITION.BOTTOM_RIGHT }, - ) - } - }} - /> - )} -
-
- ) -} - -export default OtpModal diff --git a/src/apps/wallet-admin/src/lib/components/otp-modal/index.ts b/src/apps/wallet-admin/src/lib/components/otp-modal/index.ts deleted file mode 100644 index 9d973de1e..000000000 --- a/src/apps/wallet-admin/src/lib/components/otp-modal/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as OtpModal } from './OtpModal' diff --git a/src/apps/wallet-admin/src/lib/components/payment-provider-card/PaymentProviderCard.module.scss b/src/apps/wallet-admin/src/lib/components/payment-provider-card/PaymentProviderCard.module.scss deleted file mode 100644 index 3a56c65d7..000000000 --- a/src/apps/wallet-admin/src/lib/components/payment-provider-card/PaymentProviderCard.module.scss +++ /dev/null @@ -1,90 +0,0 @@ -@import '@libs/ui/styles/includes'; - -.card { - display: flex; - flex-direction: row; - align-items: flex-start; - justify-content: space-between; - border-radius: 8px; - background-color: white; - border: 1px solid #D4D4D4; - - .content { - display: flex; - flex-direction: column; - align-items: flex-start; - padding: 16px; - - .header { - width: 100%; - display: flex; - flex-direction: row; - justify-content: space-between; - align-items: center; - } - - .detailContainer { - display: grid; - width: 100%; - - &.singleRow { - grid-template-columns: repeat(3, 1fr); - margin-top: 24px; - gap: $sp-6; - } - - &.stackedRows { - grid-template-columns: 1fr; - .detail:not(:last-child) { - margin-bottom: 8px; - } - } - - .detail { - display: flex; - flex-direction: column; - align-items: flex-start; - gap: 4px; - - .iconLabelContainer { - display: flex; - } - - .label { - margin-left: 8px; - color: $teal-140; - font-family: $font-roboto-mono; - font-size: 12px; - font-weight: 700; - line-height: 16px; - letter-spacing: 1px; - text-align: left; - } - - .value { - color: #2a2a2a; - font-size: 14px; - } - } - } - - .footer { - margin-top: 24px; - } - } - - .actionItems { - padding-top: 16px; - margin-right: 24px; - - .actionItemsContainer { - display: flex; - flex-direction: column; - align-items: flex-end; - - .warningLabel { - color: $legacy-120; - } - } - } -} diff --git a/src/apps/wallet-admin/src/lib/components/payment-provider-card/PaymentProviderCard.tsx b/src/apps/wallet-admin/src/lib/components/payment-provider-card/PaymentProviderCard.tsx deleted file mode 100644 index c65f09406..000000000 --- a/src/apps/wallet-admin/src/lib/components/payment-provider-card/PaymentProviderCard.tsx +++ /dev/null @@ -1,173 +0,0 @@ -import { useMemo, useState } from 'react' - -import { CheckCircleIcon } from '@heroicons/react/solid' -import { Button, ConfirmModal, IconOutline, IconSolid, PageDivider } from '~/libs/ui' - -import { ActionBarItem } from '../action-bar-item' -import { PaymentProvider } from '../../models/PaymentProvider' -import { ConfirmFlowData } from '../../models/ConfirmFlowData' - -import styles from './PaymentProviderCard.module.scss' - -interface Detail { - icon: React.ReactNode - label: string - value: string -} - -interface PaymentProviderProps { - provider: PaymentProvider - logo: React.ReactNode - details: Detail[] - onConnectClick?: () => void - onResendOtpClick?: () => void - onGoToRegistrationClick?: () => void - onRemoveProvider?: () => void -} - -const PaymentProviderCard: React.FC = (props: PaymentProviderProps) => { - const [confirmFlow, setConfirmFlow] = useState(undefined) - - const renderConfirmModalContent = useMemo(() => { - if (confirmFlow?.content === undefined) { - return undefined - } - - if (typeof confirmFlow?.content === 'function') { - return confirmFlow?.content() - } - - return confirmFlow?.content - }, [confirmFlow]) - - const canConnect = props.provider.status === 'NOT_CONNECTED' - const canCancel = ['OTP_PENDING', 'OTP_VERIFIED', 'VERIFIED', 'CONNECTED'].includes(props.provider.status) - - const renderOtpPending = (): JSX.Element => ( - - ) - - const renderOtpVerified = (): JSX.Element => ( - - ) - - return ( - <> -
-
-
-
{props.logo}
-
- - {canConnect && } - -
- {props.details.map((detail: Detail) => ( -
-
- {detail.icon} - {detail.label} -
-

{detail.value}

-
- ))} -
- - {canConnect && ( -
-
- )} - {canCancel && ( -
-
- )} -
-
- {props.provider.status === 'CONNECTED' - &&
-
- {confirmFlow && ( - -
{renderConfirmModalContent}
-
- )} - - ) -} - -export default PaymentProviderCard diff --git a/src/apps/wallet-admin/src/lib/components/payment-provider-card/index.ts b/src/apps/wallet-admin/src/lib/components/payment-provider-card/index.ts deleted file mode 100644 index a3a1c4984..000000000 --- a/src/apps/wallet-admin/src/lib/components/payment-provider-card/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as PaymentProviderCard } from './PaymentProviderCard' diff --git a/src/apps/wallet-admin/src/lib/components/setting-section/SettingSection.module.scss b/src/apps/wallet-admin/src/lib/components/setting-section/SettingSection.module.scss deleted file mode 100644 index dd4087c74..000000000 --- a/src/apps/wallet-admin/src/lib/components/setting-section/SettingSection.module.scss +++ /dev/null @@ -1,26 +0,0 @@ -@import '@libs/ui/styles/includes'; - -.container { - display: flex; - padding: $sp-4; - border: 1px solid $black-20; - border-radius: 8px; - margin-top: $sp-4; - flex-wrap: wrap; - - .contentMiddle { - display: flex; - flex-direction: column; - flex: 1; - align-self: center; - - @include ltelg { - margin-right: $sp-4; - } - - .infoText { - color: #767676; - max-width: 85%; - } - } -} \ No newline at end of file diff --git a/src/apps/wallet-admin/src/lib/components/setting-section/SettingSection.tsx b/src/apps/wallet-admin/src/lib/components/setting-section/SettingSection.tsx deleted file mode 100644 index 380286fdf..000000000 --- a/src/apps/wallet-admin/src/lib/components/setting-section/SettingSection.tsx +++ /dev/null @@ -1,30 +0,0 @@ -import { FC } from 'react' -import classNames from 'classnames' - -import styles from './SettingSection.module.scss' - -interface SettingSectionProps { - containerClassName?: string - readonly title: string - readonly infoText?: string - actionElement?: React.ReactNode - leftElement?: React.ReactNode -} - -const SettingSection: FC = (props: SettingSectionProps) => ( -
- {props.leftElement} - -
-

{props.title}

-

-

- - {props.actionElement} -
-) - -export default SettingSection diff --git a/src/apps/wallet-admin/src/lib/components/setting-section/index.ts b/src/apps/wallet-admin/src/lib/components/setting-section/index.ts deleted file mode 100644 index a2a2fec21..000000000 --- a/src/apps/wallet-admin/src/lib/components/setting-section/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as SettingSection } from './SettingSection' diff --git a/src/apps/wallet-admin/src/lib/components/tax-form-card/TaxFormCard.module.scss b/src/apps/wallet-admin/src/lib/components/tax-form-card/TaxFormCard.module.scss deleted file mode 100644 index 46c3eb47d..000000000 --- a/src/apps/wallet-admin/src/lib/components/tax-form-card/TaxFormCard.module.scss +++ /dev/null @@ -1,46 +0,0 @@ -@import '@libs/ui/styles/includes'; - -.card { - display: flex; - flex-direction: column; - align-items: flex-start; - justify-content: space-between; - background-color: white; - padding: 16px; - border-radius: 8px; - border: 1px solid #eaeaea; - margin: 16px 0; - - .header { - display: flex; - align-items: center; - justify-content: flex-start; - gap: 24px; - - .icon { - max-width: 48px; - max-height: 48px; - } - } - - .content { - display: flex; - flex-direction: column; - gap: 16px; - flex: 1; - - .additionalInfoPurpose { - ul { - list-style-type: disc; - padding: 10px 24px; - } - } - } - - .footer { - display: flex; - width: 100%; - justify-content: space-between; - margin-top: 24px; - } -} diff --git a/src/apps/wallet-admin/src/lib/components/tax-form-card/TaxFormCard.tsx b/src/apps/wallet-admin/src/lib/components/tax-form-card/TaxFormCard.tsx deleted file mode 100644 index 3a8892142..000000000 --- a/src/apps/wallet-admin/src/lib/components/tax-form-card/TaxFormCard.tsx +++ /dev/null @@ -1,83 +0,0 @@ -import React from 'react' - -import { Button, PageDivider } from '~/libs/ui' - -import styles from './TaxFormCard.module.scss' - -interface TaxFormCardProps { - formTitle: string - formDescription: string - reasonTitle: string - reasonDescription: string - instructionsLink: string - instructionsLabel: string - completionLabel: string - additionalInfo?: { - link?: { - text: string - href: string - } - purpose?: { - title: string - points: string[] - } - note?: string - } - icon: React.ReactNode - onSetupClick: () => void -} - -const TaxFormCard: React.FC = (props: TaxFormCardProps) => ( -
-
-
{props.icon}
-

{props.formTitle}

-
- - - -
-
{props.formDescription}
- -

{props.reasonTitle}

-
{props.reasonDescription}
- - {props.additionalInfo?.link && ( - - )} - - {props.additionalInfo?.purpose && ( -
-

{props.additionalInfo.purpose.title}

-
    - {props.additionalInfo.purpose.points.map((point: string) => ( -
  • {point}
  • - ))} -
-
- )} - - {props.additionalInfo?.note && ( -
-
{props.additionalInfo.note}
-
- )} -
- -
-
-
-) - -export default TaxFormCard diff --git a/src/apps/wallet-admin/src/lib/components/tax-form-card/index.ts b/src/apps/wallet-admin/src/lib/components/tax-form-card/index.ts deleted file mode 100644 index 4b7cccbab..000000000 --- a/src/apps/wallet-admin/src/lib/components/tax-form-card/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as TaxFormCard } from './TaxFormCard' diff --git a/src/apps/wallet-admin/src/lib/components/tax-form-detail/TaxFormDetail.module.scss b/src/apps/wallet-admin/src/lib/components/tax-form-detail/TaxFormDetail.module.scss deleted file mode 100644 index bf64b99b9..000000000 --- a/src/apps/wallet-admin/src/lib/components/tax-form-detail/TaxFormDetail.module.scss +++ /dev/null @@ -1,92 +0,0 @@ -@import '@libs/ui/styles/includes'; - -.card { - display: flex; - flex-direction: row; - align-items: center; - justify-content: space-between; - background-color: white; - padding: 16px; - border-radius: 8px; - gap: $sp-4; - border: 1px solid #eaeaea; - margin: 16px 0; - - .iconContainer { - width: 64px; - height: 64px; - display: flex; - justify-content: center; - align-items: center; - - background: linear-gradient(264.69deg, #198807 2.17%, #017c6d 97.49%); - border-radius: 4px; - - .icon { - width: 26.67px; - height: 26.67px; - top: 2.67px; - left: 2.67px; - fill: white; - } - } - - .content { - display: flex; - flex-direction: column; - flex: 1; - } - - .actionItems { - display: flex; - align-items: center; - width: 64px; - justify-content: space-between; - - .actionButton { - width: 32px; - height: 32px; - border: none; - cursor: pointer; - display: flex; - justify-content: center; - align-items: center; - } - - .downloadIcon { - width: 24px; - height: 24px; - fill: $turq-160; - } - - .deleteIcon { - width: 24px; - height: 24px; - fill: $red-140; - } - } - - .actionItemsStacked { - display: flex; - flex-direction: column; - align-items: flex-end; - - .warningLabel { - color: $legacy-120; - } - } - - .actionButton, - .loadingWrapper { - transition: opacity 0.3s ease, transform 0.3s ease; - opacity: 1; - transform: scale(1); - } - - .hidden { - opacity: 0; - display: none; - transform: scale(0.95); - pointer-events: none; - } -} diff --git a/src/apps/wallet-admin/src/lib/components/tax-form-detail/TaxFormDetail.tsx b/src/apps/wallet-admin/src/lib/components/tax-form-detail/TaxFormDetail.tsx deleted file mode 100644 index 74d0673dd..000000000 --- a/src/apps/wallet-admin/src/lib/components/tax-form-detail/TaxFormDetail.tsx +++ /dev/null @@ -1,140 +0,0 @@ -import React, { useMemo } from 'react' - -import { DownloadIcon, ExclamationCircleIcon, TrashIcon } from '@heroicons/react/solid' -import { ConfirmModal, IconSolid } from '~/libs/ui' - -import { IconCheckCircle } from '../../assets/tax-forms' -import { ActionBarItem } from '../action-bar-item' -import { ConfirmFlowData } from '../../models/ConfirmFlowData' - -import styles from './TaxFormDetail.module.scss' - -interface TaxFormDetailProps { - title: string - description: string - status: string - onGetRecipientURL?: () => void - onResendOtpClick?: () => void - onDownloadClick?: () => void - onDeleteClick?: () => void -} - -const TaxFormDetail: React.FC = (props: TaxFormDetailProps) => { - const [confirmFlow, setConfirmFlow] = React.useState(undefined) - - const renderConfirmModalContent = useMemo(() => { - if (confirmFlow?.content === undefined) { - return undefined - } - - if (typeof confirmFlow?.content === 'function') { - return confirmFlow?.content() - } - - return confirmFlow?.content - }, [confirmFlow]) - - const renderOtpPending = (): JSX.Element => ( - - ) - - const renderOtpVerified = (): JSX.Element => ( - - ) - - const renderActive = (): JSX.Element => ( -
- - -
- ) - - return ( - <> -
-
- {props.status === 'ACTIVE' && } - {props.status !== 'ACTIVE' && } -
- -
-
{props.title}
-
{props.description}
-
- - {props.status === 'OTP_PENDING' && renderOtpPending()} - {props.status === 'OTP_VERIFIED' && renderOtpVerified()} - {props.status === 'ACTIVE' && renderActive()} -
- {confirmFlow && ( - -
{renderConfirmModalContent}
-
- )} - - ) -} - -export default TaxFormDetail diff --git a/src/apps/wallet-admin/src/lib/components/tax-form-detail/index.ts b/src/apps/wallet-admin/src/lib/components/tax-form-detail/index.ts deleted file mode 100644 index bfe5dc606..000000000 --- a/src/apps/wallet-admin/src/lib/components/tax-form-detail/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as TaxFormDetail } from './TaxFormDetail' diff --git a/src/apps/wallet-admin/src/lib/components/tax-forms-table/TaxFormTable.module.scss b/src/apps/wallet-admin/src/lib/components/tax-forms-table/TaxFormTable.module.scss new file mode 100644 index 000000000..5e4ea7c5a --- /dev/null +++ b/src/apps/wallet-admin/src/lib/components/tax-forms-table/TaxFormTable.module.scss @@ -0,0 +1,109 @@ +@import '@libs/ui/styles/includes'; + +.tableContainer { + width: 100%; + overflow-x: auto; + margin-top: $sp-2; +} + +table { + width: 100%; + border-collapse: separate; + border-spacing: 0; + margin: 16px 0; + + th, + td { + text-align: left; + padding: 8px; + + &:last-child { + width: 50px; + } + } + + tbody { + tr { + &:nth-child(odd) { + background-color: #f4f4f4; + } + &:nth-child(even) { + background-color: #ffffff; + } + + .capitalize { + text-transform: capitalize; + } + } + } + + th { + top: 0; + background-color: white !important; + text-transform: uppercase; + } + + tbody tr td:first-child { + border-top-left-radius: 8px; + border-bottom-left-radius: 8px; + } + + tbody tr td:last-child { + border-top-right-radius: 8px; + border-bottom-right-radius: 8px; + } + +} + +.selected { + background-color: #e7f4ff; +} + +.pageButtons { + display: flex; + justify-content: flex-end; + align-items: center; + margin-top: 16px; + gap: $sp-4; + + .pageNumbers { + display: flex; + justify-content: center; + align-items: center; + gap: $sp-1; + } + +} + +.footer { + display: flex; + flex-direction: column; + justify-content: space-between; + align-items: center; + margin-top: 16px; + padding-bottom: 16px; + border-radius: 8px; + background-color: white; + border: 1px solid #eaeaea; + + .total { + font-size: 18px; + font-weight: bold; + + color: #333; + } +} + +.actionButtons { + padding-right: 50px; + display: flex; + justify-content: center; + align-items: center; +} + +@media (max-width: 768px) { + .footer { + flex-direction: column; + align-items: center; + } +} diff --git a/src/apps/wallet-admin/src/lib/components/tax-forms-table/TaxFormTable.tsx b/src/apps/wallet-admin/src/lib/components/tax-forms-table/TaxFormTable.tsx new file mode 100644 index 000000000..e777badd1 --- /dev/null +++ b/src/apps/wallet-admin/src/lib/components/tax-forms-table/TaxFormTable.tsx @@ -0,0 +1,127 @@ +/* eslint-disable max-len */ +/* eslint-disable react/jsx-no-bind */ +/* eslint-disable @typescript-eslint/explicit-function-return-type */ +import React from 'react' + +import { Button, IconOutline, Tooltip } from '~/libs/ui' + +import { TaxForm } from '../../models/TaxForm' + +import styles from './TaxFormTable.module.scss' + +interface TaxFormTableProps { + taxForms: ReadonlyArray; + currentPage: number; + numPages: number; + onNextPageClick: () => void; + onPreviousPageClick: () => void; + onPageClick: (pageNumber: number) => void; + onDownloadClick?: (form: TaxForm) => void; + onDeleteClick?: (form: TaxForm) => void; +} + +const TaxFormTable: React.FC = (props: TaxFormTableProps) => { + console.log('Tax Forms', props.taxForms) + + return ( + <> +
+ + + + + + + + + + + + {props.taxForms.map(form => ( + + + + + + + + ))} + +
HANDLEFORMDATE FILEDSTATUS
{form.handle}{form.taxForm.name}{form.dateFiled}{form.status} + +
+
+ + {props.numPages > 1 && ( +
+
+
+ {props.currentPage < props.numPages - 2 && ...} +
+
+ )} + + ) +} + +export default TaxFormTable diff --git a/src/apps/wallet-admin/src/lib/components/tax-forms-table/index.ts b/src/apps/wallet-admin/src/lib/components/tax-forms-table/index.ts new file mode 100644 index 000000000..f526c746a --- /dev/null +++ b/src/apps/wallet-admin/src/lib/components/tax-forms-table/index.ts @@ -0,0 +1 @@ +export { default as TaxFormTable } from './TaxFormTable' diff --git a/src/apps/wallet-admin/src/lib/index.ts b/src/apps/wallet-admin/src/lib/index.ts index 0f5e459b8..3774aa6b7 100644 --- a/src/apps/wallet-admin/src/lib/index.ts +++ b/src/apps/wallet-admin/src/lib/index.ts @@ -1,3 +1,4 @@ export * from './wallet-swr' export * from './assets' export * from './components' +export * from './util' diff --git a/src/apps/wallet-admin/src/lib/models/OtpVerificationResponse.ts b/src/apps/wallet-admin/src/lib/models/OtpVerificationResponse.ts deleted file mode 100644 index 53456138d..000000000 --- a/src/apps/wallet-admin/src/lib/models/OtpVerificationResponse.ts +++ /dev/null @@ -1,3 +0,0 @@ -export interface OtpVerificationResponse { - data: unknown; - } diff --git a/src/apps/wallet-admin/src/lib/models/TaxForm.ts b/src/apps/wallet-admin/src/lib/models/TaxForm.ts index 6578be894..679f5a833 100644 --- a/src/apps/wallet-admin/src/lib/models/TaxForm.ts +++ b/src/apps/wallet-admin/src/lib/models/TaxForm.ts @@ -1,18 +1,12 @@ export interface TaxForm { - id: string - userId: string - dateFiled: string - withholdingAmount: string - withholdingPercentage: string + id: string; + taxFormId: string; + dateFiled: string; + userId: string; + handle?: string; taxForm: { - name: string - text: string - description: string + taxFormId: string; + name: string; } - status: string - transactionId: string -} - -export interface SetupTaxFormResponse { - transactionId: string + status: string; } diff --git a/src/apps/wallet-admin/src/lib/services/wallet.ts b/src/apps/wallet-admin/src/lib/services/wallet.ts index b8de29010..04e0d04df 100644 --- a/src/apps/wallet-admin/src/lib/services/wallet.ts +++ b/src/apps/wallet-admin/src/lib/services/wallet.ts @@ -1,13 +1,11 @@ -import { AxiosError } from 'axios' - import { EnvironmentConfig } from '~/config' -import { xhrDeleteAsync, xhrGetAsync, xhrPatchAsync, xhrPostAsync, xhrPostAsyncWithBlobHandling } from '~/libs/core' +import { xhrDeleteAsync, xhrGetAsync, xhrPatchAsync, xhrPostAsync } from '~/libs/core' +import { getAsyncWithBlobHandling } from '~/libs/core/lib/xhr/xhr-functions/xhr.functions' import { WalletDetails } from '../models/WalletDetails' import { PaymentProvider } from '../models/PaymentProvider' import { WinningDetail } from '../models/WinningDetail' import { TaxForm } from '../models/TaxForm' -import { OtpVerificationResponse } from '../models/OtpVerificationResponse' import { TransactionResponse } from '../models/TransactionId' import { PaginationInfo } from '../models/PaginationInfo' import { WinningsAudit } from '../models/WinningsAudit' @@ -74,6 +72,47 @@ export async function editPayment(updates: { return response.data } +export async function getTaxForms(limit: number, offset: number, userIds: string[]): Promise<{ + forms: TaxForm[], + pagination: PaginationInfo +}> { + const body = JSON.stringify({ + limit, + offset, + userIds, + }) + + const url = `${baseUrl}/admin/tax-forms` + const response = await xhrPostAsync>(url, body) + + if (response.status === 'error') { + throw new Error('Error fetching tax forms') + } + + return response.data +} + +export async function downloadTaxForm(userId: string, taxFormId: string): Promise { + const url = `${baseUrl}/admin/tax-forms/${userId}/${taxFormId}/download` + try { + return await getAsyncWithBlobHandling(url) + } catch (err) { + throw new Error('Failed to download users tax-form.') + } +} + +export async function deleteTaxForm(userId: string, taxFormId: string): Promise { + const url = `${baseUrl}/admin/tax-forms/${userId}/${taxFormId}` + try { + return await xhrDeleteAsync(url) + } catch (err) { + throw new Error('Failed to delete users tax-form') + } +} + // eslint-disable-next-line max-len export async function getPayments(limit: number, offset: number, filters: Record): Promise<{ winnings: WinningDetail[], @@ -214,57 +253,6 @@ export async function getRecipientViewURL(): Promise { return response.data } -// eslint-disable-next-line max-len -export async function verifyOtp(transactionId: string, code: string, blob: boolean = false): Promise { - const body = JSON.stringify({ - otpCode: code, - transactionId, - }) - - const url = `${baseUrl}/otp/verify` - try { - // eslint-disable-next-line max-len - const response = await xhrPostAsyncWithBlobHandling | Blob>(url, body, { - responseType: blob ? 'blob' : 'json', - }) - - if (response instanceof Blob) { - return response as Blob - } - - if (response.status === 'error') { - throw new Error('OTP verification failed or OTP has expired') - } - - return response.data - } catch (err) { - throw new Error('OTP verification failed or OTP has expired') - } -} - -export async function resendOtp(transactionId: string): Promise { - const body = JSON.stringify({ - transactionId, - }) - - const url = `${baseUrl}/otp/resend` - try { - const response = await xhrPostAsync>(url, body) - - if (response.status === 'error') { - throw new Error('Failed to resend OTP.') - } - - return response.data - } catch (err) { - if (err instanceof AxiosError && err.response?.data?.error !== undefined) { - throw new Error(err.response.data.error?.message) - } - - throw new Error('Failed to resend OTP.') - } -} - export async function getMemberHandle(userIds: string[]): Promise> { const url = `${memberApiBaseUrl}?userIds=[${userIds.join(',')}]&fields=handle,userId` const response = await xhrGetAsync<{ handle: string, userId: number }[]>(url) diff --git a/src/apps/wallet-admin/src/lib/util/FormatISODateString.ts b/src/apps/wallet-admin/src/lib/util/FormatISODateString.ts new file mode 100644 index 000000000..03c9665de --- /dev/null +++ b/src/apps/wallet-admin/src/lib/util/FormatISODateString.ts @@ -0,0 +1,15 @@ +export default function formatISODateString(iosDateString: string): string { + const date = new Date(iosDateString) + + if (Number.isNaN(date.getTime())) { + throw new Error('Invalid date string') + } + + const options: Intl.DateTimeFormatOptions = { + day: '2-digit', + month: '2-digit', + year: 'numeric', + } + + return date.toLocaleDateString('en-GB', options) +} diff --git a/src/apps/wallet-admin/src/lib/util/index.ts b/src/apps/wallet-admin/src/lib/util/index.ts new file mode 100644 index 000000000..b8aced3cf --- /dev/null +++ b/src/apps/wallet-admin/src/lib/util/index.ts @@ -0,0 +1 @@ +export { default as formatIOSDateString } from './FormatISODateString' From 52ae1fd05ac9739154dc6df991aef66184a460d4 Mon Sep 17 00:00:00 2001 From: Rakib Ansary Date: Fri, 22 Mar 2024 10:36:25 +0600 Subject: [PATCH 05/15] fix(wallet-admin): typo Signed-off-by: Rakib Ansary --- src/apps/wallet-admin/src/home/tabs/tax-forms/TaxFormsTab.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/apps/wallet-admin/src/home/tabs/tax-forms/TaxFormsTab.tsx b/src/apps/wallet-admin/src/home/tabs/tax-forms/TaxFormsTab.tsx index 977a79c27..6e881654f 100644 --- a/src/apps/wallet-admin/src/home/tabs/tax-forms/TaxFormsTab.tsx +++ b/src/apps/wallet-admin/src/home/tabs/tax-forms/TaxFormsTab.tsx @@ -171,8 +171,8 @@ const ListView: FC = (props: ListViewProps) => {

{Object.keys(filters).length === 0 - ? 'Member earnings will appear here.' - : 'No payments match your filters.'} + ? 'Member tax-forms will appear here.' + : 'No tax-forms match your filters.'}

)} From 835cbed216b2d797336c4dea48ea888e7330bb4c Mon Sep 17 00:00:00 2001 From: Rakib Ansary Date: Fri, 22 Mar 2024 20:46:53 +0600 Subject: [PATCH 06/15] fix(wallet-admin): add cancel api Signed-off-by: Rakib Ansary --- .../src/home/tabs/payments/PaymentsTab.tsx | 14 +++++++++++--- .../lib/components/payment-edit/PaymentEdit.tsx | 1 + src/apps/wallet-admin/src/lib/services/wallet.ts | 2 +- 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/apps/wallet-admin/src/home/tabs/payments/PaymentsTab.tsx b/src/apps/wallet-admin/src/home/tabs/payments/PaymentsTab.tsx index 205f1df4e..ef98489c6 100644 --- a/src/apps/wallet-admin/src/home/tabs/payments/PaymentsTab.tsx +++ b/src/apps/wallet-admin/src/home/tabs/payments/PaymentsTab.tsx @@ -180,12 +180,20 @@ const ListView: FC = (props: ListViewProps) => { releaseDate: currentEditState.releaseDate !== undefined ? currentEditState.releaseDate : undefined, } - let paymentStatus : 'ON_HOLD_ADMIN' | 'OWED' | undefined - if (updateObj.paymentStatus !== undefined) paymentStatus = updateObj.paymentStatus.indexOf('Owed') > -1 ? 'OWED' : 'ON_HOLD_ADMIN' + let paymentStatus : 'ON_HOLD_ADMIN' | 'OWED' | 'CANCELLED' | undefined + if (updateObj.paymentStatus !== undefined) { + if (updateObj.paymentStatus === 'Owed') { + paymentStatus = 'OWED' + } else if (updateObj.paymentStatus === 'On Hold') { + paymentStatus = 'ON_HOLD_ADMIN' + } else if (updateObj.paymentStatus === 'Cancel') { + paymentStatus = 'CANCELLED' + } + } const updates: { auditNote?: string - paymentStatus?: 'ON_HOLD_ADMIN' | 'OWED' + paymentStatus?: 'ON_HOLD_ADMIN' | 'OWED' | 'CANCELLED' releaseDate?: string paymentAmount?: number winningsId: string diff --git a/src/apps/wallet-admin/src/lib/components/payment-edit/PaymentEdit.tsx b/src/apps/wallet-admin/src/lib/components/payment-edit/PaymentEdit.tsx index 9af1a5e28..a8a7911fa 100644 --- a/src/apps/wallet-admin/src/lib/components/payment-edit/PaymentEdit.tsx +++ b/src/apps/wallet-admin/src/lib/components/payment-edit/PaymentEdit.tsx @@ -200,6 +200,7 @@ const PaymentEdit: React.FC = (props: PaymentEditFormProps options={[ { label: 'Owed', value: 'Owed' }, { label: 'On Hold', value: 'On Hold' }, + { label: 'Cancel', value: 'Cancel' }, ]} value={paymentStatus} onChange={e => handleInputChange('paymentStatus', e.target.value)} diff --git a/src/apps/wallet-admin/src/lib/services/wallet.ts b/src/apps/wallet-admin/src/lib/services/wallet.ts index 04e0d04df..b7ccfe1dc 100644 --- a/src/apps/wallet-admin/src/lib/services/wallet.ts +++ b/src/apps/wallet-admin/src/lib/services/wallet.ts @@ -56,7 +56,7 @@ export async function fetchAuditLogs(paymentId: string): Promise { From 1e8138b26a35cf14a089e77f741ea2f1e852176d Mon Sep 17 00:00:00 2001 From: Rakib Ansary Date: Fri, 22 Mar 2024 20:55:31 +0600 Subject: [PATCH 07/15] fix(wallet-admin): disable editing cancelled challenges Signed-off-by: Rakib Ansary --- .../wallet-admin/src/home/tabs/payments/PaymentsTab.tsx | 9 +++++++-- .../src/lib/components/payments-table/PaymentTable.tsx | 3 ++- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/apps/wallet-admin/src/home/tabs/payments/PaymentsTab.tsx b/src/apps/wallet-admin/src/home/tabs/payments/PaymentsTab.tsx index ef98489c6..a4da7ad8f 100644 --- a/src/apps/wallet-admin/src/home/tabs/payments/PaymentsTab.tsx +++ b/src/apps/wallet-admin/src/home/tabs/payments/PaymentsTab.tsx @@ -32,7 +32,7 @@ function formatStatus(status: string): string { case 'PAID': return 'Paid' case 'CANCELLED': - return 'Cancelled' + return 'Cancel' default: return status.replaceAll('_', ' ') } @@ -116,6 +116,11 @@ const ListView: FC = (props: ListViewProps) => { formattedReleaseDate = formatIOSDateString(payment.releaseDate) } + let status = formatStatus(payment.details[0].status) + if (status === 'Cancel') { + status = 'Cancelled' + } + return { createDate: formatIOSDateString(payment.createdAt), currency: payment.details[0].currency, @@ -129,7 +134,7 @@ const ListView: FC = (props: ListViewProps) => { netPaymentNumber: parseFloat(payment.details[0].totalAmount), releaseDate: formattedReleaseDate, releaseDateObj: releaseDate, - status: formatStatus(payment.details[0].status), + status, type: payment.category.replaceAll('_', ' ') .toLowerCase(), } diff --git a/src/apps/wallet-admin/src/lib/components/payments-table/PaymentTable.tsx b/src/apps/wallet-admin/src/lib/components/payments-table/PaymentTable.tsx index 2891b680c..b5fcd3449 100644 --- a/src/apps/wallet-admin/src/lib/components/payments-table/PaymentTable.tsx +++ b/src/apps/wallet-admin/src/lib/components/payments-table/PaymentTable.tsx @@ -1,3 +1,4 @@ +/* eslint-disable max-len */ /* eslint-disable react/jsx-no-bind */ /* eslint-disable @typescript-eslint/explicit-function-return-type */ import React, { useEffect, useState } from 'react' @@ -59,7 +60,7 @@ const PaymentsTable: React.FC = (props: PaymentTableProps) => {payment.releaseDate} {payment.datePaid} - {props.canEdit && payment.status.toUpperCase() !== 'PAID' && ( + {props.canEdit && payment.status.toUpperCase() !== 'PAID' && payment.status.toUpperCase() !== 'CANCELLED' && (
) } diff --git a/src/apps/wallet-admin/src/home/tabs/config/wallet-tabs-config.ts b/src/apps/wallet-admin/src/home/tabs/config/wallet-tabs-config.ts index 568a1e481..b29c75195 100644 --- a/src/apps/wallet-admin/src/home/tabs/config/wallet-tabs-config.ts +++ b/src/apps/wallet-admin/src/home/tabs/config/wallet-tabs-config.ts @@ -4,7 +4,7 @@ export enum WalletAdminTabViews { home = '0', payments = '1', taxforms = '2', - // withdrawalmethods = '3', + withdrawalmethods = '3', } export const WalletAdminTabsConfig: TabsNavItem[] = [ @@ -16,10 +16,10 @@ export const WalletAdminTabsConfig: TabsNavItem[] = [ id: WalletAdminTabViews.payments, title: 'Payments', }, - // { - // id: WalletAdminTabViews.withdrawalmethods, - // title: 'Withdrawal Methods', - // }, + { + id: WalletAdminTabViews.withdrawalmethods, + title: 'Payment Providers', + }, { id: WalletAdminTabViews.taxforms, title: 'Tax Forms', @@ -34,8 +34,8 @@ export function getHashFromTabId(tabId: string): string { return '#payments' case WalletAdminTabViews.taxforms: return '#tax-forms' - // case WalletAdminTabViews.withdrawalmethods: - // return '#withdrawal-methods' + case WalletAdminTabViews.withdrawalmethods: + return '#payment-providers' default: return '#home' } @@ -47,8 +47,8 @@ export function getTabIdFromHash(hash: string): string { return WalletAdminTabViews.payments case '#tax-forms': return WalletAdminTabViews.taxforms - // case '#withdrawal-methods': - // return WalletAdminTabViews.withdrawalmethods + case '#payment-providers': + return WalletAdminTabViews.withdrawalmethods default: return WalletAdminTabViews.home } diff --git a/src/apps/wallet-admin/src/home/tabs/payment-methods/PaymentMethodsTab.module.scss b/src/apps/wallet-admin/src/home/tabs/payment-methods/PaymentMethodsTab.module.scss new file mode 100644 index 000000000..4d5773ab0 --- /dev/null +++ b/src/apps/wallet-admin/src/home/tabs/payment-methods/PaymentMethodsTab.module.scss @@ -0,0 +1,35 @@ +@import '@libs/ui/styles/includes'; + +.container { + background-color: $black-5; + padding: $sp-6; + margin: $sp-8 0; + border-radius: 6px; + + @include ltelg { + padding: $sp-4; + } + + .header { + display: flex; + justify-content: flex-start; + gap: 5px; + align-items: center; + + @include ltelg { + flex-direction: column; + } + } + + .content { + background-color: $tc-white; + border-radius: 4px; + margin-top: $sp-4; + .centered { + height: 200px; + display: flex; + justify-content: space-around; + align-items: center; + } + } +} diff --git a/src/apps/wallet-admin/src/home/tabs/payment-methods/PaymentMethodsTab.tsx b/src/apps/wallet-admin/src/home/tabs/payment-methods/PaymentMethodsTab.tsx new file mode 100644 index 000000000..9539b9f7a --- /dev/null +++ b/src/apps/wallet-admin/src/home/tabs/payment-methods/PaymentMethodsTab.tsx @@ -0,0 +1,209 @@ +/* eslint-disable max-len */ +/* eslint-disable react/jsx-no-bind */ +import { toast } from 'react-toastify' +import React, { FC, useCallback, useEffect } from 'react' + +import { Collapsible, ConfirmModal, LoadingCircles } from '~/libs/ui' +import { UserProfile } from '~/libs/core' + +import { PaymentProvider } from '../../../lib/models/PaymentProvider' +import { deletePaymentProvider, getMemberHandle, getPaymentMethods } from '../../../lib/services/wallet' +import { FilterBar, PaymentMethodTable } from '../../../lib' +import { PaginationInfo } from '../../../lib/models/PaginationInfo' + +import styles from './PaymentMethodsTab.module.scss' + +interface ListViewProps { + // eslint-disable-next-line react/no-unused-prop-types + profile: UserProfile +} + +// eslint-disable-next-line @typescript-eslint/no-unused-vars +const ListView: FC = (props: ListViewProps) => { + const [confirmFlow, setConfirmFlow] = React.useState<{ + provider: PaymentProvider + } | undefined>(undefined) + const [isLoading, setIsLoading] = React.useState(false) + const [filters, setFilters] = React.useState>({}) + const [paymentMethods, setPaymentMethods] = React.useState([]) + const [userIds, setUserIds] = React.useState([]) + const [pagination, setPagination] = React.useState({ + currentPage: 1, + pageSize: 10, + totalItems: 0, + totalPages: 0, + }) + + const fetchPaymentProviders = useCallback(async () => { + if (isLoading) { + return + } + + setIsLoading(true) + try { + + const paymentMethodsResponse = await getPaymentMethods(pagination.pageSize, (pagination.currentPage - 1) * pagination.pageSize, userIds) + const tmpUserIds = paymentMethodsResponse.paymentMethods.map(provider => provider.userId) + const handleMap = await getMemberHandle(tmpUserIds) + + const userPaymentMethods = paymentMethodsResponse.paymentMethods.map((provider: PaymentProvider) => ({ ...provider, handle: handleMap.get(parseInt(provider.userId, 10)) ?? provider.userId })) + + setPaymentMethods(userPaymentMethods) + setPagination(paymentMethodsResponse.pagination) + } catch (apiError) { + console.error('Failed to fetch winnings:', apiError) + } finally { + setIsLoading(false) + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [pagination.pageSize, pagination.currentPage, userIds]) + + useEffect(() => { + fetchPaymentProviders() + }, [fetchPaymentProviders]) + + return ( + <> +
+
+

Member Payment Providers

+
+
+ Member Payment Providers Listing}> + { + const newPagination = { + ...pagination, + currentPage: 1, + } + if (key === 'pageSize') { + newPagination.pageSize = parseInt(value[0], 10) + } + + if (key === 'userIds') { + setUserIds(value) + } + + setPagination(newPagination) + setFilters({ + ...filters, + [key]: value, + }) + }} + onResetFilters={() => { + setPagination({ + ...pagination, + currentPage: 1, + pageSize: 10, + }) + setFilters({}) + }} + /> + {isLoading && } + {!isLoading && paymentMethods.length > 0 && ( + { + setPagination({ + ...pagination, + currentPage: pagination.currentPage - 1, + }) + }} + onNextPageClick={() => { + setPagination({ + ...pagination, + currentPage: pagination.currentPage + 1, + }) + }} + onPageClick={(pageNumber: number) => { + setPagination({ + ...pagination, + currentPage: pageNumber, + }) + }} + onDeleteClick={async (provider: PaymentProvider) => { + setConfirmFlow({ provider }) + }} + /> + )} + {!isLoading && paymentMethods.length === 0 && ( +
+

+ {Object.keys(filters).length === 0 + ? 'Member payment-providers will appear here.' + : 'No payment-provider found for the selected member(s).'} +

+
+ )} +
+
+
+ {confirmFlow && ( + { + setConfirmFlow(undefined) + }} + onConfirm={async () => { + const userId = confirmFlow.provider.userId + const providerId = confirmFlow.provider.id! + setConfirmFlow(undefined) + + toast.success('Deleting payment provider. Please wait...', { position: 'bottom-right' }) + try { + await deletePaymentProvider(userId, providerId) + toast.success('Successfully deleted payment provider.', { position: 'bottom-right' }) + } catch (err) { + toast.error('Failed to delete users payment provider. Please try again later', { position: 'bottom-right' }) + } + + fetchPaymentProviders() + }} + open={confirmFlow !== undefined} + > +
+

+ Are you sure you want to reset the payment provider of the member + {' '} + {confirmFlow.provider.handle} + ? +

+
+

This action cannot be undone.

+
+
+ )} + + ) +} + +export default ListView diff --git a/src/apps/wallet-admin/src/home/tabs/payment-methods/index.ts b/src/apps/wallet-admin/src/home/tabs/payment-methods/index.ts new file mode 100644 index 000000000..ae6c8e814 --- /dev/null +++ b/src/apps/wallet-admin/src/home/tabs/payment-methods/index.ts @@ -0,0 +1 @@ +export { default as PaymentMethodsTab } from './PaymentMethodsTab' diff --git a/src/apps/wallet-admin/src/home/tabs/payments/PaymentsTab.tsx b/src/apps/wallet-admin/src/home/tabs/payments/PaymentsTab.tsx index 32efe3673..be1dba97f 100644 --- a/src/apps/wallet-admin/src/home/tabs/payments/PaymentsTab.tsx +++ b/src/apps/wallet-admin/src/home/tabs/payments/PaymentsTab.tsx @@ -1,6 +1,7 @@ /* eslint-disable max-len */ /* eslint-disable react/jsx-no-bind */ import { toast } from 'react-toastify' +import { AxiosError } from 'axios' import React, { FC, useCallback, useEffect } from 'react' import { Collapsible, ConfirmModal, LoadingCircles } from '~/libs/ui' @@ -75,6 +76,7 @@ const ListView: FC = (props: ListViewProps) => { paymentStatus?: string; auditNote?: string; }>({}) + const [apiErrorMsg, setApiErrorMsg] = React.useState('Member earnings will appear here.') const editStateRef = React.useRef(editState) @@ -156,7 +158,11 @@ const ListView: FC = (props: ListViewProps) => { setWinnings(winningsData) setPagination(payments.pagination) } catch (apiError) { - console.error('Failed to fetch winnings:', apiError) + if (apiError instanceof AxiosError && apiError?.response?.status === 403) { + setApiErrorMsg(apiError.response.data.message) + } else { + setApiErrorMsg('Failed to fetch winnings. Please try again later.') + } } finally { setIsLoading(false) } @@ -436,7 +442,7 @@ const ListView: FC = (props: ListViewProps) => {

{Object.keys(filters).length === 0 - ? 'Member earnings will appear here.' + ? apiErrorMsg : 'No payments match your filters.'}

diff --git a/src/apps/wallet-admin/src/home/tabs/tax-forms/TaxFormsTab.tsx b/src/apps/wallet-admin/src/home/tabs/tax-forms/TaxFormsTab.tsx index 6e881654f..1fd6e1bb0 100644 --- a/src/apps/wallet-admin/src/home/tabs/tax-forms/TaxFormsTab.tsx +++ b/src/apps/wallet-admin/src/home/tabs/tax-forms/TaxFormsTab.tsx @@ -1,6 +1,7 @@ /* eslint-disable max-len */ /* eslint-disable react/jsx-no-bind */ import { toast } from 'react-toastify' +import { AxiosError } from 'axios' import React, { FC, useCallback, useEffect } from 'react' import { Collapsible, ConfirmModal, LoadingCircles } from '~/libs/ui' @@ -34,6 +35,7 @@ const ListView: FC = (props: ListViewProps) => { totalItems: 0, totalPages: 0, }) + const [apiErrorMsg, setApiErrorMsg] = React.useState('Member earnings will appear here.') const fetchTaxForms = useCallback(async () => { if (isLoading) { @@ -52,7 +54,11 @@ const ListView: FC = (props: ListViewProps) => { setForms(taxForms) setPagination(taxFormsResponse.pagination) } catch (apiError) { - console.error('Failed to fetch winnings:', apiError) + if (apiError instanceof AxiosError && apiError?.response?.status === 403) { + setApiErrorMsg(apiError.response.data.message) + } else { + setApiErrorMsg('Failed to fetch winnings. Please try again later.') + } } finally { setIsLoading(false) } @@ -80,7 +86,7 @@ const ListView: FC = (props: ListViewProps) => { }, { key: 'pageSize', - label: 'Tax Forms per page', + label: 'Members per page', options: [ { label: '10', @@ -171,8 +177,8 @@ const ListView: FC = (props: ListViewProps) => {

{Object.keys(filters).length === 0 - ? 'Member tax-forms will appear here.' - : 'No tax-forms match your filters.'} + ? apiErrorMsg + : 'No tax-forms found for the selected member(s).'}

)} diff --git a/src/apps/wallet-admin/src/lib/components/index.ts b/src/apps/wallet-admin/src/lib/components/index.ts index eb2f27235..23457ecab 100644 --- a/src/apps/wallet-admin/src/lib/components/index.ts +++ b/src/apps/wallet-admin/src/lib/components/index.ts @@ -4,3 +4,4 @@ export * from './filter-bar' export * from './payment-edit' export * from './payment-view' export * from './tax-forms-table' +export * from './payment-method-table' diff --git a/src/apps/wallet-admin/src/lib/components/payment-method-table/PaymentMethodTable.module.scss b/src/apps/wallet-admin/src/lib/components/payment-method-table/PaymentMethodTable.module.scss new file mode 100644 index 000000000..5e4ea7c5a --- /dev/null +++ b/src/apps/wallet-admin/src/lib/components/payment-method-table/PaymentMethodTable.module.scss @@ -0,0 +1,109 @@ +@import '@libs/ui/styles/includes'; + +.tableContainer { + width: 100%; + overflow-x: auto; + margin-top: $sp-2; +} + +table { + width: 100%; + border-collapse: separate; + border-spacing: 0; + margin: 16px 0; + + th, + td { + text-align: left; + padding: 8px; + + &:last-child { + width: 50px; + } + } + + tbody { + tr { + &:nth-child(odd) { + background-color: #f4f4f4; + } + &:nth-child(even) { + background-color: #ffffff; + } + + .capitalize { + text-transform: capitalize; + } + } + } + + th { + top: 0; + background-color: white !important; + text-transform: uppercase; + } + + tbody tr td:first-child { + border-top-left-radius: 8px; + border-bottom-left-radius: 8px; + } + + tbody tr td:last-child { + border-top-right-radius: 8px; + border-bottom-right-radius: 8px; + } + +} + +.selected { + background-color: #e7f4ff; +} + +.pageButtons { + display: flex; + justify-content: flex-end; + align-items: center; + margin-top: 16px; + gap: $sp-4; + + .pageNumbers { + display: flex; + justify-content: center; + align-items: center; + gap: $sp-1; + } + +} + +.footer { + display: flex; + flex-direction: column; + justify-content: space-between; + align-items: center; + margin-top: 16px; + padding-bottom: 16px; + border-radius: 8px; + background-color: white; + border: 1px solid #eaeaea; + + .total { + font-size: 18px; + font-weight: bold; + + color: #333; + } +} + +.actionButtons { + padding-right: 50px; + display: flex; + justify-content: center; + align-items: center; +} + +@media (max-width: 768px) { + .footer { + flex-direction: column; + align-items: center; + } +} diff --git a/src/apps/wallet-admin/src/lib/components/payment-method-table/PaymentMethodTable.tsx b/src/apps/wallet-admin/src/lib/components/payment-method-table/PaymentMethodTable.tsx new file mode 100644 index 000000000..59834b28e --- /dev/null +++ b/src/apps/wallet-admin/src/lib/components/payment-method-table/PaymentMethodTable.tsx @@ -0,0 +1,112 @@ +/* eslint-disable max-len */ +/* eslint-disable react/jsx-no-bind */ +/* eslint-disable @typescript-eslint/explicit-function-return-type */ +import React from 'react' + +import { Button, IconOutline, Tooltip } from '~/libs/ui' + +import { PaymentProvider } from '../../models/PaymentProvider' + +import styles from './PaymentMethodTable.module.scss' + +interface PaymentMethodTableProps { + paymentMethods: ReadonlyArray; + currentPage: number; + numPages: number; + onNextPageClick: () => void; + onPreviousPageClick: () => void; + onPageClick: (pageNumber: number) => void; + onDeleteClick?: (form: PaymentProvider) => void; +} + +const PaymentProviderTable: React.FC = (props: PaymentMethodTableProps) => ( + <> +
+ + + + + + + + + + + + {props.paymentMethods.map(provider => ( + + + + + + + + ))} + +
HANDLECONNECTED PROVIDERPROVIDER IDSTATUS
{provider.handle}{provider.type}{provider.providerId === 'Legacy' ? provider.userId : provider.providerId}{provider.status} + +
+
+ + {props.numPages > 1 && ( +
+
+
+ {props.currentPage < props.numPages - 2 && ...} +
+
+ )} + +) + +export default PaymentProviderTable diff --git a/src/apps/wallet-admin/src/lib/components/payment-method-table/index.ts b/src/apps/wallet-admin/src/lib/components/payment-method-table/index.ts new file mode 100644 index 000000000..6fa841064 --- /dev/null +++ b/src/apps/wallet-admin/src/lib/components/payment-method-table/index.ts @@ -0,0 +1 @@ +export { default as PaymentMethodTable } from './PaymentMethodTable' diff --git a/src/apps/wallet-admin/src/lib/components/tax-forms-table/TaxFormTable.tsx b/src/apps/wallet-admin/src/lib/components/tax-forms-table/TaxFormTable.tsx index e777badd1..149be504a 100644 --- a/src/apps/wallet-admin/src/lib/components/tax-forms-table/TaxFormTable.tsx +++ b/src/apps/wallet-admin/src/lib/components/tax-forms-table/TaxFormTable.tsx @@ -20,108 +20,104 @@ interface TaxFormTableProps { onDeleteClick?: (form: TaxForm) => void; } -const TaxFormTable: React.FC = (props: TaxFormTableProps) => { - console.log('Tax Forms', props.taxForms) - - return ( - <> -
- - - - - - - - +const TaxFormTable: React.FC = (props: TaxFormTableProps) => ( + <> +
+
HANDLEFORMDATE FILEDSTATUS
+ + + + + + + + + + + {props.taxForms.map(form => ( + + + + + + - - - {props.taxForms.map(form => ( - - - - - - - - ))} - -
HANDLEFORMDATE FILEDSTATUS
{form.handle}{form.taxForm.name}{form.dateFiled}{form.status} + +
{form.handle}{form.taxForm.name}{form.dateFiled}{form.status} - -
-
+ ))} + + +
- {props.numPages > 1 && ( -
-
-
- {props.currentPage < props.numPages - 2 && ...} -
+ {props.currentPage < props.numPages - 2 && ...} +