dynamic routes for main page

This commit is contained in:
2025-05-23 11:48:45 +03:00
parent efccb591ff
commit 45e5e78df2
10 changed files with 234 additions and 141 deletions

View File

@@ -1,9 +1,7 @@
from rest_framework import serializers from rest_framework import serializers
from routes.models import Route
from sitemanagement.models import FAQ, News from sitemanagement.models import FAQ, News
from django.conf import settings from routes.models import Country
import pytz from api.account.client.serializers import RouteSerializer
from routes.constants.routeChoices import cargo_type_choices, type_transport_choices
class FAQMainSerializer(serializers.ModelSerializer): class FAQMainSerializer(serializers.ModelSerializer):
class Meta: class Meta:
@@ -38,3 +36,87 @@ class TelegramSerializer(serializers.Serializer):
def create(self, validated_data): def create(self, validated_data):
return type('TelegramMessage', (), validated_data) return type('TelegramMessage', (), validated_data)
class HomePageRouteSerializer(RouteSerializer):
username = serializers.SerializerMethodField()
userImg = serializers.SerializerMethodField()
start_point = serializers.SerializerMethodField()
country_from = serializers.SerializerMethodField()
country_from_icon = serializers.SerializerMethodField()
country_from_code = serializers.SerializerMethodField()
end_point = serializers.SerializerMethodField()
country_to = serializers.SerializerMethodField()
country_to_icon = serializers.SerializerMethodField()
country_to_code = serializers.SerializerMethodField()
cargo_type = serializers.SerializerMethodField()
user_request = serializers.SerializerMethodField()
user_comment = serializers.CharField(source='comment')
moving_type = serializers.SerializerMethodField()
estimated_date = serializers.SerializerMethodField()
day_out = serializers.DateTimeField(source='departure_DT')
day_in = serializers.DateTimeField(source='arrival_DT')
def get_username(self, obj):
return obj.owner.first_name if obj.owner else None
def get_userImg(self, obj):
try:
if obj.owner and hasattr(obj.owner, 'userprofile') and obj.owner.userprofile.image:
return obj.owner.userprofile.image.url
return None
except Exception as e:
print(f"Error in get_userImg: {e}")
return None
def get_start_point(self, obj):
return self.get_from_city_name(obj)
def get_country_from(self, obj):
return self.get_from_country_name(obj)
def get_country_from_icon(self, obj):
country = self.get_from_country_name(obj)
if not country:
return None
try:
country_obj = Country.objects.get(international_name=country)
return country_obj.flag_img_url
except Country.DoesNotExist:
return None
def get_country_from_code(self, obj):
country = self.get_from_country_name(obj)
return country[:3].upper() if country else None
def get_end_point(self, obj):
return self.get_to_city_name(obj)
def get_country_to(self, obj):
return self.get_to_country_name(obj)
def get_country_to_icon(self, obj):
country = self.get_to_country_name(obj)
if not country:
return None
try:
country_obj = Country.objects.get(international_name=country)
return country_obj.flag_img_url
except Country.DoesNotExist:
print(f"Country not found: {country}")
return None
def get_country_to_code(self, obj):
country = self.get_to_country_name(obj)
return country[:3].upper() if country else None
def get_cargo_type(self, obj):
return self.get_formatted_cargo_type(obj)
def get_user_request(self, obj):
return 'Нужен перевозчик' if obj.owner_type == 'customer' else 'Могу перевезти'
def get_moving_type(self, obj):
return self.get_formatted_transport(obj)
def get_estimated_date(self, obj):
return obj.arrival_DT

View File

@@ -4,12 +4,10 @@ from rest_framework import status
from rest_framework.views import APIView from rest_framework.views import APIView
from rest_framework.response import Response from rest_framework.response import Response
from api.utils.decorators import handle_exceptions from api.utils.decorators import handle_exceptions
from django.db.models import Q
from routes.models import Route from routes.models import Route
from routes.constants.routeChoices import owner_type_choices from routes.constants.routeChoices import owner_type_choices
from api.main.serializers import FAQMainSerializer, NewsMainSerializer, TelegramSerializer from api.main.serializers import FAQMainSerializer, NewsMainSerializer, TelegramSerializer, HomePageRouteSerializer
from api.account.client.serializers import RouteSerializer
from sitemanagement.models import FAQ, News from sitemanagement.models import FAQ, News
class FAQView(APIView): class FAQView(APIView):
@@ -39,16 +37,20 @@ class NewsView(APIView):
class LatestRoutesView(APIView): class LatestRoutesView(APIView):
@handle_exceptions @handle_exceptions
def get(self, request): def get(self, request):
"""Получаем последние 5 маршрутов для каждого типа owner_type""" """Получаем последние маршруты"""
latest_routes = {} routes = []
owner_types = dict(owner_type_choices).keys() owner_types = dict(owner_type_choices).keys()
for owner_type in owner_types: for owner_type in owner_types:
routes = Route.objects.filter(owner_type=owner_type).order_by('-id')[:5] routes.extend(
latest_routes[owner_type] = RouteSerializer(routes, many=True).data HomePageRouteSerializer(
Route.objects.filter(owner_type=owner_type).order_by('-id')[:5],
many=True
).data
)
return Response(latest_routes, status=status.HTTP_200_OK) return Response(routes, status=status.HTTP_200_OK)
class TelegramMessageView(APIView): class TelegramMessageView(APIView):
@handle_exceptions @handle_exceptions

View File

@@ -1,42 +1,43 @@
import React from 'react' import React from 'react'
import Image from 'next/image' import Image from 'next/image'
import Button from '@/components/ui/Button' import Button from '@/components/ui/Button'
import { SearchCardProps } from '@/app/types/index' import { SearchCardProps } from '@/app/types'
import noPhoto from '../../../../public/images/noPhoto.png'
const SearchCard = ({ const SearchCard = ({
id, id,
username, username,
owner_type,
from_city_name,
from_country_name,
to_city_name,
to_country_name,
formatted_cargo_type,
formatted_transport,
type_transport,
userImg, userImg,
start_point, comment,
country_from, formatted_departure,
formatted_arrival,
country_from_icon, country_from_icon,
country_from_code,
end_point,
country_to,
country_to_icon, country_to_icon,
country_to_code,
cargo_type,
user_request,
user_comment,
moving_type,
estimated_date,
day_out,
day_in,
}: SearchCardProps) => { }: SearchCardProps) => {
const getUserRequestStyles = () => { const getUserRequestStyles = () => {
if (user_request === 'Нужен перевозчик') { if (owner_type === 'customer') {
return 'text-[#065bff]' return 'text-[#065bff]'
} }
return 'text-[#45c226]' return 'text-[#45c226]'
} }
const setMovingTypeIcon = () => { const setMovingTypeIcon = () => {
if (moving_type === 'Авиатранспорт') { if (type_transport === 'air') {
return '/images/airplane.png' return '/images/airplane.png'
} }
return '/images/car.png' return '/images/car.png'
} }
const userRequest = owner_type === 'customer' ? 'Нужен перевозчик' : 'Могу перевезти'
return ( return (
<> <>
{/* десктоп */} {/* десктоп */}
@@ -46,21 +47,22 @@ const SearchCard = ({
<div className="flex items-center gap-5"> <div className="flex items-center gap-5">
<div className="flex h-16 w-16 items-center justify-center rounded-full bg-gray-200"> <div className="flex h-16 w-16 items-center justify-center rounded-full bg-gray-200">
<Image <Image
src={userImg} src={userImg || noPhoto}
alt={username} alt={`User ${username}`}
width={52} width={52}
height={52} height={52}
className="rounded-full object-cover" className="aspect-square w-full rounded-full object-cover md:w-[84px]"
/> />
</div> </div>
<div className="flex items-center gap-3"> <div className="flex items-center gap-3">
<div className="text-base font-semibold">{username}</div> <div className="text-base font-semibold">{username}</div>
<div className="text-gray-500">|</div> <div className="text-gray-500">|</div>
<div className={`text-base font-semibold ${getUserRequestStyles()}`}> <div className={`text-base font-semibold ${getUserRequestStyles()}`}>
{user_request} {userRequest}
</div> </div>
<div className="ml-1"> <div className="ml-1">
Тип посылки: <span className="text-orange ml-1 font-semibold">{cargo_type}</span> Тип посылки:{' '}
<span className="text-orange ml-1 font-semibold">{formatted_cargo_type}</span>
</div> </div>
</div> </div>
</div> </div>
@@ -72,30 +74,37 @@ const SearchCard = ({
<div className="rounded-lg bg-[#f8f8f8] p-5"> <div className="rounded-lg bg-[#f8f8f8] p-5">
<div className="flex items-baseline gap-2"> <div className="flex items-baseline gap-2">
<span className="text-gray-600">{user_comment}</span> <span className="text-gray-600">{comment}</span>
</div> </div>
</div> </div>
<div className="flex justify-end pt-2 text-sm text-gray-500">Объявление {id}</div> <div className="flex justify-end pt-2 text-sm text-gray-500">Объявление {id}</div>
<div className="mt-6 flex items-center justify-between"> <div className="mt-6 flex items-center justify-between">
<div className="flex flex-col"> <div className="flex flex-col">
{user_request === 'Нужен перевозчик' ? ( {userRequest === 'Нужен перевозчик' ? (
<span className="text-gray-500">Забрать из:</span> <span className="text-gray-500">Забрать из:</span>
) : ( ) : (
<span className="text-gray-500">Выезжаю из:</span> <span className="text-gray-500">Выезжаю из:</span>
)} )}
<div className="flex flex-col"> <div className="flex flex-col">
<div className="flex items-center"> <div className="flex items-center">
<Image src={country_from_icon} width={26} height={13} alt={country_from_code} /> <Image
<span className="pr-2 pl-1 text-gray-400">{country_from_code}</span> src={country_from_icon}
width={26}
height={13}
alt={from_country_name.substring(0, 3)}
/>
<span className="pr-2 pl-1 text-gray-400">
{from_country_name.substring(0, 3).toUpperCase()}
</span>
<span className="text-base font-semibold"> <span className="text-base font-semibold">
{start_point} / {country_from} {from_city_name} / {from_country_name}
</span> </span>
</div> </div>
{user_request === 'Могу перевезти' && ( {userRequest === 'Могу перевезти' && (
<div className="mt-1 text-sm text-gray-500"> <div className="mt-1 text-sm text-gray-500">
<span className="text-sm font-normal">Отправление:</span>{' '} <span className="text-sm font-normal">Отправление:</span>{' '}
<span className="text-sm font-semibold">{day_out?.toLocaleDateString()}</span> <span className="text-sm font-semibold">{formatted_departure}</span>
</div> </div>
)} )}
</div> </div>
@@ -103,7 +112,7 @@ const SearchCard = ({
<div className="text-center"> <div className="text-center">
<div className="flex items-center justify-center gap-2"> <div className="flex items-center justify-center gap-2">
<span className="text-base font-semibold">{moving_type}</span> <span className="text-base font-semibold">{formatted_transport}</span>
<Image <Image
src={setMovingTypeIcon()} src={setMovingTypeIcon()}
width={15} width={15}
@@ -124,18 +133,16 @@ const SearchCard = ({
<div className="relative z-10 h-5 w-5 rounded-full border-3 border-[#45c226] bg-white" /> <div className="relative z-10 h-5 w-5 rounded-full border-3 border-[#45c226] bg-white" />
</div> </div>
{user_request === 'Нужен перевозчик' && ( {userRequest === 'Нужен перевозчик' && (
<div className="text-sm text-gray-500"> <div className="text-sm text-gray-500">
<span className="text-sm font-normal">Дата доставки:</span>{' '} <span className="text-sm font-normal">Дата доставки:</span>{' '}
<span className="text-sm font-semibold"> <span className="text-sm font-semibold">{formatted_arrival}</span>
{estimated_date.toLocaleDateString()}
</span>
</div> </div>
)} )}
</div> </div>
<div className="-mb-[14px] flex flex-col"> <div className="-mb-[14px] flex flex-col">
{user_request === 'Нужен перевозчик' ? ( {userRequest === 'Нужен перевозчик' ? (
<div className="text-base text-gray-500">Доставить в:</div> <div className="text-base text-gray-500">Доставить в:</div>
) : ( ) : (
<div className="text-base text-gray-500">Прибываю в:</div> <div className="text-base text-gray-500">Прибываю в:</div>
@@ -143,16 +150,23 @@ const SearchCard = ({
<div className="flex flex-col"> <div className="flex flex-col">
<div className="flex items-center"> <div className="flex items-center">
<Image src={country_to_icon} width={26} height={13} alt={country_to_code} /> <Image
<span className="pr-2 pl-1 text-gray-400">{country_to_code}</span> src={country_to_icon}
width={26}
height={13}
alt={to_country_name.substring(0, 3)}
/>
<span className="pr-2 pl-1 text-gray-400">
{to_country_name.substring(0, 3).toUpperCase()}
</span>
<span className="text-base font-semibold"> <span className="text-base font-semibold">
{end_point} / {country_to} {to_city_name} / {to_country_name}
</span> </span>
</div> </div>
{user_request === 'Могу перевезти' && ( {userRequest === 'Могу перевезти' && (
<div className="text-sm text-gray-500"> <div className="text-sm text-gray-500">
<span className="text-sm font-normal">Прибытие:</span>{' '} <span className="text-sm font-normal">Прибытие:</span>{' '}
<span className="text-sm font-semibold">{day_in?.toLocaleDateString()}</span> <span className="text-sm font-semibold">{formatted_arrival}</span>
</div> </div>
)} )}
</div> </div>
@@ -165,28 +179,26 @@ const SearchCard = ({
<div className="block sm:hidden"> <div className="block sm:hidden">
<div className="my-4 w-full rounded-xl bg-white p-4 shadow-lg"> <div className="my-4 w-full rounded-xl bg-white p-4 shadow-lg">
<div className="flex items-center justify-between"> <div className="flex items-center justify-between">
<div className={`text-sm font-semibold ${getUserRequestStyles()}`}>{user_request}</div> <div className={`text-sm font-semibold ${getUserRequestStyles()}`}>{userRequest}</div>
<div className="text-sm font-semibold"> <div className="text-sm font-semibold">
Тип посылки: <span className="text-orange">{cargo_type}</span> Тип посылки: <span className="text-orange">{formatted_cargo_type}</span>
</div> </div>
</div> </div>
<div className="mt-5 mb-2 flex flex-row items-center justify-between gap-3"> <div className="mt-5 mb-2 flex flex-row items-center justify-between gap-3">
<div className="flex h-16 w-16 min-w-[64px] shrink-0 items-center justify-center rounded-full bg-gray-200"> <div className="flex h-16 w-16 min-w-[64px] shrink-0 items-center justify-center rounded-full bg-gray-200">
<Image <Image
src={userImg} src={noPhoto}
alt={username} alt={`User ${username}`}
width={52} width={52}
height={52} height={52}
className="aspect-square h-[52px] w-[52px] rounded-full object-cover" className="aspect-square h-[52px] w-[52px] rounded-full object-cover"
/> />
</div> </div>
<div className="flex-1 rounded-lg bg-[#f8f8f8] p-4 text-sm font-normal"> <div className="flex-1 rounded-lg bg-[#f8f8f8] p-4 text-sm font-normal">{comment}</div>
{user_comment}
</div>
</div> </div>
<div className="flex justify-end text-xs text-gray-500">Объявление {id}</div> <div className="flex justify-end text-xs text-gray-500">Объявление {id}</div>
{user_request === 'Нужен перевозчик' ? ( {userRequest === 'Нужен перевозчик' ? (
<span className="pl-7 text-sm text-gray-500">Забрать из:</span> <span className="pl-7 text-sm text-gray-500">Забрать из:</span>
) : ( ) : (
<span className="pl-7 text-sm text-gray-500">Выезжаю из:</span> <span className="pl-7 text-sm text-gray-500">Выезжаю из:</span>
@@ -207,16 +219,23 @@ const SearchCard = ({
</div> </div>
<div className="flex flex-1 flex-col justify-between"> <div className="flex flex-1 flex-col justify-between">
<div className="-mt-[14px] flex items-center"> <div className="-mt-[14px] flex items-center">
<Image src={country_from_icon} width={26} height={13} alt={country_from_code} /> <Image
<span className="pr-2 pl-1 text-sm text-gray-400">{country_from_code}</span> src={`/images/flags/${from_country_name.toLowerCase()}.png`}
width={26}
height={13}
alt={from_country_name.substring(0, 3)}
/>
<span className="pr-2 pl-1 text-sm text-gray-400">
{from_country_name.substring(0, 3).toUpperCase()}
</span>
<span className="text-base font-semibold"> <span className="text-base font-semibold">
{start_point} / {country_from} {from_city_name} / {from_country_name}
</span> </span>
</div> </div>
<div className="flex flex-col"> <div className="flex flex-col">
<div className="flex items-center gap-4"> <div className="flex items-center gap-4">
<span className="text-base">{moving_type}</span> <span className="text-base">{formatted_transport}</span>
<Image <Image
src={setMovingTypeIcon()} src={setMovingTypeIcon()}
width={15} width={15}
@@ -226,30 +245,37 @@ const SearchCard = ({
/> />
</div> </div>
<div className="my-2 h-[2px] w-[165px] bg-gray-200" /> <div className="my-2 h-[2px] w-[165px] bg-gray-200" />
<div className="text-sm">Дата доставки: {estimated_date.toLocaleDateString()}</div> <div className="text-sm">Дата доставки: {formatted_arrival}</div>
</div> </div>
<div className="-mb-[14px] flex flex-col"> <div className="-mb-[14px] flex flex-col">
{user_request === 'Нужен перевозчик' ? ( {userRequest === 'Нужен перевозчик' ? (
<div className="text-sm text-gray-500">Доставить в:</div> <div className="text-sm text-gray-500">Доставить в:</div>
) : ( ) : (
<div className="text-sm text-gray-500">Прибываю в:</div> <div className="text-sm text-gray-500">Прибываю в:</div>
)} )}
<div className="flex items-center"> <div className="flex items-center">
<Image src={country_to_icon} width={26} height={13} alt={country_to_code} /> <Image
<span className="pr-2 pl-1 text-gray-400">{country_to_code}</span> src={`/images/flags/${to_country_name.toLowerCase()}.png`}
width={26}
height={13}
alt={to_country_name.substring(0, 3)}
/>
<span className="pr-2 pl-1 text-gray-400">
{to_country_name.substring(0, 3).toUpperCase()}
</span>
<span className="text-base font-semibold"> <span className="text-base font-semibold">
{end_point} / {country_to} {to_city_name} / {to_country_name}
</span> </span>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
{user_request === 'Могу перевезти' && ( {userRequest === 'Могу перевезти' && (
<div className="mt-3 ml-7 text-sm text-gray-500"> <div className="mt-3 ml-7 text-sm text-gray-500">
<span className="text-sm font-normal">Прибытие:</span>{' '} <span className="text-sm font-normal">Прибытие:</span>{' '}
<span className="text-sm font-semibold">{day_in?.toLocaleDateString()}</span> <span className="text-sm font-semibold">{formatted_arrival}</span>
</div> </div>
)} )}
</div> </div>

View File

@@ -1,55 +1,7 @@
import avatar from '../../public/images/avatar.png'
import belarusIcon from '../../public/images/belarus.png'
import russiaIcon from '../../public/images/russia.png'
import { CargoType, TransportType } from '../types' import { CargoType, TransportType } from '../types'
const userImg = avatar
const blIcon = belarusIcon
const ruIcon = russiaIcon
export const routes = 12845 export const routes = 12845
export const data = [
{
id: 1123,
username: 'John Doe',
userImg: userImg,
start_point: 'Минск',
country_from: 'Беларусь',
end_point: 'Москва',
country_to: 'Россия',
cargo_type: 'Документы',
user_request: 'Нужен перевозчик',
user_comment: 'Нужно перевезти документы из Минска в Москву',
country_from_icon: blIcon,
country_to_icon: ruIcon,
country_from_code: 'BY',
country_to_code: 'RU',
moving_type: 'Авиатранспорт',
estimated_date: new Date(2025, 4, 15),
},
{
id: 2423,
username: 'John Doe',
userImg: userImg,
start_point: 'Минск',
country_from: 'Беларусь',
end_point: 'Москва',
country_to: 'Россия',
cargo_type: 'Документы',
user_request: 'Могу перевезти',
user_comment: 'Нужно перевезти документы из Минска в Москву',
moving_type: 'Автоперевозка',
estimated_date: new Date(2025, 5, 18),
country_from_icon: blIcon,
country_to_icon: ruIcon,
country_from_code: 'BY',
country_to_code: 'RU',
day_out: new Date(2025, 5, 21),
day_in: new Date(2025, 5, 25),
},
]
export const cargo_types: CargoType[] = ['letter', 'package', 'passenger', 'parcel', 'cargo'] export const cargo_types: CargoType[] = ['letter', 'package', 'passenger', 'parcel', 'cargo']
export const cargo_type_translations: Record<CargoType, string> = { export const cargo_type_translations: Record<CargoType, string> = {

View File

@@ -3,16 +3,17 @@ import Image from 'next/image'
import AddressSelector from '@/components/AddressSelector' import AddressSelector from '@/components/AddressSelector'
import SearchCard from '@/app/(urls)/search/components/SearchCard' import SearchCard from '@/app/(urls)/search/components/SearchCard'
import FAQ from '@/components/FAQ' import FAQ from '@/components/FAQ'
import { data } from '@/app/constants'
import { routes } from '@/app/constants' import { routes } from '@/app/constants'
import Button from '@/components/ui/Button' import Button from '@/components/ui/Button'
import News from '@/components/News' import News from '@/components/News'
import { getFAQs } from '@/lib/main/fetchFAQ' import { getFAQs } from '@/lib/main/fetchFAQ'
import { getNews } from '@/lib/main/fetchNews' import { getNews } from '@/lib/main/fetchNews'
import { getFirstRoutes } from '@/lib/main/fetchFirstRoutes'
export default async function Home() { export default async function Home() {
const faqs = await getFAQs() const faqs = await getFAQs()
const news = await getNews() const news = await getNews()
const latestRoutes = await getFirstRoutes()
return ( return (
<div className="mx-auto flex max-w-[93%] flex-col items-center justify-center"> <div className="mx-auto flex max-w-[93%] flex-col items-center justify-center">
@@ -69,9 +70,11 @@ export default async function Home() {
{/* первые пять серч карточек -- бекенд??? */} {/* первые пять серч карточек -- бекенд??? */}
<div className="mx-auto w-full max-w-[1250px]"> <div className="mx-auto w-full max-w-[1250px]">
<div className="grid w-full grid-cols-1 gap-4"> <div className="grid w-full grid-cols-1 gap-4">
{data.map(card => ( {Array.isArray(latestRoutes) && latestRoutes.length > 0 ? (
<SearchCard key={card.id} {...card} /> latestRoutes.map(card => <SearchCard key={card.id} {...card} />)
))} ) : (
<div className="py-4 text-center text-gray-600">Нет доступных маршрутов</div>
)}
</div> </div>
<div className="flex justify-center py-4"> <div className="flex justify-center py-4">
<Button <Button

View File

@@ -29,23 +29,24 @@ export interface ButtonProps {
export interface SearchCardProps { export interface SearchCardProps {
id: number id: number
username: string username: number
userImg: string | StaticImageData userImg: string
start_point: string owner_type: string
country_from: string from_city_name: string
country_from_icon: string | StaticImageData from_country_name: string
country_from_code: string to_city_name: string
end_point: string to_country_name: string
country_to: string
country_to_icon: string | StaticImageData
country_to_code: string
cargo_type: string cargo_type: string
user_request: string formatted_cargo_type: string
moving_type: string formatted_transport: string
estimated_date: Date type_transport: string
user_comment: string comment: string
day_out?: Date departure_DT: string
day_in?: Date arrival_DT: string
formatted_departure: string
formatted_arrival: string
country_from_icon: string
country_to_icon: string
} }
export interface AccordionProps { export interface AccordionProps {

View File

@@ -0,0 +1,24 @@
import { SearchCardProps } from '@/app/types'
export async function getFirstRoutes(): Promise<SearchCardProps[]> {
const API_URL = process.env.NEXT_PUBLIC_API_URL
try {
const response = await fetch(`${API_URL}/latest-routes/`, {
next: {
revalidate: 86400, // один день
},
})
if (!response.ok) {
console.error('Failed to fetch latest routes:', response.statusText)
return []
}
const routes = (await response.json()) as SearchCardProps[]
return Array.isArray(routes) ? routes : []
} catch (error) {
console.error('Error fetching latest routes:', error)
return []
}
}

View File

@@ -1,7 +1,6 @@
import type { NextConfig } from 'next' import type { NextConfig } from 'next'
const API_URL = const API_URL = process.env.NEXT_PUBLIC_API_URL || 'http://127.0.0.1:8000/api/v1'
process.env.NEXT_PUBLIC_API_URL || 'http://127.0.0.1:8000/api/v1'
const nextConfig: NextConfig = { const nextConfig: NextConfig = {
images: { images: {
@@ -20,6 +19,10 @@ const nextConfig: NextConfig = {
protocol: 'https', protocol: 'https',
hostname: 'tripwb.com', hostname: 'tripwb.com',
}, },
{
protocol: 'https',
hostname: 'i.ibb.co',
},
], ],
}, },
} }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.2 KiB