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

- Добавлена полная реферальная система с 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

@ -15,11 +15,15 @@ import {
Mail,
MapPin,
X,
Copy,
Gift,
} from 'lucide-react'
import React, { useState, useMemo } from 'react'
import { toast } from 'sonner'
import { Badge } from '@/components/ui/badge'
import { Button } from '@/components/ui/button'
import { Card } from '@/components/ui/card'
import { GlassInput } from '@/components/ui/input'
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'
@ -29,6 +33,7 @@ import {
GET_INCOMING_REQUESTS,
GET_OUTGOING_REQUESTS,
SEARCH_ORGANIZATIONS,
GET_MY_PARTNER_LINK,
} from '@/graphql/queries'
import { OrganizationAvatar } from './organization-avatar'
@ -68,6 +73,7 @@ export function MarketCounterparties() {
const { data: counterpartiesData, loading: counterpartiesLoading } = useQuery(GET_MY_COUNTERPARTIES)
const { data: incomingData, loading: incomingLoading } = useQuery(GET_INCOMING_REQUESTS)
const { data: outgoingData, loading: outgoingLoading } = useQuery(GET_OUTGOING_REQUESTS)
const { data: partnerLinkData } = useQuery(GET_MY_PARTNER_LINK)
const [respondToRequest] = useMutation(RESPOND_TO_COUNTERPARTY_REQUEST, {
refetchQueries: [
@ -103,6 +109,23 @@ export function MarketCounterparties() {
awaitRefetchQueries: true,
})
// Функция копирования партнерской ссылки
const copyPartnerLink = async () => {
try {
const partnerLink = partnerLinkData?.myPartnerLink
if (!partnerLink) {
toast.error('Партнерская ссылка недоступна')
return
}
await navigator.clipboard.writeText(partnerLink)
toast.success('Партнерская ссылка скопирована!', {
description: 'Поделитесь ей для прямого делового сотрудничества'
})
} catch {
toast.error('Не удалось скопировать ссылку')
}
}
// Фильтрация и сортировка контрагентов
const filteredAndSortedCounterparties = useMemo(() => {
const filtered = (counterpartiesData?.myCounterparties || []).filter((org: Organization) => {
@ -298,6 +321,28 @@ export function MarketCounterparties() {
</TabsList>
<TabsContent value="counterparties" className="flex-1 overflow-hidden mt-3 flex flex-col">
{/* Блок с партнерской ссылкой */}
<Card className="glass-card p-4 mb-3">
<div className="flex items-center justify-between">
<div className="flex items-center gap-3">
<div className="p-2 rounded-lg bg-purple-500/20 border border-purple-500/30">
<Gift className="h-5 w-5 text-purple-400" />
</div>
<div>
<h3 className="text-white font-medium">Пригласить партнера</h3>
<p className="text-white/60 text-sm">Прямое деловое сотрудничество с автоматическим добавлением в партнеры</p>
</div>
</div>
<Button
onClick={copyPartnerLink}
className="glass-button hover:bg-white/20 transition-all duration-200"
>
<Copy className="h-4 w-4 mr-2" />
Копировать ссылку
</Button>
</div>
</Card>
{/* Компактная панель фильтров */}
<div className="glass-card p-3 mb-3 space-y-3">
<div className="flex flex-col xl:flex-row gap-3">