import React, { useState, useEffect, useMemo, useRef } from 'react';
import {
Truck, X, Check, Phone, ChevronRight, ChevronLeft, Loader2,
Monitor, Wind, Tv, Zap, Layout, Archive, Bike, Laptop, Music,
Sofa, Bed, Search, Calendar, History, AlertCircle
} from 'lucide-react';
import { initializeApp } from 'firebase/app';
import {
getFirestore, collection, addDoc, query, getDocs, where
} from 'firebase/firestore';
import { getAuth, signInAnonymously, onAuthStateChanged, signInWithCustomToken } from 'firebase/auth';
// --- Configuration & Constants ---
const firebaseConfig = JSON.parse(__firebase_config);
const app = initializeApp(firebaseConfig);
const db = getFirestore(app);
const auth = getAuth(app);
const appId = typeof __app_id !== 'undefined' ? __app_id : 'kamitsudo-app';
const CITIES = ['下関市', '宇部市', '山陽小野田市', '美祢市', '長門市'];
const TIME_SLOTS = ['10:00~12:00', '12:00~14:00', '14:00~16:00', '16:00~18:00'];
const ITEM_CATEGORIES = [
{
name: '主要家電',
items: [
{ id: 'ref_l', label: '冷蔵庫(大型)', icon: },
{ id: 'ref_s', label: '冷蔵庫(小型)', icon: },
{ id: 'wm', label: '洗濯機', icon: },
{ id: 'tv', label: 'テレビ', icon: },
{ id: 'ac', label: 'エアコン', icon: },
]
},
{
name: '家具',
items: [
{ id: 'table', label: 'テーブル', icon: },
{ id: 'sofa', label: 'ソファー', icon: },
{ id: 'bed', label: 'ベッドフレーム', icon: },
{ id: 'cabinet', label: '棚・キャビネット', icon: },
]
},
{
name: 'その他',
items: [
{ id: 'bicycle', label: '自転車', icon: },
{ id: 'pc', label: 'パソコン', icon: },
{ id: 'instrument', label: '楽器', icon: },
]
}
];
// --- Utilities ---
const formatDate = (date) => {
return `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}-${String(date.getDate()).padStart(2, '0')}`;
};
const getDaysInMonth = (year, month) => new Date(year, month + 1, 0).getDate();
// --- Main App Component ---
export default function App() {
const [user, setUser] = useState(null);
const [activeView, setActiveView] = useState('booking');
const [loading, setLoading] = useState(true);
useEffect(() => {
const initAuth = async () => {
try {
if (typeof __initial_auth_token !== 'undefined' && __initial_auth_token) {
await signInWithCustomToken(auth, __initial_auth_token);
} else {
await signInAnonymously(auth);
}
} catch (err) {
console.error("Auth error:", err);
} finally {
setLoading(false);
}
};
initAuth();
const unsubscribe = onAuthStateChanged(auth, setUser);
return () => unsubscribe();
}, []);
if (loading) {
return (
);
}
return (
{activeView === 'booking' ? : }
{/* Mobile Nav */}
);
}
function BookingView({ user }) {
const [step, setStep] = useState(1);
const [items, setItems] = useState({});
const [bookingDate, setBookingDate] = useState(null);
const [bookingTime, setBookingTime] = useState(null);
const [formData, setFormData] = useState({
city: '下関市',
address: '',
phone: '',
name: ''
});
const [submitting, setSubmitting] = useState(false);
const [completedId, setCompletedId] = useState(null);
const totalItems = Object.values(items).reduce((a, b) => a + b, 0);
const handleBooking = async () => {
if (!user) return;
setSubmitting(true);
try {
const bookingData = {
userId: user.uid,
items,
date: formatDate(bookingDate),
time: bookingTime,
...formData,
status: 'pending',
createdAt: new Date().toISOString()
};
const docRef = await addDoc(collection(db, 'artifacts', appId, 'public', 'data', 'bookings'), bookingData);
setCompletedId(docRef.id);
setStep(5);
} catch (err) {
console.error(err);
} finally {
setSubmitting(false);
}
};
if (step === 5) {
return (
ご予約を受け付けました!
担当者より内容確認のお電話を差し上げます。
Reservation ID
{completedId}
);
}
return (
{step === 1 && "買取品目の選択"}
{step === 2 && "訪問日時の選択"}
{step === 3 && "連絡先情報の入力"}
{step === 4 && "ご予約内容の確認"}
Step {step} / 4
{step === 1 && (
{ITEM_CATEGORIES.map(cat => (
{cat.items.map(item => (
{items[item.id] || 0}
))}
))}
)}
{step === 2 && (
{bookingDate && (
希望の時間帯を選択
{TIME_SLOTS.map(slot => (
))}
)}
)}
{step === 3 && (
)}
{step === 4 && (
訪問予定日時
{formatDate(bookingDate)}
{bookingTime}
買取品目リスト
{Object.entries(items).map(([id, qty]) => {
if (qty === 0) return null;
const label = ITEM_CATEGORIES.flatMap(c => c.items).find(i => i.id === id)?.label;
return (
{label} x{qty}
);
})}
ご住所
{formData.city} {formData.address}
※予約後、買取スタッフよりお電話にてご連絡をさせていただきます。品目の状態によっては買取ができない場合もございますので、あらかじめご了承ください。
)}
);
}
function CalendarComponent({ onSelect, selected }) {
const [currentDate, setCurrentDate] = useState(new Date());
const year = currentDate.getFullYear();
const month = currentDate.getMonth();
const firstDay = new Date(year, month, 1).getDay();
const daysInMonth = getDaysInMonth(year, month);
const today = new Date();
today.setHours(0, 0, 0, 0);
const prevMonth = () => setCurrentDate(new Date(year, month - 1, 1));
const nextMonth = () => setCurrentDate(new Date(year, month + 1, 1));
const days = [];
for (let i = 0; i < firstDay; i++) days.push(null);
for (let i = 1; i <= daysInMonth; i++) days.push(new Date(year, month, i));
return (
{year}年 {month + 1}月
{['日', '月', '火', '水', '木', '金', '土'].map((d, i) => (
{d}
))}
{days.map((date, i) => {
if (!date) return
;
const isSelected = selected && date.getTime() === selected.getTime();
const isPast = date < today;
const isSunday = date.getDay() === 0;
return (
);
})}
);
}
function LookupView({ user }) {
const [phone, setPhone] = useState('');
const [bookings, setBookings] = useState([]);
const [searching, setSearching] = useState(false);
const [hasSearched, setHasSearched] = useState(false);
const handleSearch = async () => {
if (!phone || !user) return;
setSearching(true);
try {
const q = query(
collection(db, 'artifacts', appId, 'public', 'data', 'bookings'),
where('phone', '==', phone)
);
const snapshot = await getDocs(q);
const data = snapshot.docs.map(doc => ({ id: doc.id, ...doc.data() }));
setBookings(data);
setHasSearched(true);
} catch (err) {
console.error(err);
} finally {
setSearching(false);
}
};
return (
予約情報の確認
登録した電話番号で予約状況を確認できます。
{hasSearched && (
検索結果: {bookings.length}件
{bookings.length === 0 ? (
) : (
bookings.map(b => (
{b.status === 'pending' ? 'Confirmation Pending' : 'Confirmed'}
{b.date}
{b.time}
{Object.entries(b.items).map(([id, qty]) => {
if (qty === 0) return null;
const label = ITEM_CATEGORIES.flatMap(c => c.items).find(i => i.id === id)?.label;
return (
{label} x{qty}
);
})}
))
)}
)}
);
}