Compare commits
3 Commits
b545e71243
...
f46942e269
| Author | SHA1 | Date |
|---|---|---|
|
|
f46942e269 | |
|
|
48036d8eb7 | |
|
|
96ef8ffb3c |
|
|
@ -7,7 +7,7 @@ import { i18nManager } from './i18n/manager';
|
|||
// Page components
|
||||
import Home from './pages/home';
|
||||
import History from './pages/history';
|
||||
import FriendsPhoto from './pages/friends-photo';
|
||||
import Create from './pages/create';
|
||||
import Result from './pages/result';
|
||||
|
||||
// Bottom navigation component
|
||||
|
|
@ -20,7 +20,7 @@ function App() {
|
|||
const location = useLocation();
|
||||
|
||||
// Pages that don't need to show bottom navigation
|
||||
const hideBottomNavPages = ['/friends-photo', '/result'];
|
||||
const hideBottomNavPages = ['/create', '/result'];
|
||||
|
||||
useEffect(() => {
|
||||
const initApp = async () => {
|
||||
|
|
@ -58,11 +58,11 @@ function App() {
|
|||
<Route path="/" element={<Navigate to="/home" replace />} />
|
||||
<Route path="/home" element={<Home />} />
|
||||
<Route path="/history" element={<History />} />
|
||||
<Route path="/friends-photo" element={<FriendsPhoto />} />
|
||||
<Route path="/create/:templateCode" element={<Create />} />
|
||||
<Route path="/result" element={<Result />} />
|
||||
</Routes>
|
||||
</div>
|
||||
{!hideBottomNavPages.includes(location.pathname) && <BottomNavigation />}
|
||||
{!hideBottomNavPages.some(path => location.pathname.startsWith(path)) && <BottomNavigation />}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,23 +1,25 @@
|
|||
import { authService } from '@/services/auth';
|
||||
import { useState } from 'react';
|
||||
import { bowongAI } from '../../../../sdk/bowongAISDK';
|
||||
import { useI18n } from '../../../../hooks/useI18n';
|
||||
import { bowongAI } from '../../../../sdk/bowongAISDK';
|
||||
import './index.css';
|
||||
|
||||
interface UploadCardProps {
|
||||
imageUrl: string;
|
||||
title: string;
|
||||
onLogin: () => void;
|
||||
onUploadSuccess: (imageUrl: string) => void;
|
||||
className?: string;
|
||||
disabled?: boolean;
|
||||
}
|
||||
|
||||
export default function UploadCard({ imageUrl, title, onUploadSuccess, className = '', disabled = false }: UploadCardProps) {
|
||||
export default function UploadCard({ imageUrl, title, onLogin, onUploadSuccess, className = '', disabled = false }: UploadCardProps) {
|
||||
const [uploading, setUploading] = useState<boolean>(false);
|
||||
const { t } = useI18n();
|
||||
|
||||
const handleUpload = async () => {
|
||||
if (disabled) {
|
||||
alert('Please login first');
|
||||
onLogin();
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
import { Template } from '@/sdk/sdk-server';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useSearchParams } from 'react-router-dom';
|
||||
import { useParams } from 'react-router-dom';
|
||||
import { useServerSdk } from '../../hooks/index';
|
||||
import { useI18n } from '../../hooks/useI18n';
|
||||
import { i18nManager } from '../../i18n/manager';
|
||||
|
|
@ -11,12 +11,13 @@ import UploadCard from './components/UploadCard';
|
|||
import './index.css';
|
||||
import { authService } from '@/services';
|
||||
|
||||
export default function FriendsPhoto() {
|
||||
const [searchParams] = useSearchParams();
|
||||
export default function Create() {
|
||||
const { templateCode } = useParams();
|
||||
const [isLoggedIn, setIsLoggedIn] = useState<boolean>(false);
|
||||
const templateCode = searchParams.get('templateCode');
|
||||
const [template, setTemplate] = useState<Template | null>(null);
|
||||
|
||||
const [loginRedirecting, setLoginRedirecting] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
const checkLogin = async () => {
|
||||
// Check login status, including OAuth 2.0 callback handling
|
||||
|
|
@ -50,16 +51,17 @@ export default function FriendsPhoto() {
|
|||
// 提交处理
|
||||
const handleSubmit = async () => {
|
||||
if (!isLoggedIn) {
|
||||
setLoginRedirecting(true);
|
||||
setLoading(true);
|
||||
authService.login('/friends-photo');
|
||||
await authService.login(window.location.pathname);
|
||||
return;
|
||||
}
|
||||
if (!templateCode) {
|
||||
alert(t('friendsPhoto.templateCodeNotSet'));
|
||||
alert('Template code not set');
|
||||
return;
|
||||
}
|
||||
if (!image1 || !image2) {
|
||||
alert(t('friendsPhoto.uploadTwoImages'));
|
||||
alert('Upload two images');
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -87,36 +89,52 @@ export default function FriendsPhoto() {
|
|||
// navigate(`/result?taskId=${taskId}&templateCode=${templateCode}`);
|
||||
} catch (error) {
|
||||
console.error('提交失败:', error);
|
||||
alert(t('friendsPhoto.waitForTaskCompletion'));
|
||||
alert('Wait for task completion');
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
// // If not authenticated, show login prompt
|
||||
// if (isLoggedIn === false) {
|
||||
// return (
|
||||
// <div className="app-loading">
|
||||
// <div className="loading-container">
|
||||
// <div className="loading-spinner"></div>
|
||||
// <div className="loading-text">Redirecting to login page...</div>
|
||||
// </div>
|
||||
// </div>
|
||||
// );
|
||||
// }
|
||||
|
||||
if (loginRedirecting) {
|
||||
return (
|
||||
<div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center', height: '100vh' }}>
|
||||
<div>Redirecting to login...</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="friends-photo">
|
||||
{/* 上传区域 */}
|
||||
<div className="upload-section">
|
||||
<UploadCard disabled={!isLoggedIn} imageUrl={image1} title={t('friendsPhoto.selectYourPhoto')} onUploadSuccess={setImage1} />
|
||||
<UploadCard disabled={!isLoggedIn} imageUrl={image2} title={t('friendsPhoto.selectFriendPhoto')} onUploadSuccess={setImage2} />
|
||||
<UploadCard
|
||||
disabled={!isLoggedIn}
|
||||
imageUrl={image1}
|
||||
title={t('friendsPhoto.selectYourPhoto')}
|
||||
onUploadSuccess={setImage1}
|
||||
onLogin={() => {
|
||||
setLoginRedirecting(true);
|
||||
authService.login(window.location.pathname);
|
||||
}}
|
||||
/>
|
||||
<UploadCard
|
||||
disabled={!isLoggedIn}
|
||||
imageUrl={image2}
|
||||
title={t('friendsPhoto.selectFriendPhoto')}
|
||||
onUploadSuccess={setImage2}
|
||||
onLogin={() => {
|
||||
setLoginRedirecting(true);
|
||||
authService.login(window.location.pathname);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* 固定底部按钮 */}
|
||||
<div className="submit-section">
|
||||
<button
|
||||
className={`submit-button ${!image1 || !image2 || loading ? 'disabled' : ''}`}
|
||||
className={`submit-button ${(!image1 || !image2 || loading) && isLoggedIn ? 'disabled' : ''}`}
|
||||
disabled={(!image1 || !image2 || loading) && isLoggedIn}
|
||||
onClick={handleSubmit}
|
||||
>
|
||||
|
|
@ -15,6 +15,8 @@ export default function History() {
|
|||
const [isLoggedIn, setIsLoggedIn] = useState<boolean | null>(null);
|
||||
const serverSdk = useServerSdk();
|
||||
|
||||
const [loginRedirecting, setLoginRedirecting] = useState(false);
|
||||
|
||||
const checkLoginStatus = async () => {
|
||||
try {
|
||||
const loginStatus = await authService.checkLogin();
|
||||
|
|
@ -105,12 +107,21 @@ export default function History() {
|
|||
|
||||
const handleLogin = async () => {
|
||||
try {
|
||||
setLoginRedirecting(true);
|
||||
await authService.login('/history');
|
||||
} catch (error) {
|
||||
console.error('Login failed:', error);
|
||||
}
|
||||
};
|
||||
|
||||
if (loginRedirecting) {
|
||||
return (
|
||||
<div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center', height: '100vh' }}>
|
||||
<div>Redirecting to login...</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="history">
|
||||
{/* Settings area */}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
.home {
|
||||
/* background: linear-gradient(180deg, #f8f9fa 0%, #e9ecef 100%); */
|
||||
background: #f5f6f8;
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ export default function Home() {
|
|||
}, [dispatch]);
|
||||
|
||||
const handleTemplateClick = async (template: Template) => {
|
||||
navigate(`/friends-photo?templateCode=${template.code}`);
|
||||
navigate(`/create/${template.code}`);
|
||||
return;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -46,13 +46,14 @@ export class AuthService {
|
|||
/**
|
||||
* 跳转到Google OAuth登录页面
|
||||
*/
|
||||
async login(redirectUrl?: string): Promise<void> {
|
||||
async login(redirectPath?: string): Promise<void> {
|
||||
const { hostname, protocol, port } = window.location;
|
||||
let baseUrl = `${protocol}//${hostname}`;
|
||||
if (hostname === 'localhost') {
|
||||
baseUrl = `${protocol}//${hostname}:${port}`;
|
||||
}
|
||||
window.location.href = `https://mixvideo-workflow.bowong.cc/auth/google/authorize?redirect_url=${baseUrl}${redirectUrl || ''}`;
|
||||
const redirectUrl = `https://mixvideo-workflow.bowong.cc/auth/google/authorize?redirect_url=${baseUrl}${redirectPath || ''}`;
|
||||
window.location.href = redirectUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
Loading…
Reference in New Issue