Initial commit: AI-powered numerology analysis application

This commit is contained in:
patdelphi
2025-08-18 09:13:18 +08:00
commit db343a096e
59 changed files with 17320 additions and 0 deletions

221
src/pages/ProfilePage.tsx Normal file
View File

@@ -0,0 +1,221 @@
import React, { useState, useEffect } from 'react';
import { useAuth } from '../contexts/AuthContext';
import { supabase } from '../lib/supabase';
import { Button } from '../components/ui/Button';
import { Input } from '../components/ui/Input';
import { Select } from '../components/ui/Select';
import { Card, CardContent, CardHeader, CardTitle } from '../components/ui/Card';
import { toast } from 'sonner';
import { User, Calendar, MapPin, Save } from 'lucide-react';
import { UserProfile } from '../types';
const ProfilePage: React.FC = () => {
const { user } = useAuth();
const [loading, setLoading] = useState(false);
const [profile, setProfile] = useState<UserProfile | null>(null);
const [formData, setFormData] = useState({
full_name: '',
birth_date: '',
birth_time: '',
birth_location: '',
gender: 'male' as 'male' | 'female',
username: ''
});
useEffect(() => {
loadProfile();
}, [user]);
const loadProfile = async () => {
if (!user) return;
try {
const { data, error } = await supabase
.from('user_profiles')
.select('*')
.eq('user_id', user.id)
.maybeSingle();
if (error && error.code !== 'PGRST116') {
throw error;
}
if (data) {
setProfile(data);
setFormData({
full_name: data.full_name || '',
birth_date: data.birth_date || '',
birth_time: data.birth_time || '',
birth_location: data.birth_location || '',
gender: data.gender || 'male',
username: data.username || ''
});
}
} catch (error: any) {
console.error('加载档案失败:', error);
toast.error('加载档案失败');
}
};
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
if (!user) return;
setLoading(true);
try {
const profileData = {
user_id: user.id,
...formData,
updated_at: new Date().toISOString()
};
let result;
if (profile) {
// 更新现有档案
result = await supabase
.from('user_profiles')
.update(profileData)
.eq('user_id', user.id)
.select()
.maybeSingle();
} else {
// 创建新档案
result = await supabase
.from('user_profiles')
.insert([{
...profileData,
created_at: new Date().toISOString()
}])
.select()
.maybeSingle();
}
if (result.error) {
throw result.error;
}
setProfile(result.data);
toast.success('档案保存成功!');
} catch (error: any) {
console.error('保存档案失败:', error);
toast.error('保存档案失败:' + error.message);
} finally {
setLoading(false);
}
};
const handleInputChange = (field: string, value: string) => {
setFormData(prev => ({ ...prev, [field]: value }));
};
return (
<div className="max-w-2xl mx-auto">
<Card>
<CardHeader>
<div className="flex items-center space-x-3">
<div className="w-12 h-12 bg-purple-100 rounded-full flex items-center justify-center">
<User className="h-6 w-6 text-purple-600" />
</div>
<div>
<CardTitle></CardTitle>
<p className="text-gray-600"></p>
</div>
</div>
</CardHeader>
<CardContent>
<form onSubmit={handleSubmit} className="space-y-6">
<div className="grid md:grid-cols-2 gap-4">
<Input
label="姓名 *"
value={formData.full_name}
onChange={(e) => handleInputChange('full_name', e.target.value)}
required
placeholder="请输入您的真实姓名"
/>
<Input
label="用户名"
value={formData.username}
onChange={(e) => handleInputChange('username', e.target.value)}
placeholder="请输入用户名(可选)"
/>
</div>
<div className="grid md:grid-cols-2 gap-4">
<div className="relative">
<Input
type="date"
label="出生日期 *"
value={formData.birth_date}
onChange={(e) => handleInputChange('birth_date', e.target.value)}
required
/>
<Calendar className="absolute right-3 top-8 h-4 w-4 text-gray-400 pointer-events-none" />
</div>
<Input
type="time"
label="出生时间"
value={formData.birth_time}
onChange={(e) => handleInputChange('birth_time', e.target.value)}
placeholder="选填,但强烈建议填写"
/>
</div>
<div className="grid md:grid-cols-2 gap-4">
<Select
label="性别 *"
value={formData.gender}
onChange={(e) => handleInputChange('gender', e.target.value)}
options={[
{ value: 'male', label: '男性' },
{ value: 'female', label: '女性' }
]}
required
/>
<div className="relative">
<Input
label="出生地点"
value={formData.birth_location}
onChange={(e) => handleInputChange('birth_location', e.target.value)}
placeholder="如:北京市朝阳区"
/>
<MapPin className="absolute right-3 top-8 h-4 w-4 text-gray-400 pointer-events-none" />
</div>
</div>
<div className="bg-blue-50 p-4 rounded-lg">
<h4 className="font-medium text-blue-800 mb-2"></h4>
<ul className="text-sm text-blue-700 space-y-1">
<li> </li>
<li> </li>
<li> </li>
</ul>
</div>
<Button
type="submit"
className="w-full"
disabled={loading}
>
<Save className="mr-2 h-4 w-4" />
{loading ? '保存中...' : '保存档案'}
</Button>
</form>
{profile && (
<div className="mt-6 pt-6 border-t border-gray-200">
<p className="text-sm text-gray-500">
{new Date(profile.updated_at).toLocaleString('zh-CN')}
</p>
</div>
)}
</CardContent>
</Card>
</div>
);
};
export default ProfilePage;