fix: phần code build android

This commit is contained in:
2026-06-27 17:46:23 +07:00
parent 813b41933b
commit 796487ef76
10 changed files with 189 additions and 252 deletions
+28 -28
View File
@@ -1,27 +1,27 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover" />
<link rel="icon" type="image/x-icon" href="/favicon.ico" />
<script src="https://accounts.google.com/gsi/client" async defer></script>
<title>Travel Planner</title>
<!-- Open Graph Meta Tags for Social Media Sharing -->
<meta property="og:type" content="website" />
<meta property="og:url" content="https://yotrip.labz.io.vn" />
<meta property="og:title" content="Travel Planner - Lên kế hoạch chuyến đi của bạn" />
<meta property="og:description" content="Khám phá những hành trình tuyệt vời và chia sẻ khoảnh khắc đẹp với cộng đồng du lịch." />
<meta property="og:image" content="https://yotrip.labz.io.vn/background.avif" />
<meta property="og:image:width" content="1200" />
<meta property="og:image:height" content="630" />
<!-- Twitter Card Meta Tags -->
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:title" content="Travel Planner - Lên kế hoạch chuyến đi của bạn" />
<meta name="twitter:description" content="Khám phá những hành trình tuyệt vời và chia sẻ khoảnh khắc đẹp với cộng đồng du lịch." />
<meta name="twitter:image" content="https://yotrip.labz.io.vn/background.avif" />
<script type="module" crossorigin src="/assets/index-CRdl2V_E.js"></script>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover" />
<link rel="icon" type="image/x-icon" href="/favicon.ico" />
<script src="https://accounts.google.com/gsi/client" async defer></script>
<title>Travel Planner</title>
<!-- Open Graph Meta Tags for Social Media Sharing -->
<meta property="og:type" content="website" />
<meta property="og:url" content="https://yotrip.labz.io.vn" />
<meta property="og:title" content="Travel Planner - Lên kế hoạch chuyến đi của bạn" />
<meta property="og:description" content="Khám phá những hành trình tuyệt vời và chia sẻ khoảnh khắc đẹp với cộng đồng du lịch." />
<meta property="og:image" content="https://yotrip.labz.io.vn/background.avif" />
<meta property="og:image:width" content="1200" />
<meta property="og:image:height" content="630" />
<!-- Twitter Card Meta Tags -->
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:title" content="Travel Planner - Lên kế hoạch chuyến đi của bạn" />
<meta name="twitter:description" content="Khám phá những hành trình tuyệt vời và chia sẻ khoảnh khắc đẹp với cộng đồng du lịch." />
<meta name="twitter:image" content="https://yotrip.labz.io.vn/background.avif" />
<script type="module" crossorigin src="/assets/index--uaaEHqB.js"></script>
<link rel="modulepreload" crossorigin href="/assets/rolldown-runtime-Cyuzqnbw.js">
<link rel="modulepreload" crossorigin href="/assets/vendor-others-VIU5qAPG.js">
<link rel="modulepreload" crossorigin href="/assets/vendor-editor-DOXkNaRS.js">
@@ -31,8 +31,8 @@
<link rel="stylesheet" crossorigin href="/assets/vendor-maps-CcXJxNtP.css">
<link rel="stylesheet" crossorigin href="/assets/vendor-react-CuSj0z1j.css">
<link rel="stylesheet" crossorigin href="/assets/index-BsXBn1-b.css">
</head>
<body>
<div id="root"></div>
</body>
</head>
<body>
<div id="root"></div>
</body>
+2 -1
View File
@@ -2,6 +2,7 @@ import React, { useState, useEffect } from 'react';
import { X, Send, MessageSquare, User, Loader2, Trash2 } from 'lucide-react';
import { io } from 'socket.io-client';
import { Capacitor } from '@capacitor/core';
import { BACKEND_URL } from '@/utils/backendEndpoint';
import { useTourStore } from '@/store/useTourStore';
import { ConfirmModal } from './ConfirmModal';
@@ -71,7 +72,7 @@ export const CommentModal: React.FC<CommentModalProps> = ({ isOpen, onClose, loc
// Lắng nghe bình luận mới qua Proxy (không cần hardcode URL)
const socket = Capacitor.isNativePlatform()
? io(import.meta.env.VITE_BACKEND_URL || 'https://yotrip.labz.io.vn')
? io(BACKEND_URL)
: io();
socket.emit('joinTour', 'global'); // Hoặc logic join cụ thể
+2 -1
View File
@@ -2,6 +2,7 @@ import React, { useState, useEffect, useRef } from 'react';
import { X, Send, MessageSquare, User, Loader2, Calendar, MapPin, Download, Edit, Heart, Trash2 } from 'lucide-react';
import { io } from 'socket.io-client';
import { Capacitor } from '@capacitor/core';
import { BACKEND_URL } from '@/utils/backendEndpoint';
import { CoordinateSelectModal } from './CoordinateSelectModal';
import { useTranslation } from '../hooks/useTranslation';
import { useConfirm } from '../hooks/useConfirm';
@@ -248,7 +249,7 @@ export const PublicPhotoModal: React.FC<PublicPhotoModalProps> = ({
fetchComments();
const socket = Capacitor.isNativePlatform()
? io(import.meta.env.VITE_BACKEND_URL || 'https://yotrip.labz.io.vn')
? io(BACKEND_URL)
: io();
socket.emit('joinPhoto', photo.id);
+2 -1
View File
@@ -2,6 +2,7 @@ import React, { useState, useEffect, useRef } from 'react';
import { io, Socket } from 'socket.io-client';
import { Capacitor } from '@capacitor/core';
import { Camera, CameraResultType, CameraSource } from '@capacitor/camera';
import { BACKEND_URL } from '@/utils/backendEndpoint';
import { Send, MessageSquare, Loader2, Image as ImageIcon, MapPin, Download, X } from 'lucide-react';
import { useNotification } from '@/hooks/useNotification';
@@ -182,7 +183,7 @@ export const TourChat: React.FC<TourChatProps> = ({ tourId, embedded = false })
// Connect to socket and listen for tour messages
useEffect(() => {
const socket = Capacitor.isNativePlatform()
? io(import.meta.env.VITE_BACKEND_URL || 'https://yotrip.labz.io.vn')
? io(BACKEND_URL)
: io();
socketRef.current = socket;
+36 -18
View File
@@ -1,4 +1,10 @@
import React, { useEffect, useState, useRef } from 'react';
<<<<<<< Updated upstream
=======
import { io, Socket } from 'socket.io-client';
import { Capacitor } from '@capacitor/core';
import { BACKEND_URL } from '@/utils/backendEndpoint';
>>>>>>> Stashed changes
import {
Compass,
Users,
@@ -97,6 +103,7 @@ export const MemberDashboard: React.FC<MemberDashboardProps> = ({
const [chatMessages, setChatMessages] = useState<any[]>([]);
const [newMessage, setNewMessage] = useState('');
const messagesEndRef = useRef<HTMLDivElement>(null);
const socketRef = useRef<Socket | null>(null);
useEffect(() => {
@@ -530,14 +537,32 @@ export const MemberDashboard: React.FC<MemberDashboardProps> = ({
muteNotificationsRef.current = muteNotifications;
});
// Socket connection for realtime messaging - changed to listen to global socket events
// Socket connection for realtime messaging
useEffect(() => {
if (!user?.id) return;
<<<<<<< Updated upstream
const handleMessageReceived = (e: Event) => {
const message = (e as CustomEvent).detail;
// If we are actively chatting with the sender of this message
if (activeChatUser && (message.senderId === activeChatUser.id || message.receiverId === activeChatUser.id)) {
=======
// Connect to WebSocket: absolute URL on native, relative (Vite proxy) on web
const socket = Capacitor.isNativePlatform()
? io(BACKEND_URL)
: io();
socketRef.current = socket;
socket.on('connect', () => {
console.log('[WS] MemberDashboard connected:', socket.id);
socket.emit('joinUser', user.id);
});
const handleMessageReceived = (message: any) => {
// Check against window-global activeChatUserId so stale closure doesn't block updates
const activeChatUserId = (window as any).activeChatUserId;
if (activeChatUserId && (message.senderId === activeChatUserId || message.receiverId === activeChatUserId)) {
>>>>>>> Stashed changes
setChatMessages(prev => [...prev, message]);
} else {
// Add to unread states
@@ -548,31 +573,24 @@ export const MemberDashboard: React.FC<MemberDashboardProps> = ({
}
};
const handleConnectionAccepted = () => {
socket.on('messageReceived', handleMessageReceived);
socket.on('connectionAccepted', () => {
fetchConnectionsRef.current();
};
});
const handleTourMessageNotification = (e: Event) => {
const data = (e as CustomEvent).detail;
socket.on('tourMessageNotification', (data: any) => {
setUnreadTourChats(prev => prev.includes(data.tourId) ? prev : [...prev, data.tourId]);
};
});
const handleJoinRequestAccepted = () => {
socket.on('joinRequestAccepted', () => {
fetchPublicToursRef.current();
};
window.addEventListener('app:messageReceived', handleMessageReceived);
window.addEventListener('app:connectionAccepted', handleConnectionAccepted);
window.addEventListener('app:tourMessageNotification', handleTourMessageNotification);
window.addEventListener('app:joinRequestAccepted', handleJoinRequestAccepted);
});
return () => {
window.removeEventListener('app:messageReceived', handleMessageReceived);
window.removeEventListener('app:connectionAccepted', handleConnectionAccepted);
window.removeEventListener('app:tourMessageNotification', handleTourMessageNotification);
window.removeEventListener('app:joinRequestAccepted', handleJoinRequestAccepted);
socket.disconnect();
};
}, [user?.id, activeChatUser]);
}, [user?.id]);
// Autoscroll chat to bottom
useEffect(() => {
+2 -1
View File
@@ -1,6 +1,7 @@
import React, { useState, useEffect, useMemo, useRef } from 'react';
import { io } from 'socket.io-client';
import { Capacitor } from '@capacitor/core';
import { BACKEND_URL } from '@/utils/backendEndpoint';
import { jsPDF } from 'jspdf';
import autoTable from 'jspdf-autotable';
import { robotoBase64, robotoBoldBase64 } from '../utils/pdfFont';
@@ -1573,7 +1574,7 @@ export const TourDetailPage = ({
if (!currentTour) return;
const socket = Capacitor.isNativePlatform()
? io(import.meta.env.VITE_BACKEND_URL || 'https://yotrip.labz.io.vn')
? io(BACKEND_URL)
: io(); // Kết nối qua Proxy của Vite (cùng origin)
socket.on('connect', () => {
+46
View File
@@ -0,0 +1,46 @@
/**
* Smart runtime backend URL resolver.
*
* Eliminates the need to manually update `.env` files when switching between:
* - Docker/Linux Production Web Server uses window.location.origin
* - Android APK (Capacitor WebView) forces absolute production domain
*
* Priority order:
* 1. Explicit VITE_BACKEND_URL env variable (if set at build time)
* 2. Android/Capacitor app detection https://yotrip.labz.io.vn
* 3. Production web server window.location.origin
*/
const PRODUCTION_DOMAIN = 'https://yotrip.labz.io.vn';
const resolveBackendEndpoint = (): string => {
// 1. Honour explicit build-time env override first
const envUrl = import.meta.env.VITE_BACKEND_URL as string | undefined;
if (envUrl) {
return envUrl;
}
const origin = window.location.origin;
const userAgent = navigator.userAgent.toLowerCase();
// 2. Detect Android APK / Capacitor WebView environment
// These shells run on local/file:// origins, not the production domain.
const isAndroidApp =
origin.startsWith('http://localhost') ||
origin.startsWith('capacitor://') ||
origin.startsWith('file://') ||
(userAgent.includes('android') && !origin.includes('yotrip.labz.io.vn'));
if (isAndroidApp) {
console.log('[Backend] 📱 Android/Capacitor environment detected — using production domain.');
return PRODUCTION_DOMAIN;
}
// 3. Web production server: the origin IS the backend (same Docker host)
return origin;
};
/** Resolved backend base URL for the current runtime environment. */
export const BACKEND_URL: string = resolveBackendEndpoint();
console.log(`[Backend] 🌐 Active endpoint: ${BACKEND_URL}`);
+2 -1
View File
@@ -1,6 +1,7 @@
import { Capacitor } from '@capacitor/core';
import { GoogleAuth } from '@codetrix-studio/capacitor-google-auth';
import { LocalNotifications } from '@capacitor/local-notifications';
import { BACKEND_URL } from './backendEndpoint';
function rewriteUrls(obj: any, backendUrl: string): any {
if (obj === null || obj === undefined) return obj;
@@ -47,7 +48,7 @@ if (Capacitor.isNativePlatform()) {
console.error('[LocalNotifications] Failed to request permissions:', e);
}
const backendUrl = import.meta.env.VITE_BACKEND_URL || 'https://yotrip.labz.io.vn';
const backendUrl = BACKEND_URL;
const originalFetch = window.fetch;
window.fetch = async (input: RequestInfo | URL, init?: RequestInit): Promise<Response> => {