edit referrals page, add referrals fetch functions

This commit is contained in:
smanylov
2026-02-07 14:31:04 +07:00
parent 7572c1ada2
commit 0ec7834cc5
11 changed files with 273 additions and 70 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "no-copy-frontend", "name": "no-copy-frontend",
"version": "0.33.0", "version": "0.34.0",
"private": true, "private": true,
"scripts": { "scripts": {
"dev": "next dev -p 2999", "dev": "next dev -p 2999",
+123
View File
@@ -0,0 +1,123 @@
'use server'
import { getSessionData } from '@/app/actions/session';
import { API_BASE_URL } from '@/app/actions/definitions';
export async function fetchReferralsLevels() {
const token = await getSessionData('token');
try {
const response = await fetch(`${API_BASE_URL}/api/v1/data`, {
method: 'POST',
body: JSON.stringify({
version: 1,
msg_id: 30003,
message_body: {
action: 'levels',
token: token,
}
}),
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json'
}
});
if (response.ok) {
let parsed = await response.json();
if (parsed.message_code === 0) {
return parsed.message_body.length ? parsed.message_body : parsed;
} else {
throw parsed;
}
} else {
throw (`${response.status}`);
}
} catch (error) {
return {
error: error
}
}
}
export async function fetchReferralUserStats() {
const token = await getSessionData('token');
try {
const response = await fetch(`${API_BASE_URL}/api/v1/data`, {
method: 'POST',
body: JSON.stringify({
version: 1,
msg_id: 30003,
message_body: {
action: 'userStats',
token: token,
}
}),
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json'
}
});
if (response.ok) {
let parsed = await response.json();
if (parsed.message_code === 0) {
return parsed.message_body;
} else {
throw parsed;
}
} else {
throw (`${response.status}`);
}
} catch (error) {
return {
error: error
}
}
}
export async function fetchReferralInvitees() {
const token = await getSessionData('token');
try {
const response = await fetch(`${API_BASE_URL}/api/v1/data`, {
method: 'POST',
body: JSON.stringify({
version: 1,
msg_id: 30003,
message_body: {
action: 'invitees',
token: token,
pageSize: 10,
pageNumber: 0
}
}),
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json'
}
});
if (response.ok) {
let parsed = await response.json();
if (parsed.message_code === 0) {
return parsed.message_body;
} else {
throw parsed;
}
} else {
throw (`${response.status}`);
}
} catch (error) {
return {
error: error
}
}
}
+5
View File
@@ -1,6 +1,7 @@
import { QueryClient } from '@tanstack/react-query'; import { QueryClient } from '@tanstack/react-query';
import { getUserData, getUserFilesInfo } from '@/app/actions/action'; import { getUserData, getUserFilesInfo } from '@/app/actions/action';
import { getUserFilesData } from '@/app/actions/fileEntity'; import { getUserFilesData } from '@/app/actions/fileEntity';
import {fetchReferralUserStats} from '@/app/actions/referralsActions';
export async function prefetchLayoutQueries(queryClient: QueryClient) { export async function prefetchLayoutQueries(queryClient: QueryClient) {
await Promise.all([ await Promise.all([
@@ -19,5 +20,9 @@ export async function prefetchLayoutQueries(queryClient: QueryClient) {
queryKey: ['userFilesInfo'], queryKey: ['userFilesInfo'],
queryFn: () => getUserFilesInfo() queryFn: () => getUserFilesInfo()
}), }),
queryClient.prefetchQuery({
queryKey: ['referralUserStats'],
queryFn: () => fetchReferralUserStats()
}),
]); ]);
} }
+1
View File
@@ -236,6 +236,7 @@
border-bottom: 1px solid v.$b-color-1; border-bottom: 1px solid v.$b-color-1;
align-items: center; align-items: center;
overflow: auto; overflow: auto;
border-radius: 10px;
.stats-item { .stats-item {
border: 1px solid v.$b-color-1; border: 1px solid v.$b-color-1;
+21
View File
@@ -11,8 +11,25 @@ import navigation from './navigation.json';
import { useSideMenuStore } from '@/app/stores/sideMenuStore'; import { useSideMenuStore } from '@/app/stores/sideMenuStore';
import { useRef } from 'react'; import { useRef } from 'react';
import { useClickOutside } from '@/app/hooks/useClickOutside'; import { useClickOutside } from '@/app/hooks/useClickOutside';
import { fetchReferralUserStats } from '@/app/actions/referralsActions';
import { useQuery } from '@tanstack/react-query';
export default function NavLinks() { export default function NavLinks() {
const {
data: referralLink,
isLoading,
isError,
error
} = useQuery({
queryKey: ['referralUserStats'],
queryFn: () => {
return fetchReferralUserStats();
},
select: (data) => {
return data?.referralLink;
}
});
const pathname = usePathname().replace('/en/', '/').replace('/ru/', '/'); const pathname = usePathname().replace('/en/', '/').replace('/ru/', '/');
const t = useTranslations('Global'); const t = useTranslations('Global');
@@ -69,6 +86,10 @@ export default function NavLinks() {
<DropDownList /> <DropDownList />
{links.map((link) => { {links.map((link) => {
if (!referralLink && link.name === 'referral-program') {
return null;
}
return ( return (
<Link <Link
key={link.name} key={link.name}
@@ -10,7 +10,7 @@ export default function IncomeAndPayments() {
<div className="earning-card success"> <div className="earning-card success">
<h4>💰 Доступно к выводу</h4> <h4>💰 Доступно к выводу</h4>
<p> <p>
135.00 Б 0
</p> </p>
<small>Минимальная сумма вывода: 100 Б</small> <small>Минимальная сумма вывода: 100 Б</small>
</div> </div>
@@ -18,7 +18,7 @@ export default function IncomeAndPayments() {
<div className="earning-card"> <div className="earning-card">
<h4>📈 Всего заработано</h4> <h4>📈 Всего заработано</h4>
<p> <p>
135.00 Б 0
</p> </p>
<small>За все время участия в программе</small> <small>За все время участия в программе</small>
</div> </div>
@@ -26,7 +26,7 @@ export default function IncomeAndPayments() {
<div className="earning-card warning"> <div className="earning-card warning">
<h4> Выплачено</h4> <h4> Выплачено</h4>
<p> <p>
0.00 Б 0
</p> </p>
<small>Успешно выплачено на ваши счета</small> <small>Успешно выплачено на ваши счета</small>
</div> </div>
@@ -70,8 +70,8 @@ export default function IncomeAndPayments() {
Обработано Обработано
</div> </div>
<div className="stats-item first-column second-row"> <div className="stats-item first-column left-bottom-corner">
100.00 0
</div> </div>
<div className="stats-item second-row"> <div className="stats-item second-row">
0 0
@@ -82,39 +82,7 @@ export default function IncomeAndPayments() {
<div className="stats-item second-row"> <div className="stats-item second-row">
0 0
</div> </div>
<div className="stats-item second-row last-column"> <div className="stats-item last-column right-bottom-corner">
0
</div>
<div className="stats-item first-column">
100.00
</div>
<div className="stats-item">
0
</div>
<div className="stats-item">
0
</div>
<div className="stats-item">
0
</div>
<div className="stats-item last-column">
0
</div>
<div className="stats-item last-row left-bottom-corner first-column">
100.00
</div>
<div className="stats-item last-row">
0
</div>
<div className="stats-item last-row">
0
</div>
<div className="stats-item last-row">
0
</div>
<div className="stats-item last-row last-column right-bottom-corner">
0 0
</div> </div>
</div> </div>
@@ -1,4 +1,38 @@
'use client'
import { useQuery } from '@tanstack/react-query';
import { fetchReferralsLevels } from '@/app/actions/referralsActions';
import { useEffect } from 'react';
export default function CommissionLevels() { export default function CommissionLevels() {
const {
data: referralsLevels,
isLoading,
isError,
error
} = useQuery({
queryKey: ['referralsLevels'],
queryFn: () => {
return fetchReferralsLevels();
},
select: (data) => {
if (data?.message_body) {
return data?.message_body
} else {
return []
}
}
});
useEffect(() => {
console.log('referralsLevels');
console.log(referralsLevels);
}, [referralsLevels])
if (!referralsLevels?.length) {
return null;
}
return ( return (
<div className="block-wrapper"> <div className="block-wrapper">
<h3 className="section-title"> <h3 className="section-title">
+18 -22
View File
@@ -17,38 +17,34 @@ import DropDownList from '@/app/components/DropDownList';
import { useQuery, useQueryClient } from '@tanstack/react-query'; import { useQuery, useQueryClient } from '@tanstack/react-query';
import { toast } from 'sonner'; import { toast } from 'sonner';
import { pluralize } from '@/app/lib/pluralize'; import { pluralize } from '@/app/lib/pluralize';
import { fetchReferralInvitees } from '@/app/actions/referralsActions';
type FileItem = { type InviteesType = {
status?: string; status?: string;
email?: string; email?: string;
registrationData: number; registrationData: number;
}; };
type ApiFile = { type InviteType = {
status?: string; active?: string;
email?: string; email?: string;
registrationData: string; regDate: number;
}; };
type ApiResponse = {
files?: ApiFile[];
};
export default function InvitationsTable() { export default function InvitationsTable() {
const { const {
data: testData, data: referralInvitees,
isLoading, isLoading,
isError, isError,
error, error,
} = useQuery<ApiResponse, Error, FileItem[], ['testData']>({ } = useQuery<InviteType[], Error, InviteesType[], ['referralInvitees']>({
queryKey: ['testData'], queryKey: ['referralInvitees'],
queryFn: () => { queryFn: () => {
return {} return fetchReferralInvitees();
}, },
select: (data: ApiResponse): FileItem[] => { select: (data: InviteType[]): InviteesType[] => {
if (!data?.files) return [ if (!data) return [
{ {
status: 'string1', status: 'string1',
email: 'string1', email: 'string1',
@@ -66,11 +62,11 @@ export default function InvitationsTable() {
} }
]; ];
return data.files.map((item: ApiFile) => { return data.map((item: InviteType) => {
return { return {
status: 'string', status: item.active,
email: 'string', email: item.email,
registrationData: 40 registrationData: item.regDate
}; };
}); });
}, },
@@ -92,7 +88,7 @@ export default function InvitationsTable() {
const locale = useLocale(); const locale = useLocale();
// Определение колонок // Определение колонок
const columns = useMemo<ColumnDef<FileItem>[]>( const columns = useMemo<ColumnDef<InviteesType>[]>(
() => [ () => [
{ {
accessorKey: 'email', accessorKey: 'email',
@@ -207,7 +203,7 @@ export default function InvitationsTable() {
// Фильтрация по типу файла и дате // Фильтрация по типу файла и дате
const filteredData = useMemo(() => { const filteredData = useMemo(() => {
let result = testData; let result = referralInvitees;
if (!result) { if (!result) {
return []; return [];
} }
@@ -263,7 +259,7 @@ export default function InvitationsTable() {
} }
return result; return result;
}, [testData, statusFilter, dateFilter]); }, [referralInvitees, statusFilter, dateFilter]);
useEffect(() => { useEffect(() => {
const currentPageRows = table.getRowModel().rows; const currentPageRows = table.getRowModel().rows;
@@ -1,18 +1,71 @@
'use client'
import { fetchReferralUserStats } from '@/app/actions/referralsActions';
import { useQuery } from '@tanstack/react-query';
import { useTranslations } from 'next-intl';
import { useEffect, useRef, useState } from 'react';
import { toast } from 'sonner';
export default function ReferralLinkSection() { export default function ReferralLinkSection() {
const {
data: referralUserStats,
isLoading,
isError,
error
} = useQuery({
queryKey: ['referralUserStats'],
queryFn: () => {
return fetchReferralUserStats();
},
select: (data) => {
return data;
}
});
const t = useTranslations('Global')
const [referralUrl, setReferralUrl] = useState<string>('');
const refLink = useRef<HTMLElement>(null);
useEffect(() => {
if (typeof window !== 'undefined') {
setReferralUrl(`${window.location.origin}/register?ref=${referralUserStats?.referralLink}`);
}
}, [referralUserStats]);
const copyHandler = () => {
if (refLink.current?.textContent) {
navigator.clipboard.writeText(refLink.current?.textContent);
toast.success(`${t('copied')}: ${refLink.current?.textContent}`)
}
};
if (!referralUserStats?.referralLink) {
return null;
}
return ( return (
<div className="referral-link-section"> <div className="referral-link-section">
<h3>🔗 Ваша реферальная ссылка</h3> <h3>Ваша реферальная ссылка</h3>
<p>Поделитесь этой ссылкой с друзьями и получайте комиссию с каждой их покупки</p> <p>Поделитесь этой ссылкой с друзьями и получайте комиссию с каждой их покупки</p>
<div className="referral-link-input"> <div className="referral-link-input">
<span id="referral-link" > <span
https://dashboard.no-copy.ru/register.php?ref=REFA0406AC8 id="referral-link"
ref={refLink}
>
{referralUrl}
</span > </span >
<button className="copy-btn">📋 Копировать</button> <button
className="copy-btn"
onClick={copyHandler}
>
Копировать
</button>
</div> </div>
<p className="referral-link-footer"> <p className="referral-link-footer">
Код: <strong>REFA0406AC8</strong> Код: <strong>{referralUserStats?.referralLink}</strong>
Кликов: <strong>21</strong> Приглашений: <strong>
Комиссия: <strong>15%</strong> {referralUserStats?.totalInvitee}
</strong>
</p> </p>
</div> </div>
) )
+2 -1
View File
@@ -212,7 +212,8 @@
"are-no-violations": "There are no violations", "are-no-violations": "There are no violations",
"error-reading-image": "Error reading image", "error-reading-image": "Error reading image",
"error-user-not-have-tokens-for-protect": "User not have tokens for protect", "error-user-not-have-tokens-for-protect": "User not have tokens for protect",
"registration-date": "Registration date" "registration-date": "Registration date",
"copied": "Copied"
}, },
"Login-register-form": { "Login-register-form": {
"and": "and", "and": "and",
+2 -1
View File
@@ -212,7 +212,8 @@
"are-no-violations": "Нарушений нет", "are-no-violations": "Нарушений нет",
"error-reading-image": "Ошибка чтения изображения", "error-reading-image": "Ошибка чтения изображения",
"error-user-not-have-tokens-for-protect": "У пользователя нет токенов для защиты.", "error-user-not-have-tokens-for-protect": "У пользователя нет токенов для защиты.",
"registration-date": "Дата регистрации" "registration-date": "Дата регистрации",
"copied": "Скопировано"
}, },
"Login-register-form": { "Login-register-form": {
"and": "и", "and": "и",