account/responses page

This commit is contained in:
2025-05-26 12:15:32 +03:00
parent 50e6da10f1
commit c761c60818
8 changed files with 252 additions and 11 deletions

View File

@@ -8,6 +8,7 @@ import { RiUser3Line } from 'react-icons/ri'
import { FaRoute } from 'react-icons/fa'
import { GoPackageDependents, GoPackageDependencies } from 'react-icons/go'
import { MdOutlinePayments, MdOutlineContactSupport } from 'react-icons/md'
import { IoGitPullRequest } from 'react-icons/io5'
import useUserStore from '@/app/store/userStore'
export default function AccountLayout({ children }: { children: React.ReactNode }) {
@@ -35,6 +36,7 @@ export default function AccountLayout({ children }: { children: React.ReactNode
const userNavigation = [
{ name: 'Профиль', href: '/account', icon: RiUser3Line },
{ name: 'Мои маршруты', href: '/account/routes', icon: FaRoute },
{ name: 'Мои отклики', href: '/account/responses', icon: IoGitPullRequest },
{
name: 'Отправить посылку',
href: '/account/create-as-sender',

View File

@@ -0,0 +1,139 @@
'use client'
import React, { useEffect, useState } from 'react'
import Loader from '@/components/ui/Loader'
import { LeadPageProps } from '@/app/types'
const ResponsesPage = () => {
const [leads, setLeads] = useState<LeadPageProps[]>([])
const [isLoading, setIsLoading] = useState(true)
const [error, setError] = useState<string | null>(null)
useEffect(() => {
const fetchLeads = async () => {
try {
const response = await fetch('/api/account/requests')
if (!response.ok) {
throw new Error('Failed to fetch leads')
}
const data = await response.json()
setLeads(data)
} catch (err) {
console.error('Component error:', err)
setError(err instanceof Error ? err.message : 'Failed to load leads')
} finally {
setIsLoading(false)
}
}
fetchLeads()
}, [])
if (isLoading) {
return <Loader />
}
if (error) {
return <div className="p-8 text-center text-red-500">{error}</div>
}
return (
<div className="space-y-3">
<div className="overflow-hidden rounded-2xl shadow">
<div className="bg-white p-6 sm:p-8">
<div className="space-y-4">
<div className="flex items-center justify-between">
<h1 className="text-2xl">Мои отклики</h1>
</div>
</div>
{leads.length > 0 && (
<div className="mt-4 space-y-4">
{leads.map(lead => (
<div
key={lead.id}
className="space-y-4 rounded-2xl border bg-white p-6 transition-shadow hover:shadow-md"
>
<div className="flex flex-col space-y-4">
<div className="flex flex-col sm:flex-row sm:items-center sm:justify-between">
<div>
<div className="text-sm text-gray-500">Маршрут</div>
<div className="font-medium">#{lead.route.id}</div>
<div className="mt-1 text-sm text-gray-600">
{lead.route.from_city_name}, {lead.route.from_country_name} {' '}
{lead.route.to_city_name}, {lead.route.to_country_name}
</div>
<div className="mt-1 text-xs text-gray-500">
{lead.route.formatted_departure} - {lead.route.formatted_arrival}
</div>
<div className="mt-1 text-xs text-gray-500">
<span className="font-medium">Тип груза:</span>{' '}
{lead.route.formatted_cargo_type} {' '}
<span className="font-medium">Транспорт:</span>{' '}
{lead.route.formatted_transport}
</div>
{lead.route.comment && (
<div className="mt-1 text-xs text-gray-500">
<span className="font-medium">Комментарий к маршруту:</span>{' '}
{lead.route.comment}
</div>
)}
<div className="mt-2 flex items-center text-xs text-gray-500">
<svg
className="mr-1 h-4 w-4 text-gray-400"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z"
/>
</svg>
{lead.owner_name}
<span className="mx-1"></span>
<a
href={`mailto:${lead.owner_email}`}
className="text-blue-600 hover:text-blue-800"
>
{lead.owner_email}
</a>
</div>
</div>
<div className="mt-4 sm:mt-0 sm:text-right">
<div className="text-sm text-gray-500">Предложенная цена</div>
<div className="text-lg font-medium">{lead.moving_price} тенге</div>
</div>
</div>
{lead.comment && (
<div className="rounded-lg bg-gray-50 p-3">
<div className="text-sm text-gray-500">Комментарий к отклику:</div>
<div className="mt-1">{lead.comment}</div>
</div>
)}
<div className="text-sm text-gray-500">
Отправлено:{' '}
{new Date(lead.created_at).toLocaleString('ru-RU', {
year: 'numeric',
month: 'long',
day: 'numeric',
hour: '2-digit',
minute: '2-digit',
})}
</div>
</div>
</div>
))}
</div>
)}
</div>
</div>
</div>
)
}
export default ResponsesPage

View File

@@ -50,10 +50,8 @@ export default async function UserRoutes() {
</div>
{(!routes || routes.length === 0) && (
<div className="flex flex-col items-center justify-center py-12 text-gray-500">
<p className="text-lg">У вас пока нет завершенных маршрутов</p>
<p className="text-sm">
Создавайте или принимайте заявки на перевозку, чтобы они отобразились тут
</p>
<p className="text-lg">У вас пока нет созданных маршрутов</p>
<p className="text-sm">Создавайте заявки на перевозку, чтобы они отобразились тут</p>
</div>
)}
{routes.length > 0 && (

View File

@@ -0,0 +1,38 @@
import { NextRequest } from 'next/server'
import { getServerSession } from 'next-auth'
import { authOptions } from '@/app/api/auth/[...nextauth]/route'
export async function GET(req: NextRequest) {
try {
const session = await getServerSession(authOptions)
if (!session) {
console.error('No session found')
return new Response(JSON.stringify({ error: 'Unauthorized' }), {
status: 401,
})
}
const response = await fetch(`${process.env.NEXT_PUBLIC_API_URL}/account/leads/`, {
method: 'GET',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${session.accessToken}`,
},
})
if (!response.ok) {
const error = await response.json()
console.error('API error:', error)
return new Response(JSON.stringify(error), { status: response.status })
}
const result = await response.json()
return new Response(JSON.stringify(result), { status: 200 })
} catch (error) {
console.error('Route handler error:', error)
return new Response(JSON.stringify({ error: 'Internal Server Error' }), {
status: 500,
})
}
}

View File

@@ -157,7 +157,7 @@ export interface TextAreaProps {
}
export interface Route {
id: string
id: string | number
from_city_name: string
to_city_name: string
from_country_name: string
@@ -168,6 +168,9 @@ export interface Route {
formatted_transport: string
comment?: string
owner_type: string
status: string
owner_email: string
owner_name: string
}
export interface SelectOption {
@@ -238,11 +241,20 @@ export interface SearchPageProps {
}
export interface Lead {
id: number
name: string
phone_number: string
email: string
route: Route
moving_user: number
moving_price: string
moving_date: string
comment: string
route?: number
comment?: string
created_at: string
status: 'actual' | 'canceled' | 'completed'
}
export interface LeadPageProps extends Lead {
owner_name: string
owner_email: string
}