2026-05-09 23:35:53 +08:00
import { useState , useEffect } from 'react' ;
2026-05-09 16:00:29 +08:00
import Icon from './Icon' ;
2026-05-09 23:35:53 +08:00
import { getPointsBalance , type PointsBalance } from '../lib/api' ;
2026-05-09 16:00:29 +08:00
interface Props {
locale : string ;
dashboard : { brandName : string ; navHome : string ; navStore : string ; navDivination : string ; navManual : string ; navAuto : string ; navHistory : string ; navLanguage : string ; navSettings : string ; logout : string } ;
divination : { questionTitle : string ; questionPlaceholder : string ; categoryLabel : string ; categories : string ; timeTitle : string ; timeHint : string ; guideTitle : string ; guideAuto : string ; shakeTitle : string ; shakeBtn : string ; hexPreview : string ; summaryTitle : string ; checkCategory : string ; checkMethod : string ; checkCost : string ; submitBtn : string ; progressLabel : string } ;
}
export default function AutoDivinationPage ( { locale , divination : d } : Props ) {
const cats = d . categories . split ( ',' ) ;
const [ category , setCategory ] = useState ( cats [ 0 ] ) ;
const [ question , setQuestion ] = useState ( '' ) ;
const [ progress , setProgress ] = useState ( 0 ) ;
const [ hexLines , setHexLines ] = useState < boolean [ ] > ( [ ] ) ;
const [ isShaking , setIsShaking ] = useState ( false ) ;
2026-05-09 23:35:53 +08:00
const [ points , setPoints ] = useState < PointsBalance | null > ( null ) ;
useEffect ( ( ) = > {
getPointsBalance ( ) . then ( setPoints ) . catch ( ( ) = > { } ) ;
} , [ ] ) ;
2026-05-09 16:00:29 +08:00
const handleShake = ( ) = > {
setIsShaking ( true ) ;
setTimeout ( ( ) = > {
const newProgress = progress + 1 ;
setProgress ( newProgress ) ;
const line = Math . random ( ) > 0.5 ;
setHexLines ( prev = > [ . . . prev , line ] ) ;
setIsShaking ( false ) ;
} , 600 ) ;
} ;
const done = progress >= 6 ;
return (
< div className = "flex flex-col gap-[22px] min-h-full" >
< div className = "flex items-center justify-between" >
< div >
< h1 className = "text-[#333333] text-[28px] font-bold leading-tight" > { locale === 'en' ? 'Auto Cast' : d . checkMethod . replace ( /^.*: |^.*: / , '' ) . replace ( '手动' , '自动' ) } < / h1 >
< p className = "text-[#666666] text-sm mt-1" > { locale === 'en' ? 'Click the button or shake your device to generate six coin results.' : '点击按钮或摇动设备生成铜钱结果,连续 6 次形成完整卦象。' } < / p >
< / div >
< div className = "hidden md:flex items-center gap-2 h-10 px-3.5 rounded-full bg-white border border-slate-200 text-[#333333] text-[13px] font-semibold" >
< Icon name = "paid" className = "w-[18px] h-[18px] text-violet-700" / >
2026-05-09 23:35:53 +08:00
{ locale === 'en'
? ` Available ${ points ? . availableBalance ? ? '...' } credits · This time ${ points ? . runCost ? ? 20 } credits `
: ` 可用 ${ points ? . availableBalance ? ? '...' } 积分 · 本次 ${ points ? . runCost ? ? 20 } 积分 ` }
2026-05-09 16:00:29 +08:00
< / div >
< / div >
< div className = "flex flex-col xl:flex-row gap-[22px] min-h-0 flex-1" >
{ /* Left: Question + Time + Guide */ }
< div className = "w-full xl:w-[340px] flex flex-col gap-4 shrink-0" >
< div className = "bg-white rounded-2xl p-[22px] border border-slate-200 flex flex-col gap-4" >
< h3 className = "text-slate-900 text-lg font-bold" > { d . questionTitle } < / h3 >
< div className = "flex items-center justify-between h-[42px] px-3 rounded-[10px] bg-slate-50 border border-slate-300" >
< span className = "text-slate-600 text-sm" > { category } < / span >
< select value = { category } onChange = { e = > setCategory ( e . target . value ) } className = "bg-transparent text-sm outline-none cursor-pointer" >
{ cats . map ( c = > < option key = { c } value = { c } > { c } < / option > ) }
< / select >
< / div >
< textarea value = { question } onChange = { e = > setQuestion ( e . target . value ) } placeholder = { d . questionPlaceholder } rows = { 3 }
className = "w-full px-3.5 py-3 rounded-[10px] bg-white border border-slate-300 text-sm focus:outline-none focus:border-violet-400 resize-none" / >
< / div >
< div className = "bg-white rounded-2xl p-5 border border-slate-200 flex flex-col gap-3" >
< h3 className = "text-slate-900 text-base font-bold" > { d . timeTitle } < / h3 >
< div className = "flex items-center justify-between h-[42px] px-3 rounded-[10px] bg-slate-50" >
< input type = "datetime-local" className = "bg-transparent text-sm outline-none w-full" / >
< Icon name = "calendar_today" className = "w-[18px] h-[18px] text-slate-400" / >
< / div >
< / div >
< div className = "bg-white rounded-2xl p-5 border border-slate-200 flex flex-col gap-3 flex-1 overflow-y-auto" >
< h3 className = "text-slate-900 text-base font-bold" > { d . guideTitle } < / h3 >
< p className = "text-slate-500 text-[13px] whitespace-pre-line" > { d . guideAuto } < / p >
< / div >
< / div >
{ /* Center: Shake panel */ }
< div className = "flex-1 bg-white rounded-2xl p-6 border border-slate-200 flex flex-col gap-[18px]" >
< div className = "flex items-center justify-between" >
< h3 className = "text-slate-900 text-lg font-bold" > { d . shakeTitle } < / h3 >
< span className = "text-violet-600 text-[13px] font-bold" > { progress } / 6 < / span >
< / div >
{ /* Coin stage */ }
< div className = "bg-slate-50 rounded-2xl p-[22px] flex items-center justify-center gap-6" style = { { minHeight : '194px' } } >
{ [ 0 , 1 , 2 ] . map ( i = > (
< div key = { i } className = "flex flex-col items-center gap-2" style = { { width : '86px' } } >
< img
src = { isShaking ? '/images/qigua/hua.jpg' : '/images/qigua/zi.jpg' }
alt = { locale === 'en' ? 'coin' : '铜钱' }
className = { ` w-16 h-16 rounded-full object-cover border border-amber-300 shadow-sm transition-all ${ isShaking ? 'animate-pulse' : '' } ` }
/ >
< span className = "text-slate-400 text-xs" > { '铜钱' } < / span >
< / div >
) ) }
< / div >
{ /* Shake button */ }
< div className = "flex flex-col items-center gap-2.5" style = { { height : '82px' , justifyContent : 'center' } } >
{ ! done && (
< button onClick = { handleShake } disabled = { isShaking }
className = "flex items-center gap-2 px-8 py-2.5 rounded-full bg-violet-600 text-white text-sm font-bold hover:bg-violet-700 disabled:opacity-50 transition-colors" >
< Icon name = "casino" className = "w-[18px] h-[18px]" / >
{ d . shakeBtn }
< / button >
) }
{ done && < p className = "text-violet-600 text-sm font-medium" > 六 爻 完 成 < / p > }
< / div >
{ /* Hexagram preview */ }
< div className = "bg-white rounded-xl p-[18px] border border-slate-200 flex-1 flex flex-col gap-3 overflow-y-auto" >
< p className = "text-slate-900 text-base font-bold" > { d . hexPreview } < / p >
< div className = "flex flex-col gap-2" >
{ hexLines . length > 0 ? hexLines . map ( ( isYang , i ) = > isYang ? (
< div key = { i } className = "w-12 h-2 bg-violet-600 rounded" / >
) : (
< div key = { i } className = "flex gap-1.5" > < div className = "w-4 h-2 bg-violet-400 rounded" / > < div className = "w-4 h-2 bg-violet-400 rounded" / > < / div >
) ) : (
< p className = "text-slate-300 text-sm" > 点 击 摇 卦 生 成 卦 象 < / p >
) }
< / div >
< / div >
< / div >
{ /* Right: Summary */ }
< div className = "w-full xl:w-[300px] bg-white rounded-2xl p-[22px] border border-slate-200 flex flex-col gap-[18px] shrink-0" >
< h3 className = "text-slate-900 text-lg font-bold" > { d . summaryTitle } < / h3 >
< div className = "bg-slate-50 rounded-xl p-4 flex flex-col gap-2" style = { { height : '94px' } } >
< p className = "text-slate-500 text-[13px]" > { d . progressLabel } < / p >
< p className = "text-violet-600 text-[28px] font-bold" > { progress } / 6 < / p >
< / div >
< p className = "text-slate-500 text-sm" > { d . checkCategory } < / p >
< p className = "text-slate-500 text-sm" > { d . checkMethod } < / p >
< p className = "text-slate-500 text-sm" > { d . checkCost } < / p >
< div className = "flex-1" / >
< button disabled = { ! done }
className = { ` w-full h-[46px] rounded-full text-sm font-bold transition-colors ${ done ? 'bg-violet-600 text-white hover:bg-violet-700' : 'bg-slate-300 text-slate-400 cursor-not-allowed' } ` } >
{ d . submitBtn }
< / button >
< / div >
< / div >
< / div >
) ;
}