import { useState, useEffect, useCallback } from "react"; /* ══════ DATE HELPERS ══════ */ const DAYS_AR = ["الأحد","الاثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"]; const DAYS_S = ["أحد","اثنين","ثلاثاء","أربعاء","خميس","جمعة","سبت"]; const MONTHS_AR = ["يناير","فبراير","مارس","أبريل","مايو","يونيو","يوليو","أغسطس","سبتمبر","أكتوبر","نوفمبر","ديسمبر"]; const HIJRI_M = ["محرم","صفر","ربيع الأول","ربيع الثاني","جمادى الأولى","جمادى الآخرة","رجب","شعبان","رمضان","شوال","ذو القعدة","ذو الحجة"]; function toHijri(d) { let gy=d.getFullYear(), gm=d.getMonth()+1, gd=d.getDate(), y=gy, m=gm; if (m<=2){y--;m+=12;} const A=Math.floor(y/100), B=2-A+Math.floor(A/4); const JD=Math.floor(365.25*(y+4716))+Math.floor(30.6001*(m+1))+gd+B-1524; let l=JD-1948440+10632; const n=Math.floor((l-1)/10631); l=l-10631*n+354; const j=Math.floor((10985-l)/5316)*Math.floor(50*l/17719)+Math.floor(l/5670)*Math.floor(43*l/15238); l=l-Math.floor((30-j)/15)*Math.floor(17719*j/50)-Math.floor(j/16)*Math.floor(15238*j/43)+29; const hm=Math.floor(24*l/709), hd=l-Math.floor(709*hm/24), hy=30*n+j-30; return { y:hy, m:hm-1, d:hd }; } function useClock() { const [now, setNow] = useState(new Date()); useEffect(() => { const t = setInterval(()=>setNow(new Date()), 1000); return ()=>clearInterval(t); }, []); const h=now.getHours(), mn=now.getMinutes(), s=now.getSeconds(); const pad = n => String(n).padStart(2,"0"); const hj = toHijri(now); return { day: DAYS_AR[now.getDay()], gregorian:`${now.getDate()} ${MONTHS_AR[now.getMonth()]} ${now.getFullYear()}م`, hijri: `${hj.d} ${HIJRI_M[hj.m]} ${hj.y}هـ`, time: `${pad(h%12||12)}:${pad(mn)}:${pad(s)} ${h>=12?"م":"ص"}`, }; } /* ══════ LOCATIONS ══════ */ const GRP_ORDER = ["تبوك الساحلية","المدينة الساحلية","جدة وضواحيها","مكة الساحلية","جازان الساحلية","الخليج الشمالي","الجبيل والقطيف","الدمام والخبر"]; const LOCS = [ {id:"haql", name:"حقل", grp:"تبوك الساحلية", reg:"البحر الأحمر", lat:29.28,lng:34.93,emoji:"🏝️",type:"ساحل صخري"}, {id:"sharma", name:"شرما", grp:"تبوك الساحلية", reg:"البحر الأحمر", lat:28.03,lng:35.23,emoji:"🌊",type:"خليج عميق"}, {id:"muwaylih", name:"المويلح", grp:"تبوك الساحلية", reg:"البحر الأحمر", lat:27.68,lng:35.47,emoji:"🏖️",type:"ساحل رملي"}, {id:"duba", name:"ضباء", grp:"تبوك الساحلية", reg:"البحر الأحمر", lat:27.35,lng:35.70,emoji:"⚓", type:"ميناء"}, {id:"wajh", name:"الوجه", grp:"المدينة الساحلية", reg:"البحر الأحمر", lat:26.25,lng:36.47,emoji:"🐡",type:"شعاب مرجانية"}, {id:"umluj", name:"أملج", grp:"المدينة الساحلية", reg:"البحر الأحمر", lat:25.05,lng:37.27,emoji:"🐠",type:"شعاب مرجانية"}, {id:"yanbu", name:"ينبع", grp:"المدينة الساحلية", reg:"البحر الأحمر", lat:24.09,lng:38.05,emoji:"⚓", type:"ساحل صخري"}, {id:"rayis", name:"الرايس", grp:"المدينة الساحلية", reg:"البحر الأحمر", lat:23.52,lng:38.76,emoji:"🏖️",type:"ساحل رملي"}, {id:"rabigh", name:"رابغ", grp:"جدة وضواحيها", reg:"البحر الأحمر", lat:22.80,lng:39.03,emoji:"🌴",type:"ساحل رملي"}, {id:"mastorah", name:"مستورة", grp:"جدة وضواحيها", reg:"البحر الأحمر", lat:22.30,lng:39.07,emoji:"🏖️",type:"شاطئ"}, {id:"thuwal", name:"ثول", grp:"جدة وضواحيها", reg:"البحر الأحمر", lat:22.27,lng:39.08,emoji:"🔬",type:"ساحل صخري"}, {id:"dhabban", name:"ذهبان", grp:"جدة وضواحيها", reg:"البحر الأحمر", lat:21.77,lng:39.11,emoji:"🌅",type:"شاطئ"}, {id:"jeddah", name:"جدة", grp:"جدة وضواحيها", reg:"البحر الأحمر", lat:21.49,lng:39.19,emoji:"🏙️",type:"ميناء"}, {id:"lith", name:"الليث", grp:"مكة الساحلية", reg:"البحر الأحمر", lat:20.15,lng:40.27,emoji:"🌊",type:"ساحل رملي"}, {id:"qunfudhah",name:"القنفذة", grp:"مكة الساحلية", reg:"البحر الأحمر", lat:19.13,lng:41.08,emoji:"🐟",type:"ميناء"}, {id:"qahmah", name:"القحمة", grp:"مكة الساحلية", reg:"البحر الأحمر", lat:18.32,lng:41.54,emoji:"🏖️",type:"ساحل رملي"}, {id:"samta", name:"صامطة الساحل",grp:"جازان الساحلية", reg:"البحر الأحمر", lat:17.46,lng:42.07,emoji:"🌿",type:"ساحل"}, {id:"jizan", name:"جازان", grp:"جازان الساحلية", reg:"البحر الأحمر", lat:16.88,lng:42.55,emoji:"🌴",type:"شعاب مرجانية"}, {id:"farasan", name:"جزر فرسان", grp:"جازان الساحلية", reg:"البحر الأحمر", lat:16.72,lng:41.98,emoji:"🏝️",type:"جزر مرجانية"}, {id:"khafji", name:"الخفجي", grp:"الخليج الشمالي", reg:"الخليج العربي", lat:28.42,lng:48.50,emoji:"🛢️",type:"ساحل رملي"}, {id:"nairiyah", name:"العريق", grp:"الخليج الشمالي", reg:"الخليج العربي", lat:27.82,lng:48.88,emoji:"🌊",type:"ساحل"}, {id:"jubail", name:"الجبيل", grp:"الجبيل والقطيف", reg:"الخليج العربي", lat:27.00,lng:49.66,emoji:"🏭",type:"ميناء"}, {id:"rastanura",name:"رأس تنورة", grp:"الجبيل والقطيف", reg:"الخليج العربي", lat:26.70,lng:50.16,emoji:"🛢️",type:"ميناء"}, {id:"safwa", name:"صفوى", grp:"الجبيل والقطيف", reg:"الخليج العربي", lat:26.67,lng:49.93,emoji:"🌅",type:"ساحل"}, {id:"qatif", name:"القطيف", grp:"الجبيل والقطيف", reg:"الخليج العربي", lat:26.57,lng:50.01,emoji:"🌊",type:"ساحل"}, {id:"saihat", name:"سيهات", grp:"الجبيل والقطيف", reg:"الخليج العربي", lat:26.47,lng:50.04,emoji:"🏖️",type:"ساحل رملي"}, {id:"dammam", name:"الدمام", grp:"الدمام والخبر", reg:"الخليج العربي", lat:26.43,lng:50.10,emoji:"🌅",type:"ساحل رملي"}, {id:"khobar", name:"الخبر", grp:"الدمام والخبر", reg:"الخليج العربي", lat:26.28,lng:50.20,emoji:"🌆",type:"كورنيش"}, {id:"uqair", name:"العقير", grp:"الدمام والخبر", reg:"الخليج العربي", lat:25.64,lng:50.21,emoji:"🏺",type:"ساحل تاريخي"}, ]; /* ══════ WEATHER ══════ */ function rng(seed){ let s=seed; return()=>{ s=(s*1664525+1013904223)&0xffffffff; return(s>>>0)/0xffffffff; }; } const season = m => [12,1,2].includes(m)?"winter":[3,4,5].includes(m)?"spring":[6,7,8].includes(m)?"summer":"fall"; const SEASON = {winter:"❄️ الشتاء",spring:"🌸 الربيع",summer:"☀️ الصيف",fall:"🍂 الخريف"}; const sCol = s => s>=70?"#10b981":s>=40?"#f59e0b":"#ef4444"; const sLbl = s => s>=70?"ممتاز":s>=40?"مقبول":"صعب"; function mkWx(loc, seed, mode) { const r=rng(seed), g=loc.reg==="الخليج العربي", bt=g?27+(loc.lat-25)*.4:29-(loc.lat-17)*.35; return { temp:(bt+r()*6-1).toFixed(1), wtemp:(bt-2+r()*5).toFixed(1), wind:(3+r()*(mode==="boat"?30:24)).toFixed(1), dir:["شمال","شمال شرق","شرق","جنوب شرق","جنوب","جنوب غرب","غرب","شمال غرب"][Math.floor(r()*8)], wave:(0.1+r()*(mode==="boat"?4:2.8)).toFixed(1), vis:(5+r()*20).toFixed(0), hum:(45+r()*45).toFixed(0), tide:r()>.5?"مد":"جزر", pressure:(1005+r()*20).toFixed(0), uv:Math.floor(r()*10)+1, }; } function shoreScore(w){let s=100;const wi=+w.wind,wa=+w.wave,vi=+w.vis;if(wi>22)s-=35;else if(wi>15)s-=18;else if(wi>10)s-=8;if(wa>2)s-=28;else if(wa>1.5)s-=16;else if(wa>1)s-=7;if(vi<6)s-=14;else if(vi<10)s-=5;if(w.tide==="مد")s+=5;return Math.max(10,Math.min(100,Math.round(s)));} function boatScore(w){let s=100;const wi=+w.wind,wa=+w.wave,vi=+w.vis;if(wi>25)s-=45;else if(wi>18)s-=28;else if(wi>12)s-=12;if(wa>2.5)s-=45;else if(wa>2)s-=28;else if(wa>1.5)s-=14;else if(wa>1)s-=6;if(vi<6)s-=20;else if(vi<10)s-=8;if(+w.pressure<1008)s-=8;return Math.max(5,Math.min(100,Math.round(s)));} function mk14(loc, mode) { const today = new Date(); return Array.from({length:14},(_,i)=>{ const d=new Date(today); d.setDate(today.getDate()+i); const seed=loc.id.charCodeAt(0)*7777+(loc.id.charCodeAt(1)||1)*333+i*1234+d.getMonth()*99+(mode==="boat"?5555:0); const wx=mkWx(loc,seed,mode); return {date:d,dayS:DAYS_S[d.getDay()],dayF:DAYS_AR[d.getDay()],dateStr:`${d.getDate()} ${MONTHS_AR[d.getMonth()]}`,isToday:i===0,wx,score:mode==="boat"?boatScore(wx):shoreScore(wx)}; }); } /* ══════ AI ══════ */ async function callAI(prompt) { const r = await fetch("https://api.anthropic.com/v1/messages",{method:"POST",headers:{"content-type":"application/json","anthropic-version":"2023-06-01","anthropic-dangerous-direct-browser-access":"true"},body:JSON.stringify({model:"claude-sonnet-4-20250514",max_tokens:900,messages:[{role:"user",content:prompt}]})}); const d = await r.json(); if(!r.ok) throw new Error(d?.error?.message||`HTTP ${r.status}`); return d.content[0].text; } const mkPrompt = (type,loc,wx,label,sn) => { const b=`الموقع: ${loc.name} — ${loc.reg} (${loc.type}) | ${label} | ${SEASON[sn]}\n🌡️${wx.temp}° | 💧${wx.wtemp}° | 💨${wx.wind}عق(${wx.dir}) | 🌊${wx.wave}م | 👁️${wx.vis}كم | ${wx.tide==="مد"?"🔼مد":"🔽جزر"} | 🔵${wx.pressure}هب | ☀️UV${wx.uv}`; return type==="shore"?`خبير صيد ساحلي. ${b}\nحلّل: 1.**الحكم** 2.**الأمواج والمد** 3.**أفضل نقطة** 4.**الطعم والعمق** 5.**التوقيت والتحذير**. موجز مع رموز.` :type==="boat" ?`خبير صيد بحري. ${b}\nحلّل: 1.**أمان الإبحار** 2.**الأمواج والرياح** 3.**المسافة والعمق** 4.**أفضل تقنية** 5.**تحذيرات السلامة**. موجز مع رموز.` :`خبير صيد. ${b}\nتقرير: 1.**الحكم** 2.**عوامل الطقس** 3.**أفضل أسلوب** 4.**التوقيت** 5.**التحذير**. موجز مع رموز.`; }; const fmtAI = t => t.replace(/\*\*(.*?)\*\*/g,"$1").replace(/\*(.*?)\*/g,"$1"); /* ══════ STYLES ══════ */ const CSS=` @import url('https://fonts.googleapis.com/css2?family=Tajawal:wght@400;700;900&display=swap'); *{box-sizing:border-box;margin:0;padding:0;}body{font-family:Tajawal,sans-serif;} @keyframes fu{from{opacity:0;transform:translateY(6px)}to{opacity:1;transform:translateY(0)}} @keyframes pulse{0%,100%{opacity:.4}50%{opacity:1}} @keyframes spin{to{transform:rotate(360deg)}} @keyframes shimmer{0%{background-position:-200% 0}100%{background-position:200% 0}} .tap{transition:all .18s;cursor:pointer;}.tap:hover{opacity:.8;transform:translateY(-1px);} .ait{white-space:pre-wrap;line-height:1.85;font-size:13px;color:rgba(220,240,255,.85);} .ait strong{color:#38bdf8;font-weight:800;} .sh{background:linear-gradient(90deg,rgba(56,189,248,.05) 25%,rgba(56,189,248,.18) 50%,rgba(56,189,248,.05) 75%);background-size:200% 100%;animation:shimmer 1.4s infinite;} input::placeholder{color:rgba(148,210,255,.3);} button,input{font-family:Tajawal,sans-serif;} ::-webkit-scrollbar{width:4px;} ::-webkit-scrollbar-track{background:transparent;} ::-webkit-scrollbar-thumb{background:rgba(56,189,248,.3);border-radius:2px;} `; const WRAP={width:"100%",maxWidth:430,minHeight:"100vh",margin:"0 auto",background:"linear-gradient(160deg,#020e1f,#061424)",fontFamily:"Tajawal,sans-serif",direction:"rtl",color:"#e8f4ff"}; const HDR=96; /* ══════ HAWAT LOGO SVG ══════ */ function HawatLogo({ size = 44 }) { return ( {/* outer circle */} {/* radar arcs top-right */} {/* fish body */} {/* tail */} {/* dorsal fin */} {/* ventral fin */} {/* body stripes */} {/* eye */} {/* location pin on fish */} {/* waves */} {/* text Hawat */} Hawat ); } /* ══════ HEADER ══════ */ function Header({ sel }) { const clk = useClock(); const rc = sel ? (sel.reg==="البحر الأحمر"?"#f87171":"#38bdf8") : "#38bdf8"; return (
{/* Row 1 */}
رادار الحوات
{sel && (
{sel.emoji} {sel.name}
)}
{clk.time}
{/* Row 2 — dates */}
📅 {clk.day} · {clk.gregorian} {clk.hijri}
{/* Row 3 — location */}
{sel ? ( <> 📍 {sel.grp} · {sel.reg} {sel.type} ) : ( <> 📍 اختر موقعاً من الصفحة الرئيسية )}
); } /* ══════ NAV BAR ══════ */ function Nav({ scr, setScr, sel }) { const tabs = [{i:"🏠",l:"الرئيسية",s:"home"},{i:"🏖️",l:"الشاطئ",s:"shore"},{i:"⛵",l:"القارب",s:"boat"},{i:"🗺️",l:"الخريطة",s:"map"},{i:"🎣",l:"النتائج",s:"res"}]; return (
{tabs.map(t => { const off = t.s!=="home" && !sel; return ( ); })}
); } /* ══════ SECRET SPOTS ══════ */ function SecretSpots() { const [spots, setSpots] = useState([]); const [adding, setAdding] = useState(false); const [name, setName] = useState(""); const [locating, setLocating] = useState(false); const [coords, setCoords] = useState(null); const [locErr, setLocErr] = useState(""); const [delId, setDelId] = useState(null); const [loaded, setLoaded] = useState(false); // load spots on mount useEffect(() => { async function load() { try { const res = await window.storage.get("hawat_spots"); if (res?.value) setSpots(JSON.parse(res.value)); } catch(_) {} setLoaded(true); } load(); }, []); async function save(updated) { setSpots(updated); try { await window.storage.set("hawat_spots", JSON.stringify(updated)); } catch(_) {} } function getLocation() { setLocating(true); setLocErr(""); setCoords(null); if (!navigator.geolocation) { setLocErr("المتصفح لا يدعم تحديد الموقع"); setLocating(false); return; } navigator.geolocation.getCurrentPosition( pos => { setCoords({ lat: pos.coords.latitude, lng: pos.coords.longitude }); setLocating(false); }, () => { setLocErr("تعذّر تحديد الموقع — تحقق من صلاحيات GPS"); setLocating(false); } ); } function addSpot() { if (!name.trim() || !coords) return; const spot = { id: Date.now(), name: name.trim(), lat: coords.lat, lng: coords.lng, date: new Date().toLocaleDateString("ar-SA") }; save([spot, ...spots]); setName(""); setCoords(null); setAdding(false); } function deleteSpot(id) { save(spots.filter(s => s.id !== id)); setDelId(null); } const mapsUrl = (lat, lng) => `https://www.google.com/maps?q=${lat},${lng}`; if (!loaded) return null; return (
{/* Section header */}
🔐
مواقعي الخاصة
محفوظة على جهازك فقط · لا يراها أحد
{/* Add form */} {adding && (
{/* name input */}
📝 اسم الموقع
setName(e.target.value)} placeholder="مثال: شعبة الهامور 🐟" style={{width:"100%",padding:"9px 13px",borderRadius:10,background:"rgba(255,255,255,.06)",border:"1px solid rgba(245,158,11,.3)",color:"#e8f4ff",fontSize:13,outline:"none",direction:"rtl"}}/>
{/* GPS button */} {locErr &&
⚠️ {locErr}
} {/* save btn */}
)} {/* Spots list */} {spots.length === 0 ? (
📍
لا توجد مواقع محفوظة بعد
أضف أول موقع سري لك!
) : (
{spots.map(sp => (
{delId === sp.id ? ( /* confirm delete */
حذف "{sp.name}"؟
) : (
📍
{sp.name}
{sp.lat.toFixed(5)}, {sp.lng.toFixed(5)} · {sp.date}
🗺️ خريطة
)}
))} {spots.length > 0 && (
🔒 {spots.length} موقع محفوظ على جهازك فقط
)}
)}
); } /* ══════ NO-LOCATION PLACEHOLDER ══════ */ function NoLoc({ go }) { return (
📍
لم يتم اختيار موقع
اختر موقع الصيد من الصفحة الرئيسية،
سيُطبَّق على جميع صفحات التطبيق
); } /* ══════ SCORE RING ══════ */ function Ring({ score, size=88 }) { const R=size*.38, C=2*Math.PI*R, c=sCol(score); return ( {score} {sLbl(score)} ); } /* ══════ WX GRID ══════ */ function WxGrid({ wx, small }) { const fs = small ? {i:14,v:11,l:8,p:"7px 4px",r:9} : {i:18,v:13,l:9,p:"10px 7px",r:12}; const items = [ {i:"🌡️",l:"الهواء", v:`${wx.temp}°`, c:"#f87171"}, {i:"💧", l:"الماء", v:`${wx.wtemp}°`, c:"#38bdf8"}, {i:"🌊", l:"الأمواج", v:`${wx.wave}م`, c:+wx.wave>1.5?"#ef4444":"#10b981"}, {i:"💨", l:"الرياح", v:`${wx.wind}عق`, c:"#fbbf24"}, {i:"🧭", l:"الاتجاه", v:wx.dir, c:"#a78bfa"}, {i:"🌊", l:"المد", v:wx.tide==="مد"?"🔼مد":"🔽جزر",c:"#10b981"}, {i:"🔵", l:"الضغط", v:wx.pressure, c:"#60a5fa"}, {i:"👁️",l:"الرؤية", v:`${wx.vis}كم`, c:"#22d3ee"}, {i:"☀️", l:"UV", v:wx.uv, c:"#fb923c"}, ]; return (
{items.map(x => (
{x.i}
{x.v}
{x.l}
))}
); } /* ══════ AI BLOCK ══════ */ function AIBlock({ prompt, ac, ad, ab }) { const [st, setSt] = useState("idle"); const [tx, setTx] = useState(""); const [er, setEr] = useState(""); const run = async () => { setSt("loading"); setTx(""); setEr(""); try { setTx(await callAI(prompt)); setSt("done"); } catch(e) { setEr(e.message||"خطأ"); setSt("error"); } }; if (st==="idle") return ; if (st==="loading") return (
{[88,70,82,60,76].map((w,k)=>
)}
⚙️جاري التحليل...
); if (st==="error") return (
⚠️ تعذّر جلب التحليل
{er}
); return (
🤖 تحليل الذكاء الاصطناعي
); } /* ══════ LOCATION PICKER (home only) ══════ */ function Picker({ onPick, current }) { const [q, setQ] = useState(""); const [reg, setReg] = useState("all"); const list = LOCS.filter(l => { const rOk = reg==="all"||(reg==="red"&&l.reg==="البحر الأحمر")||(reg==="gulf"&&l.reg==="الخليج العربي"); const sOk = !q || l.name.includes(q) || l.grp.includes(q); return rOk && sOk; }); const groups = [...new Set(list.map(l=>l.grp))].sort((a,b)=>GRP_ORDER.indexOf(a)-GRP_ORDER.indexOf(b)); return (
{/* banner */}
📍
اختر موقع الصيد
يُطبَّق على جميع صفحات التطبيق
{current && ✓ {current.name}}
{/* search */}
🔍 setQ(e.target.value)} placeholder="ابحث عن موقع..." style={{width:"100%",padding:"9px 34px 9px 12px",borderRadius:11,background:"rgba(255,255,255,.06)",border:"1px solid rgba(255,255,255,.1)",color:"#e8f4ff",fontSize:13,outline:"none",direction:"rtl"}}/>
{/* region tabs */}
{[["all","🌍 الكل"],["red","🔴 الأحمر"],["gulf","🔵 الخليج"]].map(([v,lb])=>( ))}
{/* list */} {groups.length===0 ?
لا توجد نتائج
: groups.map(grp=>{ const items = list.filter(l=>l.grp===grp); const gc = items[0]?.reg==="البحر الأحمر"?"#f87171":"#38bdf8"; return (
{grp} ({items.length})
{items.map(loc => { const active = current?.id===loc.id; return (
onPick(loc)} style={{background:active?"rgba(16,185,129,.1)":"rgba(255,255,255,.04)",borderRadius:12,padding:"10px 13px",border:`1px solid ${active?"rgba(16,185,129,.35)":"rgba(255,255,255,.07)"}`,display:"flex",alignItems:"center",justifyContent:"space-between"}}>
{loc.emoji}
{loc.name}
{loc.type} · {loc.reg}
{active ? ✓ محدد : }
); })}
); }) }
); } /* ══════ FORECAST PAGE (shore / boat) ══════ */ function ForecastPage({ type, sel, setScr, scr }) { const [days, setDays] = useState([]); const [open, setOpen] = useState(null); const sn = season(new Date().getMonth()+1); const isS = type==="shore"; const ac = isS?"#f59e0b":"#38bdf8"; const ad = isS?"rgba(245,158,11,.12)":"rgba(56,189,248,.12)"; const ab = isS?"rgba(245,158,11,.28)":"rgba(56,189,248,.25)"; const bg = isS?"linear-gradient(160deg,#0e0800,#1c1100)":"linear-gradient(160deg,#020e1f,#061424)"; useEffect(()=>{ if(sel){ setDays(mk14(sel,type)); setOpen(null); } },[sel,type]); return (
{!sel ? : ( <> {/* page banner */}
{isS?"🏖️ الصيد من الشاطئ":"⛵ الصيد بالقارب"}
📅 توقعات ١٤ يوم · {SEASON[sn]}
{sel.emoji} {sel.name}
{sel.reg}
{/* 14 days */}
{days.map((d,i)=>{ const isOpen = open===i; const prompt = mkPrompt(type,sel,d.wx,`${d.dayF} ${d.dateStr}`,sn); return (
setOpen(isOpen?null:i)} style={{background:isOpen?ad:"rgba(255,255,255,.03)",padding:"10px 13px",display:"flex",alignItems:"center",gap:9}}>
{d.dayS}
{d.isToday?"اليوم":d.date.getDate()}
{MONTHS_AR[d.date.getMonth()].slice(0,3)}
🌊 {d.wx.wave}م
💨 {d.wx.wind}عق
🌡️ {d.wx.temp}°
{d.wx.tide==="مد"?"🔼مد":"🔽جزر"}
{isOpen && (
📅 {d.dayF}، {d.dateStr} {d.date.getFullYear()}
)}
); })}
)}
); } /* ══════════════════════════════════════ MAIN APP ══════════════════════════════════════ */ export default function App() { const [scr, setScr] = useState("home"); const [sel, setSel] = useState(null); // ← single global location const [wx, setWx] = useState(null); const [wxLoading, setWxLoading] = useState(false); const [tab, setTab] = useState("wx"); const sn = season(new Date().getMonth()+1); const clk = useClock(); // ── load saved location on mount ── useEffect(() => { async function loadSaved() { try { const res = await window.storage.get("hawat_location"); if (res?.value) { const saved = LOCS.find(l => l.id === res.value); if (saved) { setSel(saved); setWxLoading(true); setTimeout(() => { const seed = saved.id.charCodeAt(0)*999 + new Date().getHours()*37; setWx(mkWx(saved, seed, "today")); setWxLoading(false); }, 600); } } } catch(_) {} } loadSaved(); }, []); const pickLocation = useCallback(async loc => { setSel(loc); setWxLoading(true); setWx(null); // save to persistent storage try { await window.storage.set("hawat_location", loc.id); } catch(_) {} setTimeout(()=>{ const seed = loc.id.charCodeAt(0)*999 + new Date().getHours()*37; setWx(mkWx(loc, seed, "today")); setWxLoading(false); }, 600); }, []); /* ── route: shore ── */ if (scr==="shore") return ; /* ── route: boat ── */ if (scr==="boat") return ; /* ── route: map ── */ if (scr==="map") { const W=340,H=210, px=(la,ln)=>[((ln-34)/(52-34))*W, H-((la-16)/(30-16))*H]; return (
{!sel ? : ( <>
🗺️ الخريطة الساحلية
٢٩ موقعاً على سواحل المملكة
{sel.emoji} {sel.name}
🔴 البحر الأحمر🔵 الخليج العربي🟢 موقعك
البحر الأحمر الخليج العربي {LOCS.map(loc=>{ const [x,y]=px(loc.lat,loc.lng), cur=sel?.id===loc.id; const c=loc.reg==="البحر الأحمر"?"#f87171":"#38bdf8"; return ( {cur && } {loc.name} ); })}
)}
); } /* ── route: res ── */ if (scr==="res") { const sc = wx ? shoreScore(wx) : 0; const col = sCol(sc); const verdict = sc>=70?"ممتاز للصيد! 🎣":sc>=40?"مقبول مع حذر ⚠️":"غير مناسب اليوم 🚫"; const prompt = (sel && wx) ? mkPrompt("today",sel,wx,`${clk.day} ${clk.gregorian}`,sn) : ""; return (
{!sel ? : wxLoading ? (
🌊
جاري تحليل البيانات...
) : wx && ( <> {/* score card */}
تقييم الصيد اليوم
{verdict}
{SEASON[sn]}
{/* tabs */}
{[{id:"wx",l:"🌊 الطقس"},{id:"ai",l:"🤖 تحليل AI"},{id:"times",l:"⏰ الأوقات"}].map(t=>( ))}
{tab==="wx" && } {tab==="ai" && (
🤖
تحليل الصيد بالذكاء الاصطناعي
بناءً على جميع عوامل الطقس الحالية
)} {tab==="times" && (
{[{ic:"🌅",l:"⭐ الأفضل",t:"5:15 ص – 7:45 ص",c:"#10b981"},{ic:"🌇",l:"الوقت الثاني",t:"5:00 م – 7:30 م",c:"#38bdf8"}].map(x=>(
{x.ic}
{x.l}
{x.t}
))}
📌 نصائح السلامة
{["ابدأ التحضير قبل ساعة","ارتدِ سترة النجاة دائماً","راقب تغيرات الطقس","احترم أنظمة الصيد"].map(t=>(
{t}
))}
)} )}
); } /* ══════ HOME ══════ */ return (
{/* Location picker */}
); }