feat(dealer): 新增银行卡管理功能

- 添加银行卡管理页面和相关API
- 实现银行卡列表展示、添加、编辑和删除功能
- 优化提现页面,支持选择银行卡进行提现
- 新增 FixedButton 组件用于底部固定按钮
This commit is contained in:
2025-09-06 19:37:49 +08:00
parent e57fe8810a
commit d770796df4
25 changed files with 517 additions and 143 deletions

View File

@@ -0,0 +1,101 @@
import request from '@/utils/request';
import type { ApiResult, PageResult } from '@/api';
import type { ShopDealerBank, ShopDealerBankParam } from './model';
/**
* 分页查询分销商银行卡
*/
export async function pageShopDealerBank(params: ShopDealerBankParam) {
const res = await request.get<ApiResult<PageResult<ShopDealerBank>>>(
'/shop/shop-dealer-bank/page',
params
);
if (res.code === 0) {
return res.data;
}
return Promise.reject(new Error(res.message));
}
/**
* 查询分销商银行卡列表
*/
export async function listShopDealerBank(params?: ShopDealerBankParam) {
const res = await request.get<ApiResult<ShopDealerBank[]>>(
'http://127.0.0.1:9200/api/shop/shop-dealer-bank',
params
);
if (res.code === 0 && res.data) {
return res.data;
}
return Promise.reject(new Error(res.message));
}
/**
* 添加分销商银行卡
*/
export async function addShopDealerBank(data: ShopDealerBank) {
const res = await request.post<ApiResult<unknown>>(
'/shop/shop-dealer-bank',
data
);
if (res.code === 0) {
return res.message;
}
return Promise.reject(new Error(res.message));
}
/**
* 修改分销商银行卡
*/
export async function updateShopDealerBank(data: ShopDealerBank) {
const res = await request.put<ApiResult<unknown>>(
'/shop/shop-dealer-bank',
data
);
if (res.code === 0) {
return res.message;
}
return Promise.reject(new Error(res.message));
}
/**
* 删除分销商银行卡
*/
export async function removeShopDealerBank(id?: number) {
const res = await request.del<ApiResult<unknown>>(
'/shop/shop-dealer-bank/' + id
);
if (res.code === 0) {
return res.message;
}
return Promise.reject(new Error(res.message));
}
/**
* 批量删除分销商银行卡
*/
export async function removeBatchShopDealerBank(data: (number | undefined)[]) {
const res = await request.del<ApiResult<unknown>>(
'/shop/shop-dealer-bank/batch',
{
data
}
);
if (res.code === 0) {
return res.message;
}
return Promise.reject(new Error(res.message));
}
/**
* 根据id查询分销商银行卡
*/
export async function getShopDealerBank(id: number) {
const res = await request.get<ApiResult<ShopDealerBank>>(
'/shop/shop-dealer-bank/' + id
);
if (res.code === 0 && res.data) {
return res.data;
}
return Promise.reject(new Error(res.message));
}

View File

@@ -0,0 +1,45 @@
import type { PageParam } from '@/api';
/**
* 分销商提现银行卡
*/
export interface ShopDealerBank {
// 主键ID
id?: number;
// 分销商用户ID
userId?: number;
// 开户行名称
bankName?: string;
// 银行开户名
bankAccount?: string;
// 银行卡号
bankCard?: string;
// 申请状态 (10待审核 20审核通过 30驳回)
applyStatus?: number;
// 审核时间
auditTime?: number;
// 驳回原因
rejectReason?: string;
// 是否默认
isDefault?: boolean;
// 租户id
tenantId?: number;
// 创建时间
createTime?: string;
// 修改时间
updateTime?: string;
// 类型
type?: string;
// 名称
name?: string;
}
/**
* 分销商提现银行卡搜索条件
*/
export interface ShopDealerBankParam extends PageParam {
id?: number;
userId?: number;
isDefault?: boolean;
keywords?: string;
}

View File

@@ -1,4 +1,4 @@
import type { PageParam } from '@/api/index'; import type { PageParam } from '@/api';
/** /**
* 分销商提现明细表 * 分销商提现明细表

View File

@@ -67,7 +67,9 @@ export default defineAppConfig({
"customer/index", "customer/index",
"customer/add", "customer/add",
"customer/trading", "customer/trading",
"wechat/index" "wechat/index",
"bank/index",
"bank/add"
] ]
}, },
// { // {

View File

@@ -0,0 +1,4 @@
export default definePageConfig({
navigationBarTitleText: '添加银行卡',
navigationBarTextStyle: 'black'
})

142
src/dealer/bank/add.tsx Normal file
View File

@@ -0,0 +1,142 @@
import {useEffect, useState, useRef} from "react";
import {useRouter} from '@tarojs/taro'
import {Loading, CellGroup, Input, Form} from '@nutui/nutui-react-taro'
import Taro from '@tarojs/taro'
import {
getShopDealerBank,
listShopDealerBank,
updateShopDealerBank,
addShopDealerBank
} from "@/api/shop/shopDealerBank";
import FixedButton from "@/components/FixedButton";
import {ShopDealerBank} from "@/api/shop/shopDealerBank/model";
const AddUserAddress = () => {
const {params} = useRouter();
const [loading, setLoading] = useState<boolean>(true)
const [FormData, setFormData] = useState<ShopDealerBank>()
const formRef = useRef<any>(null)
// 判断是编辑还是新增模式
const isEditMode = !!params.id
const bankId = params.id ? Number(params.id) : undefined
const reload = async () => {
// 如果是编辑模式,加载地址数据
if (isEditMode && bankId) {
try {
const bank = await getShopDealerBank(bankId)
setFormData(bank)
} catch (error) {
console.error('加载地址失败:', error)
Taro.showToast({
title: '加载地址失败',
icon: 'error'
});
}
}
}
// 提交表单
const submitSucceed = async (values: any) => {
console.log('.>>>>>>,....')
try {
// 准备提交的数据
const submitData = {
...values,
isDefault: true // 新增或编辑的地址都设为默认地址
};
console.log('提交数据:', submitData)
// 如果是编辑模式添加id
if (isEditMode && bankId) {
submitData.id = bankId;
}
// 先处理默认地址逻辑
const defaultAddress = await listShopDealerBank({isDefault: true});
if (defaultAddress && defaultAddress.length > 0) {
// 如果当前编辑的不是默认地址,或者是新增地址,需要取消其他默认地址
if (!isEditMode || (isEditMode && defaultAddress[0].id !== bankId)) {
await updateShopDealerBank({
...defaultAddress[0],
isDefault: false
});
}
}
// 执行新增或更新操作
if (isEditMode) {
await updateShopDealerBank(submitData);
} else {
await addShopDealerBank(submitData);
}
Taro.showToast({
title: `${isEditMode ? '更新' : '保存'}成功`,
icon: 'success'
});
setTimeout(() => {
Taro.navigateBack();
}, 1000);
} catch (error) {
console.error('保存失败:', error);
Taro.showToast({
title: `${isEditMode ? '更新' : '保存'}失败`,
icon: 'error'
});
}
}
const submitFailed = (error: any) => {
console.log(error, 'err...')
}
useEffect(() => {
// 动态设置页面标题
Taro.setNavigationBarTitle({
title: isEditMode ? '编辑银行卡' : '添加银行卡'
});
reload().then(() => {
setLoading(false)
})
}, [isEditMode]);
if (loading) {
return <Loading className={'px-2'}></Loading>
}
return (
<>
<Form
ref={formRef}
divider
initialValues={FormData}
labelPosition="left"
onFinish={(values) => submitSucceed(values)}
onFinishFailed={(errors) => submitFailed(errors)}
>
<CellGroup style={{padding: '4px 0'}}>
<Form.Item name="bankName" label="开户行名称" initialValue={FormData?.bankName} required>
<Input placeholder="开户行名称" maxLength={10}/>
</Form.Item>
<Form.Item name="bankAccount" label="银行开户名" initialValue={FormData?.bankAccount} required>
<Input placeholder="银行开户名" maxLength={10}/>
</Form.Item>
<Form.Item name="bankCard" label="银行卡号" initialValue={FormData?.bankCard} required>
<Input placeholder="银行卡号" maxLength={11}/>
</Form.Item>
</CellGroup>
</Form>
{/* 底部浮动按钮 */}
<FixedButton text={isEditMode ? '更新地址' : '保存并使用'} onClick={() => formRef.current?.submit()}/>
</>
);
};
export default AddUserAddress;

View File

@@ -0,0 +1,4 @@
export default definePageConfig({
navigationBarTitleText: '银行卡管理',
navigationBarTextStyle: 'black'
})

134
src/dealer/bank/index.tsx Normal file
View File

@@ -0,0 +1,134 @@
import {useState} from "react";
import Taro, {useDidShow} from '@tarojs/taro'
import {Button, Cell, Space, Empty, ConfigProvider} from '@nutui/nutui-react-taro'
import {CheckNormal, Checked} from '@nutui/icons-react-taro'
import {View} from '@tarojs/components'
import {ShopDealerBank} from "@/api/shop/shopDealerBank/model";
import {listShopDealerBank, removeShopDealerBank, updateShopDealerBank} from "@/api/shop/shopDealerBank";
import FixedButton from "@/components/FixedButton";
const DealerBank = () => {
const [list, setList] = useState<ShopDealerBank[]>([])
const [bank, setAddress] = useState<ShopDealerBank>()
const reload = () => {
listShopDealerBank({})
.then(data => {
setList(data || [])
// 默认地址
setAddress(data.find(item => item.isDefault))
})
.catch(() => {
Taro.showToast({
title: '获取地址失败',
icon: 'error'
});
})
}
const onDefault = async (item: ShopDealerBank) => {
if (bank) {
await updateShopDealerBank({
...bank,
isDefault: false
})
}
await updateShopDealerBank({
id: item.id,
isDefault: true
})
Taro.showToast({
title: '设置成功',
icon: 'success'
});
reload();
}
const onDel = async (id?: number) => {
await removeShopDealerBank(id)
Taro.showToast({
title: '删除成功',
icon: 'success'
});
reload();
}
const selectAddress = async (item: ShopDealerBank) => {
if (bank) {
await updateShopDealerBank({
...bank,
isDefault: false
})
}
await updateShopDealerBank({
id: item.id,
isDefault: true
})
setTimeout(() => {
Taro.navigateBack()
}, 500)
}
useDidShow(() => {
reload()
});
if (list.length == 0) {
return (
<ConfigProvider>
<div className={'h-full flex flex-col justify-center items-center'} style={{
height: 'calc(100vh - 300px)',
}}>
<Empty
style={{
backgroundColor: 'transparent'
}}
description="您还没有地址哦"
/>
<Space>
<Button onClick={() => Taro.navigateTo({url: '/dealer/bank/add'})}></Button>
<Button type="success" fill="dashed"
onClick={() => Taro.navigateTo({url: '/dealer/bank/wxAddress'})}></Button>
</Space>
</div>
</ConfigProvider>
)
}
return (
<View className={'p-3'}>
{list.map((item, _) => (
<Cell.Group>
<Cell className={'flex flex-col gap-1'} extra={item.bankAccount} onClick={() => selectAddress(item)}>
<View>
<View className={'font-medium text-sm'}>{item.bankName}</View>
</View>
<View className={'text-xs'}>
{item.bankCard} {item.bankAccount}
</View>
</Cell>
<Cell
align="center"
title={
<View className={'flex items-center gap-1'} onClick={() => onDefault(item)}>
{item.isDefault ? <Checked className={'text-green-600'} size={16}/> : <CheckNormal size={16}/>}
<View className={'text-gray-400'}></View>
</View>
}
extra={
<>
<View className={'text-gray-400'} onClick={() => onDel(item.id)}>
</View>
</>
}
/>
</Cell.Group>
))}
{/* 底部浮动按钮 */}
<FixedButton text={'新增银行卡'} onClick={() => Taro.navigateTo({url: '/dealer/bank/add'})} />
</View>
);
};
export default DealerBank;

View File

@@ -122,7 +122,7 @@ const CustomerTrading = () => {
</Text> </Text>
</View> </View>
<Space direction={'vertical'}> <Space direction={'vertical'}>
<Text className="text-xs text-gray-500">{customer.dealerCode}</Text> {/*<Text className="text-xs text-gray-500">统一代码:{customer.dealerCode}</Text>*/}
<Text className="text-xs text-gray-500"> <Text className="text-xs text-gray-500">
{customer.createTime} {customer.createTime}
</Text> </Text>

View File

@@ -132,7 +132,7 @@ const DealerIndex: React.FC = () => {
<Text className="font-semibold text-gray-800"></Text> <Text className="font-semibold text-gray-800"></Text>
</View> </View>
<View className="grid grid-cols-3 gap-3"> <View className="grid grid-cols-3 gap-3">
<View className="text-center p-3 rounded-lg" style={{ <View className="text-center p-3 rounded-lg flex flex-col" style={{
background: businessGradients.money.available background: businessGradients.money.available
}}> }}>
<Text className="text-lg font-bold mb-1 text-white"> <Text className="text-lg font-bold mb-1 text-white">
@@ -140,7 +140,7 @@ const DealerIndex: React.FC = () => {
</Text> </Text>
<Text className="text-xs" style={{ color: 'rgba(255, 255, 255, 0.9)' }}></Text> <Text className="text-xs" style={{ color: 'rgba(255, 255, 255, 0.9)' }}></Text>
</View> </View>
<View className="text-center p-3 rounded-lg" style={{ <View className="text-center p-3 rounded-lg flex flex-col" style={{
background: businessGradients.money.frozen background: businessGradients.money.frozen
}}> }}>
<Text className="text-lg font-bold mb-1 text-white"> <Text className="text-lg font-bold mb-1 text-white">
@@ -148,7 +148,7 @@ const DealerIndex: React.FC = () => {
</Text> </Text>
<Text className="text-xs" style={{ color: 'rgba(255, 255, 255, 0.9)' }}></Text> <Text className="text-xs" style={{ color: 'rgba(255, 255, 255, 0.9)' }}></Text>
</View> </View>
<View className="text-center p-3 rounded-lg" style={{ <View className="text-center p-3 rounded-lg flex flex-col" style={{
background: businessGradients.money.total background: businessGradients.money.total
}}> }}>
<Text className="text-lg font-bold mb-1 text-white"> <Text className="text-lg font-bold mb-1 text-white">

View File

@@ -133,15 +133,6 @@ const DealerOrders: React.FC = () => {
</View> </View>
) )
if (!dealerUser) {
return (
<View className="bg-gray-50 min-h-screen flex items-center justify-center">
<Loading/>
<Text className="text-gray-500 mt-2">...</Text>
</View>
)
}
return ( return (
<View className="min-h-screen bg-gray-50"> <View className="min-h-screen bg-gray-50">
<PullToRefresh <PullToRefresh

View File

@@ -290,7 +290,7 @@ const DealerTeam: React.FC = () => {
if (!dealerUser) { if (!dealerUser) {
return ( return (
<Space className="bg-gray-50 flex items-center justify-center"> <Space className="flex items-center justify-center">
<Empty description="您还不是业务人员" style={{ <Empty description="您还不是业务人员" style={{
backgroundColor: 'transparent' backgroundColor: 'transparent'
}} actions={[{ text: '立即申请', onClick: () => navTo(`/dealer/apply/add`,true)}]} }} actions={[{ text: '立即申请', onClick: () => navTo(`/dealer/apply/add`,true)}]}

View File

@@ -4,22 +4,23 @@ import {
Cell, Cell,
Space, Space,
Button, Button,
Form,
Input, Input,
CellGroup, CellGroup,
Radio,
Tabs, Tabs,
Tag, Tag,
Empty, Empty,
ActionSheet,
Loading, Loading,
PullToRefresh PullToRefresh
} from '@nutui/nutui-react-taro' } from '@nutui/nutui-react-taro'
import {Wallet} from '@nutui/icons-react-taro' import {Wallet, ArrowRight} from '@nutui/icons-react-taro'
import {businessGradients} from '@/styles/gradients' import {businessGradients} from '@/styles/gradients'
import Taro from '@tarojs/taro' import Taro from '@tarojs/taro'
import {useDealerUser} from '@/hooks/useDealerUser' import {useDealerUser} from '@/hooks/useDealerUser'
import {pageShopDealerWithdraw, addShopDealerWithdraw} from '@/api/shop/shopDealerWithdraw' import {pageShopDealerWithdraw, addShopDealerWithdraw} from '@/api/shop/shopDealerWithdraw'
import type {ShopDealerWithdraw} from '@/api/shop/shopDealerWithdraw/model' import type {ShopDealerWithdraw} from '@/api/shop/shopDealerWithdraw/model'
import {ShopDealerBank} from "@/api/shop/shopDealerBank/model";
import {listShopDealerBank} from "@/api/shop/shopDealerBank";
interface WithdrawRecordWithDetails extends ShopDealerWithdraw { interface WithdrawRecordWithDetails extends ShopDealerWithdraw {
accountDisplay?: string accountDisplay?: string
@@ -31,6 +32,9 @@ const DealerWithdraw: React.FC = () => {
const [loading, setLoading] = useState<boolean>(false) const [loading, setLoading] = useState<boolean>(false)
const [refreshing, setRefreshing] = useState<boolean>(false) const [refreshing, setRefreshing] = useState<boolean>(false)
const [submitting, setSubmitting] = useState<boolean>(false) const [submitting, setSubmitting] = useState<boolean>(false)
const [banks, setBanks] = useState<any[]>([])
const [bank, setBank] = useState<ShopDealerBank>()
const [isVisible, setIsVisible] = useState<boolean>(false)
const [availableAmount, setAvailableAmount] = useState<string>('0.00') const [availableAmount, setAvailableAmount] = useState<string>('0.00')
const [withdrawRecords, setWithdrawRecords] = useState<WithdrawRecordWithDetails[]>([]) const [withdrawRecords, setWithdrawRecords] = useState<WithdrawRecordWithDetails[]>([])
const formRef = useRef<any>(null) const formRef = useRef<any>(null)
@@ -88,6 +92,21 @@ const DealerWithdraw: React.FC = () => {
} }
}, [dealerUser?.userId]) }, [dealerUser?.userId])
function fetchBanks() {
listShopDealerBank({}).then(data => {
const list = data.map(d => {
d.name = d.bankName;
d.type = d.bankName;
return d;
})
setBanks(list.concat({
name: '管理银行卡',
type: 'add'
}))
setBank(data[0])
})
}
// 格式化账户显示 // 格式化账户显示
const getAccountDisplay = (record: ShopDealerWithdraw) => { const getAccountDisplay = (record: ShopDealerWithdraw) => {
if (record.payType === 10) { if (record.payType === 10) {
@@ -107,11 +126,22 @@ const DealerWithdraw: React.FC = () => {
setRefreshing(false) setRefreshing(false)
} }
const handleSelect = (item: ShopDealerBank) => {
if(item.type === 'add'){
return Taro.navigateTo({
url: '/dealer/bank/index'
})
}
setBank(item)
setIsVisible(false)
}
// 初始化加载数据 // 初始化加载数据
useEffect(() => { useEffect(() => {
if (dealerUser?.userId) { if (dealerUser?.userId) {
fetchBalance().then() fetchBalance().then()
fetchWithdrawRecords().then() fetchWithdrawRecords().then()
fetchBanks()
} }
}, [fetchBalance, fetchWithdrawRecords]) }, [fetchBalance, fetchWithdrawRecords])
@@ -259,16 +289,6 @@ const DealerWithdraw: React.FC = () => {
} }
} }
const quickAmounts = ['100', '300', '500', '1000']
const setQuickAmount = (amount: string) => {
formRef.current?.setFieldsValue({amount})
}
const setAllAmount = () => {
formRef.current?.setFieldsValue({amount: availableAmount.replace(/,/g, '')})
}
// 格式化金额 // 格式化金额
const formatMoney = (money?: string) => { const formatMoney = (money?: string) => {
if (!money) return '0.00' if (!money) return '0.00'
@@ -303,121 +323,55 @@ const DealerWithdraw: React.FC = () => {
borderTop: '1px solid rgba(255, 255, 255, 0.3)' borderTop: '1px solid rgba(255, 255, 255, 0.3)'
}}> }}>
<Text className="text-white text-opacity-80 text-xs"> <Text className="text-white text-opacity-80 text-xs">
¥100 | 3 ¥100
</Text> </Text>
</View> </View>
</View> </View>
<Form <CellGroup>
ref={formRef} <Cell style={{
onFinish={handleSubmit} padding: '36px 12px'
labelPosition="top" }} title={
> <View className="flex items-center justify-between">
<CellGroup> <Text className={'text-xl'}></Text>
<Form.Item name="amount" label="提现金额" required>
<Input <Input
placeholder="请输入提现金额" placeholder="提现金额"
type="number" type="number"
onChange={(value) => { maxLength={7}
// 实时验证提现金额 style={{
const amount = parseFloat(value) padding: '0 10px',
const available = parseFloat(availableAmount.replace(/,/g, '')) fontSize: '20px'
if (!isNaN(amount) && amount > available) {
// 可以在这里添加实时提示,但不阻止输入
}
}} }}
/> />
</Form.Item> <Button fill="none" size={'small'}><Text className={'text-blue-500'}></Text></Button>
{/* 快捷金额 */}
<View className="px-4 py-2">
<Text className="text-sm text-gray-600 mb-2"></Text>
<View className="flex flex-wrap gap-2">
{quickAmounts.map(amount => (
<Button
key={amount}
size="small"
fill="outline"
onClick={() => setQuickAmount(amount)}
>
{amount}
</Button>
))}
<Button
size="small"
fill="outline"
onClick={setAllAmount}
>
</Button>
</View>
</View> </View>
}
/>
<Cell title={'提现到'} onClick={() => setIsVisible(true)} extra={
<View className="flex items-center justify-between gap-1">
{bank ? <Text className={'text-gray-800'}>{bank.bankName}</Text> : <Text className={'text-gray-400'}></Text>}
<ArrowRight className={'text-gray-300'} size={15}/>
</View>
}/>
<Cell title={'预计到账金额'} description={'提现费率 16% +3元'} extra={
<View className="flex items-center justify-between gap-1">
<Text className={'text-orange-500 px-2 text-lg'}>¥2141.41</Text>
</View>
}/>
</CellGroup>
<Form.Item name="accountType" label="提现方式" required> <View className="mt-6 px-4">
<Radio.Group value={selectedAccount} onChange={() => setSelectedAccount}> <Button
<Cell.Group> block
<Cell> type="primary"
<Radio value="wechat"></Radio> nativeType="submit"
</Cell> loading={submitting}
<Cell> disabled={submitting || !selectedAccount}
<Radio value="alipay"></Radio> onClick={handleSubmit}
</Cell> >
<Cell> {submitting ? '提交中...' : '申请提现'}
<Radio value="bank"></Radio> </Button>
</Cell> </View>
<Cell>
<Radio value="bank"></Radio>
</Cell>
</Cell.Group>
</Radio.Group>
</Form.Item>
{selectedAccount === 'alipay' && (
<>
<Form.Item name="account" label="支付宝账号" required>
<Input placeholder="请输入支付宝账号"/>
</Form.Item>
<Form.Item name="accountName" label="支付宝姓名" required>
<Input placeholder="请输入支付宝实名姓名"/>
</Form.Item>
</>
)}
{selectedAccount === 'bank' && (
<>
<Form.Item name="bankName" label="开户银行" required>
<Input placeholder="请输入开户银行名称"/>
</Form.Item>
<Form.Item name="account" label="银行卡号" required>
<Input placeholder="请输入银行卡号"/>
</Form.Item>
<Form.Item name="accountName" label="开户姓名" required>
<Input placeholder="请输入银行卡开户姓名"/>
</Form.Item>
</>
)}
{selectedAccount === 'wechat' && (
<View className="px-4 py-2">
<Text className="text-sm text-gray-500">
</Text>
</View>
)}
</CellGroup>
<View className="mt-6 px-4">
<Button
block
type="primary"
nativeType="submit"
loading={submitting}
disabled={submitting || !selectedAccount}
>
{submitting ? '提交中...' : '申请提现'}
</Button>
</View>
</Form>
</View> </View>
) )
@@ -475,15 +429,6 @@ const DealerWithdraw: React.FC = () => {
) )
} }
if (!dealerUser) {
return (
<View className="bg-gray-50 min-h-screen flex items-center justify-center">
<Loading/>
<Text className="text-gray-500 mt-2">...</Text>
</View>
)
}
return ( return (
<View className="bg-gray-50 min-h-screen"> <View className="bg-gray-50 min-h-screen">
<Tabs value={activeTab} onChange={handleTabChange}> <Tabs value={activeTab} onChange={handleTabChange}>
@@ -495,6 +440,12 @@ const DealerWithdraw: React.FC = () => {
{renderWithdrawRecords()} {renderWithdrawRecords()}
</Tabs.TabPane> </Tabs.TabPane>
</Tabs> </Tabs>
<ActionSheet
visible={isVisible}
options={banks}
onSelect={handleSelect}
onCancel={() => setIsVisible(false)}
/>
</View> </View>
) )
} }