07.03.2026 çalışan rota paylaşımlı
This commit is contained in:
parent
52bee4ac5d
commit
342070c5fa
@ -20,7 +20,7 @@ export const BudgetSelector = memo(({ selectedId, onSelect }: BudgetSelectorProp
|
|||||||
key={option.id}
|
key={option.id}
|
||||||
className={cn(
|
className={cn(
|
||||||
'h-1.5 flex-1 rounded-full transition-all duration-300',
|
'h-1.5 flex-1 rounded-full transition-all duration-300',
|
||||||
i <= selectedIndex ? option.dot : 'bg-gray-100'
|
i <= selectedIndex ? option.bg : 'bg-gray-100'
|
||||||
)}
|
)}
|
||||||
animate={{ scaleX: i <= selectedIndex ? 1 : 0.6 }}
|
animate={{ scaleX: i <= selectedIndex ? 1 : 0.6 }}
|
||||||
transition={{ duration: 0.3, delay: i * 0.05 }}
|
transition={{ duration: 0.3, delay: i * 0.05 }}
|
||||||
@ -46,7 +46,7 @@ export const BudgetSelector = memo(({ selectedId, onSelect }: BudgetSelectorProp
|
|||||||
className={cn(
|
className={cn(
|
||||||
'relative group flex items-center gap-4 px-5 py-4 rounded-2xl border-2 text-left transition-all duration-200 w-full overflow-hidden',
|
'relative group flex items-center gap-4 px-5 py-4 rounded-2xl border-2 text-left transition-all duration-200 w-full overflow-hidden',
|
||||||
isSelected
|
isSelected
|
||||||
? `${option.activeBorder} ${option.activeBg} shadow-md`
|
? `${option.border} ${option.bg} shadow-md`
|
||||||
: 'border-gray-100 bg-gray-50/60 hover:border-gray-200 hover:bg-white hover:shadow-sm'
|
: 'border-gray-100 bg-gray-50/60 hover:border-gray-200 hover:bg-white hover:shadow-sm'
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
@ -57,8 +57,8 @@ export const BudgetSelector = memo(({ selectedId, onSelect }: BudgetSelectorProp
|
|||||||
key={i}
|
key={i}
|
||||||
className={cn(
|
className={cn(
|
||||||
'w-1.5 h-1.5 rounded-full transition-all duration-200',
|
'w-1.5 h-1.5 rounded-full transition-all duration-200',
|
||||||
i < option.tier
|
i < 3
|
||||||
? isSelected ? option.dot : 'bg-gray-300'
|
? isSelected ? option.bg : 'bg-gray-300'
|
||||||
: 'bg-gray-100'
|
: 'bg-gray-100'
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
@ -69,7 +69,7 @@ export const BudgetSelector = memo(({ selectedId, onSelect }: BudgetSelectorProp
|
|||||||
<div className={cn(
|
<div className={cn(
|
||||||
'w-11 h-11 rounded-xl flex items-center justify-center transition-all duration-200 shrink-0',
|
'w-11 h-11 rounded-xl flex items-center justify-center transition-all duration-200 shrink-0',
|
||||||
isSelected
|
isSelected
|
||||||
? `${option.activeBg} ${option.color} border-2 ${option.activeBorder}`
|
? `${option.bg} ${option.text} border-2 ${option.border}`
|
||||||
: 'bg-white text-gray-400 border border-gray-100 shadow-sm'
|
: 'bg-white text-gray-400 border border-gray-100 shadow-sm'
|
||||||
)}>
|
)}>
|
||||||
<Icon className="h-5 w-5" />
|
<Icon className="h-5 w-5" />
|
||||||
@ -79,7 +79,7 @@ export const BudgetSelector = memo(({ selectedId, onSelect }: BudgetSelectorProp
|
|||||||
<div className="flex-1 min-w-0 pr-12">
|
<div className="flex-1 min-w-0 pr-12">
|
||||||
<p className={cn(
|
<p className={cn(
|
||||||
'text-sm font-black uppercase tracking-wider',
|
'text-sm font-black uppercase tracking-wider',
|
||||||
isSelected ? option.color : 'text-gray-700'
|
isSelected ? option.text : 'text-gray-700'
|
||||||
)}>
|
)}>
|
||||||
{option.label}
|
{option.label}
|
||||||
</p>
|
</p>
|
||||||
@ -91,9 +91,9 @@ export const BudgetSelector = memo(({ selectedId, onSelect }: BudgetSelectorProp
|
|||||||
{/* Price range */}
|
{/* Price range */}
|
||||||
<div className={cn(
|
<div className={cn(
|
||||||
'absolute bottom-3 right-4 text-[10px] font-bold tracking-wide transition-colors',
|
'absolute bottom-3 right-4 text-[10px] font-bold tracking-wide transition-colors',
|
||||||
isSelected ? option.color : 'text-gray-300'
|
isSelected ? option.text : 'text-gray-300'
|
||||||
)}>
|
)}>
|
||||||
{option.range}
|
{option.description}
|
||||||
</div>
|
</div>
|
||||||
</motion.button>
|
</motion.button>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -32,7 +32,7 @@ interface PlaceDetail {
|
|||||||
opening_hours?: string[] | null;
|
opening_hours?: string[] | null;
|
||||||
why_visit: string[];
|
why_visit: string[];
|
||||||
tips: string[];
|
tips: string[];
|
||||||
reviews: { author: string; rating: number; text: string; time: string }[];
|
reviews: { author: string; rating: number | undefined; text: string; time: string }[];
|
||||||
}
|
}
|
||||||
|
|
||||||
interface SelectedPOI {
|
interface SelectedPOI {
|
||||||
@ -122,13 +122,13 @@ export function TripMap({ itinerary, activePlaceId, onMarkerClick, onAddPlace }:
|
|||||||
tips.push((poi as any).personal_tip);
|
tips.push((poi as any).personal_tip);
|
||||||
}
|
}
|
||||||
const reviewTips = (place.reviews || [])
|
const reviewTips = (place.reviews || [])
|
||||||
.filter(r => r.rating >= 4 && r.text?.length > 30)
|
.filter(r => (r.rating ?? 0) >= 4 && r.text?.length > 30)
|
||||||
.slice(0, tips.length > 0 ? 1 : 2)
|
.slice(0, tips.length > 0 ? 1 : 2)
|
||||||
.map(r => `"${r.text.slice(0, 120).trim()}…"`);
|
.map(r => `"${r.text.slice(0, 120).trim()}…"`);
|
||||||
tips.push(...reviewTips);
|
tips.push(...reviewTips);
|
||||||
|
|
||||||
// summary: editorial_summary sadece Türkçe ise göster, değilse boş bırak
|
// summary: editorial_summary sadece Türkçe ise göster, değilse boş bırak
|
||||||
const rawSummary = place.editorial_summary?.overview || '';
|
const rawSummary = (place as any).editorial_summary?.overview || '';
|
||||||
const isTurkish = /[çğışöüÇĞİŞÖÜ]/.test(rawSummary) || !/[a-zA-Z]{4,}/.test(rawSummary);
|
const isTurkish = /[çğışöüÇĞİŞÖÜ]/.test(rawSummary) || !/[a-zA-Z]{4,}/.test(rawSummary);
|
||||||
const summary = isTurkish ? rawSummary : '';
|
const summary = isTurkish ? rawSummary : '';
|
||||||
|
|
||||||
@ -569,14 +569,14 @@ export function TripMap({ itinerary, activePlaceId, onMarkerClick, onAddPlace }:
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Çalışma saatleri */}
|
{/* Çalışma saatleri */}
|
||||||
{placeDetail.opening_hours?.length > 0 && (
|
{(placeDetail.opening_hours?.length ?? 0) > 0 && (
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<h4 className="text-[11px] font-black text-gray-900 uppercase tracking-widest flex items-center gap-1.5">
|
<h4 className="text-[11px] font-black text-gray-900 uppercase tracking-widest flex items-center gap-1.5">
|
||||||
<Clock className="h-3.5 w-3.5 text-blue-500" />
|
<Clock className="h-3.5 w-3.5 text-blue-500" />
|
||||||
Çalışma Saatleri
|
Çalışma Saatleri
|
||||||
</h4>
|
</h4>
|
||||||
<div className="space-y-1">
|
<div className="space-y-1">
|
||||||
{placeDetail.opening_hours.map((h, i) => (
|
{(placeDetail.opening_hours ?? []).map((h, i) => (
|
||||||
<p key={i} className="text-[11px] text-gray-500">{h}</p>
|
<p key={i} className="text-[11px] text-gray-500">{h}</p>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
@ -607,7 +607,7 @@ export function TripMap({ itinerary, activePlaceId, onMarkerClick, onAddPlace }:
|
|||||||
<div className="flex items-center gap-0.5">
|
<div className="flex items-center gap-0.5">
|
||||||
{[1,2,3,4,5].map(s => (
|
{[1,2,3,4,5].map(s => (
|
||||||
<Star key={s}
|
<Star key={s}
|
||||||
className={cn('h-3 w-3', s <= review.rating
|
className={cn('h-3 w-3', s <= (review.rating ?? 0)
|
||||||
? 'fill-amber-400 text-amber-400'
|
? 'fill-amber-400 text-amber-400'
|
||||||
: 'text-gray-200 fill-gray-200'
|
: 'text-gray-200 fill-gray-200'
|
||||||
)}
|
)}
|
||||||
|
|||||||
@ -155,7 +155,7 @@ const PlannerPage = () => {
|
|||||||
try {
|
try {
|
||||||
const startDate = format(data.dateRange.from, 'yyyy-MM-dd');
|
const startDate = format(data.dateRange.from, 'yyyy-MM-dd');
|
||||||
const endDate = format(data.dateRange.to, 'yyyy-MM-dd');
|
const endDate = format(data.dateRange.to, 'yyyy-MM-dd');
|
||||||
const result = await retryWithBackoff(
|
const result: any = await retryWithBackoff(
|
||||||
() => withTimeout(
|
() => withTimeout(
|
||||||
api.generateItinerary({
|
api.generateItinerary({
|
||||||
startDate,
|
startDate,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user