Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions changelog/unreleased/accounts-batch-import-mobile.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
### English

- Accounts batch import opens the file picker on mobile again (Safari no longer ignores the hidden-input click), and the confirm sheet fits small screens.

### 中文

- 账号页批量导入在移动端可再次打开文件选择器(Safari 不再忽略隐藏 input 的 click),确认弹层也适配小屏。
9 changes: 5 additions & 4 deletions frontend/src/components/account/BatchImportConfirmModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -62,12 +62,12 @@ export function BatchImportConfirmModal({
}}
>
<Modal.Backdrop variant="blur" isDismissable={!isPending}>
<Modal.Container placement="center" size="sm">
<Modal.Container placement="center" size="sm" scroll="inside" className="mx-3 w-full max-w-[min(100%,24rem)] sm:mx-0">
<Modal.Dialog>
<Modal.Header className="items-start justify-between gap-4 px-5 pt-5">
<div className="min-w-0">
<Modal.Heading className="text-section font-semibold">{t('batchImportConfirmTitle')}</Modal.Heading>
<p className="mt-1 text-caption leading-5 text-muted">
<p className="mt-1 break-all text-caption leading-5 text-muted">
{fileName
? t('batchImportConfirmHint', { file: fileName })
: t('batchImportConfirmHintNoFile')}
Expand Down Expand Up @@ -122,13 +122,14 @@ export function BatchImportConfirmModal({
</ul>
) : null}
</Modal.Body>
<Modal.Footer className="justify-end gap-2 px-5 pb-5">
<Button size="sm" variant="ghost" isDisabled={isPending} onPress={onClose}>
<Modal.Footer className="flex-col-reverse gap-2 px-5 pb-5 sm:flex-row sm:justify-end">
<Button size="sm" variant="ghost" className="w-full sm:w-auto" isDisabled={isPending} onPress={onClose}>
{supported ? t('cancel') : t('close')}
</Button>
{supported ? (
<Button
size="sm"
className="w-full sm:w-auto"
isPending={isPending}
onPress={() => onConfirm(region)}
>
Expand Down
37 changes: 22 additions & 15 deletions frontend/src/pages/AccountsPage.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { toast } from '@/lib/toast'
import { copyText } from '@/lib/clipboard'
import { useCallback, useEffect, useMemo, useRef, useState, type ChangeEvent } from 'react'
import { useCallback, useEffect, useMemo, useState, type ChangeEvent } from 'react'
import { Button, Label, ListBox, Select } from '@heroui/react'
import {
ArrowsClockwise,
Expand Down Expand Up @@ -77,7 +77,6 @@ export function AccountsPage() {
const [batchDetection, setBatchDetection] = useState<ImportDetectResult | null>(null)
const [batchBundle, setBatchBundle] = useState<Record<string, unknown> | null>(null)
const [batchFileName, setBatchFileName] = useState('')
const batchFileInput = useRef<HTMLInputElement>(null)
const [busy, setBusy] = useState<AccountBusy | null>(null)
const [patById, setPatById] = useState<Record<string, string>>({})
const [callbackById, setCallbackById] = useState<Record<string, string>>({})
Expand Down Expand Up @@ -338,11 +337,6 @@ export function AccountsPage() {
}
}

function onBatchImportClick() {
if (batchImporting || batchConfirmOpen) return
batchFileInput.current?.click()
}

function closeBatchConfirm() {
if (batchImporting) return
setBatchConfirmOpen(false)
Expand Down Expand Up @@ -508,21 +502,34 @@ export function AccountsPage() {
/>
</>
) : null}
<div className="ml-auto flex items-center gap-2">
<div className="flex w-full flex-wrap items-center justify-end gap-2 sm:ml-auto sm:w-auto">
<Button size="sm" variant="secondary" isPending={quotaRefreshing} onPress={() => void onRefreshCredits()}>
<ArrowsClockwise size={14} />{t('refreshCredits')}
</Button>
<Button size="sm" variant="secondary" isPending={batchImporting} onPress={onBatchImportClick}>
<UploadSimple size={14} />{t('batchImport')}
</Button>
<Button size="sm" onPress={() => setAddOpen(true)}><Plus size={14} />{t('addAccount')}</Button>
{/*
Mobile Safari ignores programmatic input.click() from React Aria
onPress when the file input is display:none. Associate a real
label with an sr-only input so the picker opens from a direct
user gesture (same detect → confirm → WorkBuddy path).
*/}
<label
htmlFor="accounts-batch-import-file"
className={`button button--sm button--secondary inline-flex items-center gap-1.5 ${
batchImporting || batchConfirmOpen ? 'pointer-events-none opacity-60' : 'cursor-pointer'
}`}
>
{batchImporting ? <BrandMark size={14} loading /> : <UploadSimple size={14} />}
{t('batchImport')}
</label>
<input
ref={batchFileInput}
id="accounts-batch-import-file"
type="file"
accept=".json,application/json"
className="hidden"
accept=".json,application/json,text/json"
disabled={batchImporting || batchConfirmOpen}
className="sr-only"
onChange={(event) => void onBatchImportFile(event)}
/>
<Button size="sm" onPress={() => setAddOpen(true)}><Plus size={14} />{t('addAccount')}</Button>
</div>
</section>

Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Large diffs are not rendered by default.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Large diffs are not rendered by default.

Loading
Loading