sendoff panel keyed (503 -> 494)
The example paths move from <span> to <code>. A path is user content and must not be translated; <code> says so semantically, matches how ApiKeys and the Google guide already render paths, and the scanner skips code elements for that exact reason. A second sentence about turning someone off was multi-line, so the scanner never saw it — converted on sight.
This commit is contained in:
@@ -2,6 +2,7 @@ import { useRef, useState } from 'react';
|
||||
import { Laptop, Send, Upload, User, X } from 'lucide-react';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { useSendOff, useSendOffSenders, useSendOffTargets } from './useSendOff';
|
||||
import { useTranslation } from '../../locales';
|
||||
|
||||
const label = (p: { name: string | null; email: string }): string => p.name || p.email.split('@')[0] || p.email;
|
||||
const kb = (n: number): string =>
|
||||
@@ -17,6 +18,7 @@ type Target = { kind: 'machine'; name: string } | { kind: 'user'; id: number; na
|
||||
* needed keeping in sync.
|
||||
*/
|
||||
export const SendOffPanel = () => {
|
||||
const { t } = useTranslation();
|
||||
const { devices, people, myFolder, isLoading } = useSendOffTargets();
|
||||
const send = useSendOff();
|
||||
const [files, setFiles] = useState<File[]>([]);
|
||||
@@ -41,7 +43,7 @@ export const SendOffPanel = () => {
|
||||
<div className="flex h-full min-h-0 flex-col overflow-y-auto p-5">
|
||||
<div className="mx-auto flex w-full max-w-2xl flex-col gap-5">
|
||||
<section>
|
||||
<h3 className="text-sm font-semibold text-foreground">Files</h3>
|
||||
<h3 className="text-sm font-semibold text-foreground">{t('sendOff.files')}</h3>
|
||||
<input
|
||||
ref={picker}
|
||||
type="file"
|
||||
@@ -70,7 +72,7 @@ export const SendOffPanel = () => {
|
||||
<span className="shrink-0 text-xs text-muted-foreground">{kb(f.size)}</span>
|
||||
<button
|
||||
type="button"
|
||||
aria-label={`Remove ${f.name}`}
|
||||
aria-label={t('sendOff.removeFile', { name: f.name })}
|
||||
className="shrink-0 text-muted-foreground hover:text-foreground"
|
||||
onClick={() => setFiles((prev) => prev.filter((_, k) => k !== i))}
|
||||
>
|
||||
@@ -86,9 +88,9 @@ export const SendOffPanel = () => {
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h3 className="text-sm font-semibold text-foreground">Where</h3>
|
||||
<h3 className="text-sm font-semibold text-foreground">{t('sendOff.where')}</h3>
|
||||
{isLoading ? (
|
||||
<p className="mt-2 text-sm text-muted-foreground">Loading…</p>
|
||||
<p className="mt-2 text-sm text-muted-foreground">{t('sendOff.loading')}</p>
|
||||
) : (
|
||||
<div className="mt-2 flex flex-col gap-3">
|
||||
<TargetGroup
|
||||
@@ -124,19 +126,19 @@ export const SendOffPanel = () => {
|
||||
<section className="flex flex-col gap-2">
|
||||
<Button onClick={doSend} disabled={!ready || send.isPending} size="lg">
|
||||
<Send className="mr-2 h-4 w-4" />
|
||||
{send.isPending ? 'Sending…' : target ? `Send to ${target.name}` : 'Send'}
|
||||
{send.isPending ? 'Sending…' : target ? t('sendOff.sendTo', { name: target.name }) : 'Send'}
|
||||
</Button>
|
||||
{/* The server's own message, not a generic one: a file over the limit and a recipient who has
|
||||
revoked you are different problems with different answers. */}
|
||||
{target?.kind === 'user' && myFolder && (
|
||||
<p className="text-xs text-muted-foreground">
|
||||
Lands in their <span className="text-foreground">Documents/SendOff/{myFolder}</span>.
|
||||
{t('sendOff.landsIn')} <code className="text-foreground">Documents/SendOff/{myFolder}</code>.
|
||||
</p>
|
||||
)}
|
||||
{send.error && <p className="text-sm text-destructive">{send.error.message}</p>}
|
||||
{send.data && (
|
||||
<p className="text-sm text-muted-foreground">
|
||||
Landed in <span className="text-foreground">{send.data.path}</span> —{' '}
|
||||
{t('sendOff.landedIn')} <span className="text-foreground">{send.data.path}</span> —{' '}
|
||||
{send.data.files.map((f) => f.name).join(', ')}
|
||||
</p>
|
||||
)}
|
||||
@@ -195,15 +197,16 @@ const TargetGroup = ({ icon: Icon, heading, empty, options, selected, onSelect }
|
||||
* the answer has to be visible in the same place the question was asked.
|
||||
*/
|
||||
const WhoMaySend = () => {
|
||||
const { t } = useTranslation();
|
||||
const { candidates, isLoading, setAllowed, isSaving } = useSendOffSenders();
|
||||
if (isLoading || candidates.length === 0) return null;
|
||||
|
||||
return (
|
||||
<section className="border-t border-border pt-4">
|
||||
<h3 className="text-sm font-semibold text-foreground">Who may send to me</h3>
|
||||
<h3 className="text-sm font-semibold text-foreground">{t('sendOff.whoMaySend')}</h3>
|
||||
<p className="mt-1 text-xs text-muted-foreground">
|
||||
Files from anyone you allow land in <span className="text-foreground">Documents/SendOff/their-name</span>.
|
||||
Turning someone off stops future sends and leaves what they already sent alone.
|
||||
{t('sendOff.allowedLandIn')} <code className="text-foreground">Documents/SendOff/their-name</code>.{' '}
|
||||
{t('sendOff.turningOff')}
|
||||
</p>
|
||||
<div className="mt-2 flex flex-col gap-1">
|
||||
{candidates.map((p) => (
|
||||
|
||||
Reference in New Issue
Block a user