推送到 LINE 改為兩段式確認,避免誤觸
根本原因: 「推送到 LINE」按鈕與「上傳資料」「讀取指定日期」並排,單擊即送出,容易手滑把配對結果直接推進 LINE 群組,且推出去無法收回。 影響: - 第一次按只會把按鈕切換成橘色「確認推送到 LINE」並提示,第二次按才真的送出 - 6 秒內沒按第二次會自動取消並提示 - 重新產生配對、讀取指定日期、載入範例名單、更改目標日期時一律解除確認狀態,避免殘留後誤觸 修法: 新增 linePushArmed 狀態與逾時 effect,pushToLine 未確認時先進入確認狀態;各動作函式與日期輸入同步重設;App.css 新增 .is-armed 橘色脈動樣式。 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
+17
@@ -260,6 +260,23 @@
|
||||
outline-offset: 2px;
|
||||
}
|
||||
|
||||
.upload-button.is-armed {
|
||||
background: linear-gradient(135deg, #c96a1c, #e6892e);
|
||||
box-shadow: 0 16px 28px rgba(201, 106, 28, 0.28);
|
||||
animation: armed-pulse 1.2s ease-in-out infinite;
|
||||
}
|
||||
|
||||
@keyframes armed-pulse {
|
||||
0%,
|
||||
100% {
|
||||
box-shadow: 0 16px 28px rgba(201, 106, 28, 0.28);
|
||||
}
|
||||
|
||||
50% {
|
||||
box-shadow: 0 16px 34px rgba(201, 106, 28, 0.5);
|
||||
}
|
||||
}
|
||||
|
||||
.upload-button:disabled {
|
||||
opacity: 0.55;
|
||||
cursor: not-allowed;
|
||||
|
||||
+33
-3
@@ -37,6 +37,7 @@ const STORAGE_KEYS = {
|
||||
|
||||
const PLACEHOLDER_NAME = '那個'
|
||||
const TOTAL_ROUNDS = 3
|
||||
const LINE_PUSH_CONFIRM_TIMEOUT_MS = 6000
|
||||
|
||||
const defaultAreaA = ['建喵', '柏威', '景涵', 'Gary', '昱翔']
|
||||
const defaultAreaB = ['小念', '玟瑄', 'RuRu', '肉肉', '蓉蓉']
|
||||
@@ -54,6 +55,20 @@ function App() {
|
||||
const [actionState, setActionState] = useState<ActionState>('idle')
|
||||
const [actionMessage, setActionMessage] = useState('')
|
||||
const [showTestBadge, setShowTestBadge] = useState(false)
|
||||
const [linePushArmed, setLinePushArmed] = useState(false)
|
||||
|
||||
useEffect(() => {
|
||||
if (!linePushArmed) {
|
||||
return
|
||||
}
|
||||
|
||||
const timer = window.setTimeout(() => {
|
||||
setLinePushArmed(false)
|
||||
setActionState('idle')
|
||||
setActionMessage('已逾時取消推送,需要時請再按一次「推送到 LINE」。')
|
||||
}, LINE_PUSH_CONFIRM_TIMEOUT_MS)
|
||||
return () => window.clearTimeout(timer)
|
||||
}, [linePushArmed])
|
||||
|
||||
useEffect(() => {
|
||||
window.localStorage.setItem(STORAGE_KEYS.areaA, areaAInput)
|
||||
@@ -94,6 +109,7 @@ function App() {
|
||||
}))
|
||||
|
||||
setResults(nextResults)
|
||||
setLinePushArmed(false)
|
||||
setError('')
|
||||
setActionState('idle')
|
||||
setActionMessage('已產生配對,請按「上傳資料」。')
|
||||
@@ -147,6 +163,7 @@ function App() {
|
||||
return
|
||||
}
|
||||
|
||||
setLinePushArmed(false)
|
||||
setActionState('loading')
|
||||
setActionMessage('讀取指定日期資料中...')
|
||||
|
||||
@@ -181,6 +198,15 @@ function App() {
|
||||
return
|
||||
}
|
||||
|
||||
if (!linePushArmed) {
|
||||
setLinePushArmed(true)
|
||||
setActionState('idle')
|
||||
setActionMessage('再按一次「確認推送到 LINE」才會真的送出,6 秒內沒按會自動取消。')
|
||||
return
|
||||
}
|
||||
|
||||
setLinePushArmed(false)
|
||||
|
||||
try {
|
||||
const timeKey = convertDateToKey(targetDate)
|
||||
setActionState('sharing')
|
||||
@@ -201,6 +227,7 @@ function App() {
|
||||
setAreaAInput(defaultAreaA.join('\n'))
|
||||
setAreaBInput(defaultAreaB.join('\n'))
|
||||
setResults([])
|
||||
setLinePushArmed(false)
|
||||
setError('')
|
||||
setActionState('idle')
|
||||
setActionMessage('')
|
||||
@@ -261,7 +288,10 @@ function App() {
|
||||
<input
|
||||
type="date"
|
||||
value={targetDate}
|
||||
onChange={(event) => setTargetDate(event.target.value)}
|
||||
onChange={(event) => {
|
||||
setTargetDate(event.target.value)
|
||||
setLinePushArmed(false)
|
||||
}}
|
||||
/>
|
||||
</label>
|
||||
<button
|
||||
@@ -282,12 +312,12 @@ function App() {
|
||||
</button>
|
||||
{results.length > 0 ? (
|
||||
<button
|
||||
className="primary-button upload-button"
|
||||
className={`primary-button upload-button${linePushArmed ? ' is-armed' : ''}`}
|
||||
type="button"
|
||||
onClick={() => void pushToLine()}
|
||||
disabled={actionState === 'saving' || actionState === 'loading'}
|
||||
>
|
||||
推送到 LINE
|
||||
{linePushArmed ? '確認推送到 LINE' : '推送到 LINE'}
|
||||
</button>
|
||||
) : null}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user