Реализация реферальной системы и улучшение системы авторизации

- Добавлена полная реферальная система с GraphQL резолверами и UI компонентами
- Улучшена система регистрации с поддержкой ВКонтакте и реферальных ссылок
- Обновлена схема Prisma для поддержки реферальной системы
- Добавлены новые файлы документации правил системы
- Улучшена система партнерства и контрагентов
- Обновлены компоненты авторизации для поддержки новых функций
- Удален устаревший server.log

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Veronika Smirnova
2025-08-11 09:47:00 +03:00
parent af16402f22
commit 8f7ec70fe6
28 changed files with 5827 additions and 4313 deletions

View File

@ -10,8 +10,6 @@ import {
CreditCard,
Key,
Edit3,
ExternalLink,
Copy,
CheckCircle,
AlertTriangle,
MessageCircle,
@ -53,8 +51,6 @@ export function UserSettings() {
type: 'success' | 'error'
text: string
} | null>(null)
const [partnerLink, setPartnerLink] = useState('')
const [isGenerating, setIsGenerating] = useState(false)
const [isUploadingAvatar, setIsUploadingAvatar] = useState(false)
const [localAvatarUrl, setLocalAvatarUrl] = useState<string | null>(null)
const phoneInputRef = useRef<HTMLInputElement | null>(null)
@ -278,56 +274,6 @@ export function UserSettings() {
const profileStatus = checkProfileCompleteness()
const isIncomplete = profileStatus.percentage < 100
const generatePartnerLink = async () => {
if (!user?.id) return
setIsGenerating(true)
setSaveMessage(null)
try {
// Генерируем уникальный код партнера
const partnerCode = btoa(user.id + Date.now())
.replace(/[^a-zA-Z0-9]/g, '')
.substring(0, 12)
const link = `${window.location.origin}/register?partner=${partnerCode}`
setPartnerLink(link)
setSaveMessage({
type: 'success',
text: 'Партнерская ссылка сгенерирована!',
})
// TODO: Сохранить партнерский код в базе данных
} catch (error) {
console.error('Error generating partner link:', error)
setSaveMessage({ type: 'error', text: 'Ошибка при генерации ссылки' })
} finally {
setIsGenerating(false)
}
}
const handleCopyLink = async () => {
if (!partnerLink) {
await generatePartnerLink()
return
}
try {
await navigator.clipboard.writeText(partnerLink)
setSaveMessage({ type: 'success', text: 'Ссылка скопирована!' })
} catch (error) {
console.error('Error copying to clipboard:', error)
setSaveMessage({ type: 'error', text: 'Ошибка при копировании' })
}
}
const handleOpenLink = async () => {
if (!partnerLink) {
await generatePartnerLink()
return
}
window.open(partnerLink, '_blank')
}
const handleAvatarUpload = async (event: React.ChangeEvent<HTMLInputElement>) => {
const file = event.target.files?.[0]
@ -1589,61 +1535,23 @@ export function UserSettings() {
</div>
</div>
{(user?.organization?.type === 'FULFILLMENT' ||
user?.organization?.type === 'LOGIST' ||
user?.organization?.type === 'WHOLESALE') && (
<div className="space-y-6">
<div>
<h4 className="text-white font-medium mb-2">Партнерская программа</h4>
<p className="text-white/70 text-sm mb-4">
Приглашайте новых контрагентов по уникальной ссылке. При регистрации они автоматически
становятся вашими партнерами.
</p>
<div className="space-y-3">
<div className="flex gap-2">
<Button
size="sm"
variant="outline"
className="glass-secondary text-white hover:text-white cursor-pointer text-xs px-3 py-2"
onClick={generatePartnerLink}
disabled={isGenerating}
>
<RefreshCw className={`h-3 w-3 mr-1 ${isGenerating ? 'animate-spin' : ''}`} />
{isGenerating ? 'Генерируем...' : 'Сгенерировать ссылку'}
</Button>
</div>
{partnerLink && (
<div className="space-y-2">
<div className="flex gap-2">
<Button
size="sm"
variant="outline"
className="glass-secondary text-white hover:text-white cursor-pointer text-xs px-3 py-2"
onClick={handleOpenLink}
>
<ExternalLink className="h-3 w-3 mr-1" />
Открыть ссылку
</Button>
<Button
size="sm"
variant="outline"
className="glass-secondary text-white hover:text-white cursor-pointer px-2"
onClick={handleCopyLink}
>
<Copy className="h-3 w-3" />
</Button>
</div>
<p className="text-white/60 text-xs">
Ваша партнерская ссылка сгенерирована и готова к использованию
</p>
</div>
)}
</div>
<div className="space-y-6">
<div className="text-center py-12">
<Settings className="h-16 w-16 text-white/20 mx-auto mb-4" />
<h3 className="text-lg font-medium text-white mb-2">
Инструменты в разработке
</h3>
<p className="text-white/60 text-sm max-w-md mx-auto">
Здесь будут размещены полезные бизнес-инструменты:
калькуляторы, аналитика, планировщики и автоматизация процессов.
</p>
<div className="mt-6">
<Badge variant="outline" className="bg-blue-500/20 text-blue-300 border-blue-500/30">
Скоро появится
</Badge>
</div>
</div>
)}
</div>
</Card>
</TabsContent>
</Tabs>