first commit
This commit is contained in:
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"navigationBarTitleText": "DIY工作台",
|
||||
"usingComponents": {}
|
||||
}
|
||||
@@ -0,0 +1,284 @@
|
||||
.diy-page {
|
||||
padding: 0 24px 24px;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
/* 画布区域 */
|
||||
.canvas-wrapper {
|
||||
padding: 40px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.canvas-area {
|
||||
position: relative;
|
||||
background: linear-gradient(135deg, rgba(255, 154, 158, 0.08) 0%, rgba(160, 196, 255, 0.08) 100%);
|
||||
overflow: hidden;
|
||||
border-radius: 16px;
|
||||
min-width: 200px;
|
||||
min-height: 200px;
|
||||
}
|
||||
|
||||
.mask-border {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
border: 3px dashed var(--accent-blue);
|
||||
pointer-events: none;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.canvas-image {
|
||||
position: absolute;
|
||||
max-width: 100%;
|
||||
max-height: 100%;
|
||||
z-index: 5;
|
||||
border: 2px solid transparent;
|
||||
}
|
||||
|
||||
.canvas-image.active {
|
||||
border-color: var(--accent-pink);
|
||||
}
|
||||
|
||||
.canvas-image.overlap {
|
||||
border-color: #ff4757;
|
||||
box-shadow: 0 0 12px rgba(255, 71, 87, 0.5);
|
||||
}
|
||||
|
||||
/* 贴纸面板 */
|
||||
.sticker-panel {
|
||||
padding: 28px;
|
||||
}
|
||||
|
||||
.sticker-list {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.sticker-thumb {
|
||||
position: relative;
|
||||
width: 120px;
|
||||
height: 120px;
|
||||
border: 2px dashed var(--line-star);
|
||||
border-radius: 12px;
|
||||
overflow: hidden;
|
||||
background: var(--bg-input);
|
||||
}
|
||||
|
||||
.sticker-thumb.active {
|
||||
border-color: var(--accent-pink);
|
||||
border-width: 3px;
|
||||
}
|
||||
|
||||
.sticker-thumb.overlap {
|
||||
border-color: #ff4757;
|
||||
}
|
||||
|
||||
.sticker-thumb-img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.sticker-del {
|
||||
position: absolute;
|
||||
top: 4px;
|
||||
right: 4px;
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
background: rgba(255, 71, 87, 0.85);
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.del-icon {
|
||||
color: #fff;
|
||||
font-size: 24px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.sticker-add-btn {
|
||||
width: 120px;
|
||||
height: 120px;
|
||||
border: 2px dashed var(--line-star);
|
||||
border-radius: 12px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: var(--bg-input);
|
||||
}
|
||||
|
||||
.add-icon {
|
||||
font-size: 48px;
|
||||
color: var(--accent-pink);
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.add-label {
|
||||
font-size: 22px;
|
||||
color: var(--text-secondary);
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
.overlap-hint {
|
||||
display: block;
|
||||
margin-top: 16px;
|
||||
font-size: 26px;
|
||||
color: #ff4757;
|
||||
font-weight: 600;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
/* 工具栏 */
|
||||
.toolbar {
|
||||
padding: 28px 32px;
|
||||
}
|
||||
|
||||
.tool-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.tool-row:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.tool-label {
|
||||
font-size: 28px;
|
||||
font-weight: 600;
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
.tool-btn {
|
||||
width: 56px;
|
||||
height: 56px;
|
||||
background: linear-gradient(135deg, rgba(255, 154, 158, 0.08) 0%, rgba(160, 196, 255, 0.08) 100%);
|
||||
border: 2px dashed var(--accent-blue);
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 32px;
|
||||
color: var(--text-primary);
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.tool-value {
|
||||
font-size: 28px;
|
||||
font-weight: 600;
|
||||
color: var(--accent-pink);
|
||||
min-width: 80px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.tool-hint {
|
||||
font-size: 24px;
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
|
||||
/* 预览弹窗 */
|
||||
.preview-overlay {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 1000;
|
||||
padding: 40px;
|
||||
}
|
||||
|
||||
.preview-card {
|
||||
background: var(--bg-card);
|
||||
width: 100%;
|
||||
max-height: 80vh;
|
||||
overflow-y: auto;
|
||||
padding: 40px;
|
||||
}
|
||||
|
||||
.preview-title {
|
||||
font-size: 36px;
|
||||
font-weight: 700;
|
||||
color: var(--text-primary);
|
||||
display: block;
|
||||
margin-bottom: 24px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.preview-canvas {
|
||||
background: linear-gradient(135deg, rgba(255, 154, 158, 0.08) 0%, rgba(160, 196, 255, 0.08) 100%);
|
||||
border-radius: 16px;
|
||||
overflow: hidden;
|
||||
margin: 0 auto 24px;
|
||||
border: 3px dashed var(--accent-blue);
|
||||
position: relative;
|
||||
min-width: 200px;
|
||||
min-height: 200px;
|
||||
}
|
||||
|
||||
.preview-image {
|
||||
position: absolute;
|
||||
max-width: 100%;
|
||||
max-height: 100%;
|
||||
z-index: 5;
|
||||
}
|
||||
|
||||
.preview-image.overlap {
|
||||
border: 2px solid #ff4757;
|
||||
}
|
||||
|
||||
.product-info {
|
||||
text-align: center;
|
||||
margin-bottom: 32px;
|
||||
}
|
||||
|
||||
.product-name {
|
||||
font-size: 30px;
|
||||
font-weight: 700;
|
||||
color: var(--text-primary);
|
||||
display: block;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.product-size {
|
||||
font-size: 24px;
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
|
||||
.preview-actions {
|
||||
display: flex;
|
||||
gap: 20px;
|
||||
}
|
||||
|
||||
.preview-actions .btn-outline,
|
||||
.preview-actions .btn-gradient {
|
||||
flex: 1;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.preview-actions .btn-gradient.disabled {
|
||||
opacity: 0.5;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
/* 按钮 */
|
||||
.action-btns {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 20px;
|
||||
}
|
||||
|
||||
.mt-20 {
|
||||
margin-top: 20px;
|
||||
}
|
||||
@@ -0,0 +1,392 @@
|
||||
import { View, Text, Image } from '@tarojs/components'
|
||||
import Taro from '@tarojs/taro'
|
||||
import { useState, useEffect } from 'react'
|
||||
import './index.scss'
|
||||
import { getProductById } from '../../utils/productConfig'
|
||||
import { getDesignList, setDesignList, updateDesign, type DesignItem, type StickerItem } from '../../utils/store'
|
||||
import ThemeToggle from '../../components/ThemeToggle'
|
||||
import { useThemeContext } from '../../context/ThemeContext'
|
||||
|
||||
export default function DIYPage() {
|
||||
const { theme } = useThemeContext()
|
||||
const [category, setCategory] = useState<any>(null)
|
||||
const [step, setStep] = useState(1)
|
||||
const [designId, setDesignId] = useState('')
|
||||
const [quantity, setQuantity] = useState(1)
|
||||
const [stickers, setStickers] = useState<StickerItem[]>([])
|
||||
const [activeStickerId, setActiveStickerId] = useState<string | null>(null)
|
||||
const [isDragging, setIsDragging] = useState(false)
|
||||
const [startPos, setStartPos] = useState({ x: 0, y: 0 })
|
||||
const [previewMode, setPreviewMode] = useState(false)
|
||||
const [hasOverlap, setHasOverlap] = useState(false)
|
||||
|
||||
useEffect(() => {
|
||||
const params = Taro.getCurrentInstance().router?.params
|
||||
const source = params?.source
|
||||
const productId = params?.productId || params?.category
|
||||
|
||||
if (source === 'product' && productId) {
|
||||
const product = getProductById(productId)
|
||||
if (product) {
|
||||
setCategory(product)
|
||||
setQuantity(Number(params?.quantity) || 1)
|
||||
const newDesign: DesignItem = {
|
||||
id: 'DSG' + Date.now(),
|
||||
productId: product.id,
|
||||
productName: product.name,
|
||||
productIcon: product.icon,
|
||||
unitPrice: product.price,
|
||||
count: Number(params?.quantity) || 1,
|
||||
status: 'designing',
|
||||
createdAt: new Date().toISOString().slice(0, 10)
|
||||
}
|
||||
const list = getDesignList()
|
||||
setDesignList([...list, newDesign])
|
||||
setDesignId(newDesign.id)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if (source === 'designList' && params?.designId) {
|
||||
const dId = params.designId
|
||||
const list = getDesignList()
|
||||
const design = list.find(d => d.id === dId)
|
||||
if (design) {
|
||||
setDesignId(dId)
|
||||
setQuantity(design.count)
|
||||
const product = getProductById(design.productId)
|
||||
if (product) setCategory(product)
|
||||
if (design.designData?.stickers) {
|
||||
setStickers(design.designData.stickers)
|
||||
} else if (design.designData?.imageSrc) {
|
||||
// 兼容旧版数据
|
||||
const s: StickerItem = {
|
||||
id: 'legacy_' + Date.now(),
|
||||
src: design.designData.imageSrc,
|
||||
x: design.designData.imagePos?.x || 0,
|
||||
y: design.designData.imagePos?.y || 0,
|
||||
scale: design.designData.imagePos?.scale || 1,
|
||||
width: 200,
|
||||
height: 200,
|
||||
isOverlapping: false
|
||||
}
|
||||
setStickers([s])
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// 默认情况(从首页 old category 参数兼容)
|
||||
if (productId) {
|
||||
const found = getProductById(productId)
|
||||
if (found) {
|
||||
setCategory(found)
|
||||
const newDesign: DesignItem = {
|
||||
id: 'DSG' + Date.now(),
|
||||
productId: found.id,
|
||||
productName: found.name,
|
||||
productIcon: found.icon,
|
||||
unitPrice: found.price,
|
||||
count: 1,
|
||||
status: 'designing',
|
||||
createdAt: new Date().toISOString().slice(0, 10)
|
||||
}
|
||||
const list = getDesignList()
|
||||
setDesignList([...list, newDesign])
|
||||
setDesignId(newDesign.id)
|
||||
}
|
||||
}
|
||||
}, [])
|
||||
|
||||
// 矩形碰撞检测
|
||||
const checkOverlap = (list: StickerItem[]) => {
|
||||
const newList = list.map(s => ({ ...s, isOverlapping: false }))
|
||||
for (let i = 0; i < newList.length; i++) {
|
||||
for (let j = i + 1; j < newList.length; j++) {
|
||||
const a = newList[i]
|
||||
const b = newList[j]
|
||||
const aw = a.width * a.scale
|
||||
const ah = a.height * a.scale
|
||||
const bw = b.width * b.scale
|
||||
const bh = b.height * b.scale
|
||||
if (
|
||||
a.x < b.x + bw &&
|
||||
a.x + aw > b.x &&
|
||||
a.y < b.y + bh &&
|
||||
a.y + ah > b.y
|
||||
) {
|
||||
newList[i].isOverlapping = true
|
||||
newList[j].isOverlapping = true
|
||||
}
|
||||
}
|
||||
}
|
||||
const overlapAny = newList.some(s => s.isOverlapping)
|
||||
setHasOverlap(overlapAny)
|
||||
return newList
|
||||
}
|
||||
|
||||
const addSticker = () => {
|
||||
Taro.chooseImage({
|
||||
count: 1,
|
||||
sizeType: ['compressed'],
|
||||
sourceType: ['album', 'camera'],
|
||||
success: (res) => {
|
||||
const src = res.tempFilePaths[0]
|
||||
// 获取图片尺寸用于碰撞检测
|
||||
Taro.getImageInfo({
|
||||
src,
|
||||
success: (info) => {
|
||||
const newSticker: StickerItem = {
|
||||
id: 'stk_' + Date.now(),
|
||||
src,
|
||||
x: 0,
|
||||
y: 0,
|
||||
scale: 1,
|
||||
width: info.width,
|
||||
height: info.height,
|
||||
isOverlapping: false
|
||||
}
|
||||
const next = [...stickers, newSticker]
|
||||
const checked = checkOverlap(next)
|
||||
setStickers(checked)
|
||||
setActiveStickerId(newSticker.id)
|
||||
},
|
||||
fail: () => {
|
||||
// fallback 尺寸
|
||||
const newSticker: StickerItem = {
|
||||
id: 'stk_' + Date.now(),
|
||||
src,
|
||||
x: 0,
|
||||
y: 0,
|
||||
scale: 1,
|
||||
width: 200,
|
||||
height: 200,
|
||||
isOverlapping: false
|
||||
}
|
||||
const next = [...stickers, newSticker]
|
||||
const checked = checkOverlap(next)
|
||||
setStickers(checked)
|
||||
setActiveStickerId(newSticker.id)
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const deleteSticker = (id: string) => {
|
||||
const next = stickers.filter(s => s.id !== id)
|
||||
const checked = checkOverlap(next)
|
||||
setStickers(checked)
|
||||
if (activeStickerId === id) setActiveStickerId(null)
|
||||
}
|
||||
|
||||
const handleStickerTouchStart = (e: any, id: string) => {
|
||||
const touch = e.touches[0]
|
||||
const s = stickers.find(x => x.id === id)
|
||||
if (!s) return
|
||||
setActiveStickerId(id)
|
||||
setIsDragging(true)
|
||||
setStartPos({ x: touch.clientX - s.x, y: touch.clientY - s.y })
|
||||
}
|
||||
|
||||
const handleStickerTouchMove = (e: any) => {
|
||||
if (!isDragging || !activeStickerId) return
|
||||
const touch = e.touches[0]
|
||||
const next = stickers.map(s => {
|
||||
if (s.id !== activeStickerId) return s
|
||||
return { ...s, x: touch.clientX - startPos.x, y: touch.clientY - startPos.y }
|
||||
})
|
||||
const checked = checkOverlap(next)
|
||||
setStickers(checked)
|
||||
}
|
||||
|
||||
const handleTouchEnd = () => setIsDragging(false)
|
||||
|
||||
const handleScale = (id: string, delta: number) => {
|
||||
const next = stickers.map(s => {
|
||||
if (s.id !== id) return s
|
||||
return { ...s, scale: Math.max(0.3, Math.min(3, s.scale + delta)) }
|
||||
})
|
||||
const checked = checkOverlap(next)
|
||||
setStickers(checked)
|
||||
}
|
||||
|
||||
const goBack = () => {
|
||||
Taro.navigateBack()
|
||||
}
|
||||
|
||||
const getMaskStyle = () => {
|
||||
if (!category) return { width: 300, height: 420 }
|
||||
const base: any = { width: category.mask.width, height: category.mask.height }
|
||||
if (category.mask.shape === 'rect') {
|
||||
base.borderRadius = category.mask.borderRadius || 0
|
||||
}
|
||||
if (category.mask.shape === 'circle') {
|
||||
base.borderRadius = '50%'
|
||||
}
|
||||
return base
|
||||
}
|
||||
|
||||
const handleComplete = () => {
|
||||
if (hasOverlap) {
|
||||
Taro.showToast({ title: '贴纸不能重叠', icon: 'none' })
|
||||
return
|
||||
}
|
||||
if (designId) {
|
||||
updateDesign(designId, {
|
||||
designData: {
|
||||
stickers,
|
||||
category
|
||||
}
|
||||
})
|
||||
}
|
||||
setPreviewMode(false)
|
||||
Taro.navigateTo({ url: `/pages/checkout/index?designId=${designId}` })
|
||||
}
|
||||
|
||||
if (!category) {
|
||||
return (
|
||||
<View className={`theme-${theme}`}>
|
||||
<View className='diy-page'>
|
||||
<Text className='page-title'>加载中...</Text>
|
||||
</View>
|
||||
</View>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<View className={`theme-${theme}`}>
|
||||
<View className='diy-page'>
|
||||
<ThemeToggle />
|
||||
|
||||
<View className='page-header dashed-card mt-20'>
|
||||
<View className='star-badge' />
|
||||
<View className='flex-between' style={{ width: '100%' }}>
|
||||
<Text className='back-btn' onClick={goBack}>←</Text>
|
||||
<Text className='page-title'>设计工作台</Text>
|
||||
<View style={{ width: '60px' }} />
|
||||
</View>
|
||||
</View>
|
||||
|
||||
{/* 画布区域 */}
|
||||
<View className='canvas-wrapper dashed-card mt-20'>
|
||||
<View className='star-badge' />
|
||||
<View className='canvas-area' style={getMaskStyle()}>
|
||||
{stickers.map(s => (
|
||||
<Image
|
||||
key={s.id}
|
||||
className={`canvas-image ${s.isOverlapping ? 'overlap' : ''} ${activeStickerId === s.id ? 'active' : ''}`}
|
||||
src={s.src}
|
||||
style={{
|
||||
transform: `translate(${s.x}px, ${s.y}px) scale(${s.scale})`,
|
||||
opacity: isDragging && activeStickerId === s.id ? 0.8 : 1,
|
||||
zIndex: activeStickerId === s.id ? 10 : 5,
|
||||
width: s.width || 200,
|
||||
height: s.height || 200
|
||||
}}
|
||||
onTouchStart={(e) => handleStickerTouchStart(e, s.id)}
|
||||
onTouchMove={handleStickerTouchMove}
|
||||
onTouchEnd={handleTouchEnd}
|
||||
onClick={() => setActiveStickerId(s.id)}
|
||||
mode='aspectFit'
|
||||
/>
|
||||
))}
|
||||
<View className='mask-border' style={getMaskStyle()} />
|
||||
</View>
|
||||
</View>
|
||||
|
||||
{/* 贴纸列表与控制 */}
|
||||
<View className='sticker-panel dashed-card mt-20'>
|
||||
<View className='star-badge' />
|
||||
<Text className='section-title'>贴纸</Text>
|
||||
<View className='sticker-list'>
|
||||
{stickers.map(s => (
|
||||
<View key={s.id} className={`sticker-thumb ${s.isOverlapping ? 'overlap' : ''} ${activeStickerId === s.id ? 'active' : ''}`}>
|
||||
<Image src={s.src} className='sticker-thumb-img' mode='aspectFit' onClick={() => setActiveStickerId(s.id)} />
|
||||
<View className='sticker-del' onClick={() => deleteSticker(s.id)}>
|
||||
<Text className='del-icon'>×</Text>
|
||||
</View>
|
||||
</View>
|
||||
))}
|
||||
<View className='sticker-add-btn' onClick={addSticker}>
|
||||
<Text className='add-icon'>+</Text>
|
||||
<Text className='add-label'>添加</Text>
|
||||
</View>
|
||||
</View>
|
||||
{hasOverlap && <Text className='overlap-hint'>⚠️ 有贴纸重叠,请调整位置</Text>}
|
||||
</View>
|
||||
|
||||
{/* 控制工具栏 */}
|
||||
{activeStickerId && (
|
||||
<View className='toolbar dashed-card mt-20'>
|
||||
<View className='star-badge' />
|
||||
<View className='tool-row'>
|
||||
<Text className='tool-label'>缩放</Text>
|
||||
<View className='flex-center' style={{ gap: '20px' }}>
|
||||
<View className='tool-btn' onClick={() => handleScale(activeStickerId, -0.1)}>-</View>
|
||||
<Text className='tool-value'>
|
||||
{Math.round((stickers.find(s => s.id === activeStickerId)?.scale || 1) * 100)}%
|
||||
</Text>
|
||||
<View className='tool-btn' onClick={() => handleScale(activeStickerId, 0.1)}>+</View>
|
||||
</View>
|
||||
</View>
|
||||
<View className='tool-row'>
|
||||
<Text className='tool-label'>提示</Text>
|
||||
<Text className='tool-hint'>拖动调整位置,贴纸不可重叠</Text>
|
||||
</View>
|
||||
</View>
|
||||
)}
|
||||
|
||||
{/* 底部操作按钮 */}
|
||||
<View className='action-btns mt-20'>
|
||||
<View className='btn-gradient' onClick={() => setPreviewMode(true)}>
|
||||
<Text>预览效果</Text>
|
||||
</View>
|
||||
<View className='btn-outline' onClick={addSticker}>
|
||||
<Text>添加贴纸</Text>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
{/* 预览弹层 */}
|
||||
{previewMode && (
|
||||
<View className='preview-overlay'>
|
||||
<View className='preview-card dashed-card'>
|
||||
<View className='star-badge' />
|
||||
<Text className='preview-title'>确认效果</Text>
|
||||
<View className='preview-canvas' style={getMaskStyle()}>
|
||||
{stickers.map(s => (
|
||||
<Image
|
||||
key={s.id}
|
||||
className={`preview-image ${s.isOverlapping ? 'overlap' : ''}`}
|
||||
src={s.src}
|
||||
style={{
|
||||
transform: `translate(${s.x}px, ${s.y}px) scale(${s.scale})`,
|
||||
width: s.width || 200,
|
||||
height: s.height || 200
|
||||
}}
|
||||
mode='aspectFit'
|
||||
/>
|
||||
))}
|
||||
</View>
|
||||
<View className='product-info'>
|
||||
<Text className='product-name'>{category.name}</Text>
|
||||
<Text className='product-size'>画布尺寸: {category.mask.width} × {category.mask.height} px</Text>
|
||||
{hasOverlap && <Text className='overlap-hint'>贴纸有重叠,不可提交</Text>}
|
||||
</View>
|
||||
<View className='preview-actions'>
|
||||
<View className='btn-outline' onClick={() => setPreviewMode(false)}>
|
||||
<Text>返回修改</Text>
|
||||
</View>
|
||||
<View className={`btn-gradient ${hasOverlap ? 'disabled' : ''}`} onClick={handleComplete}>
|
||||
<Text>确认完成</Text>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
)}
|
||||
|
||||
<View style={{ height: '40px' }} />
|
||||
</View>
|
||||
</View>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user