IO-3603 Production Board Note Autofocus

Signed-off-by: Allan Carr <allan@imexsystems.ca>
This commit is contained in:
Allan Carr
2026-03-06 15:32:06 -08:00
parent 8980d3716b
commit a873a2573a
2 changed files with 40 additions and 30 deletions

View File

@@ -1,7 +1,7 @@
import Icon from "@ant-design/icons"; import Icon from "@ant-design/icons";
import { useMutation } from "@apollo/client/react"; import { useMutation } from "@apollo/client/react";
import { Button, Input, Popover, Tooltip } from "antd"; import { Button, Input, Popover, Tooltip } from "antd";
import { useState } from "react"; import { useState, useRef } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { FaRegStickyNote } from "react-icons/fa"; import { FaRegStickyNote } from "react-icons/fa";
import { UPDATE_JOB } from "../../graphql/jobs.queries"; import { UPDATE_JOB } from "../../graphql/jobs.queries";
@@ -9,10 +9,9 @@ import { logImEXEvent } from "../../firebase/firebase.utils";
export default function ProductionListColumnComment({ record, usePortal = false }) { export default function ProductionListColumnComment({ record, usePortal = false }) {
const { t } = useTranslation(); const { t } = useTranslation();
const [note, setNote] = useState(record.comment || ""); const [note, setNote] = useState(record.comment || "");
const [open, setOpen] = useState(false); const [open, setOpen] = useState(false);
const textAreaRef = useRef(null);
const [updateAlert] = useMutation(UPDATE_JOB); const [updateAlert] = useMutation(UPDATE_JOB);
@@ -39,22 +38,27 @@ export default function ProductionListColumnComment({ record, usePortal = false
const handleOpenChange = (flag) => { const handleOpenChange = (flag) => {
setOpen(flag); setOpen(flag);
if (flag) setNote(record.comment || ""); if (flag) {
setNote(record.comment || "");
requestAnimationFrame(() => {
try {
textAreaRef.current?.focus?.({ preventScroll: true });
} catch {
textAreaRef.current?.focus?.();
}
});
}
}; };
const content = ( const content = (
<div <div style={{ width: "30em" }} onClick={(e) => e.stopPropagation()} onPointerDown={(e) => e.stopPropagation()}>
style={{ width: "30em" }}
onClick={(e) => e.stopPropagation()}
onPointerDown={(e) => e.stopPropagation()}
>
<Input.TextArea <Input.TextArea
id={`job-comment-${record.id}`} id={`job-comment-${record.id}`}
name="comment" name="comment"
rows={5} rows={5}
value={note} value={note}
onChange={handleChange} onChange={handleChange}
autoFocus ref={textAreaRef}
allowClear allowClear
style={{ marginBottom: "1em" }} style={{ marginBottom: "1em" }}
/> />
@@ -67,13 +71,13 @@ export default function ProductionListColumnComment({ record, usePortal = false
); );
return ( return (
<Popover <Popover
onOpenChange={handleOpenChange} onOpenChange={handleOpenChange}
open={open} open={open}
content={content} content={content}
trigger="click" trigger="click"
destroyOnHidden destroyOnHidden
styles={{ body: { padding: '12px' } }} styles={{ body: { padding: "12px" } }}
{...(usePortal ? { getPopupContainer: (trigger) => trigger.parentElement || document.body } : {})} {...(usePortal ? { getPopupContainer: (trigger) => trigger.parentElement || document.body } : {})}
> >
<div <div

View File

@@ -1,7 +1,7 @@
import Icon from "@ant-design/icons"; import Icon from "@ant-design/icons";
import { useMutation } from "@apollo/client/react"; import { useMutation } from "@apollo/client/react";
import { Button, Input, Popover, Space } from "antd"; import { Button, Input, Popover, Space } from "antd";
import { useCallback, useState } from "react"; import { useCallback, useRef, useState } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { FaRegStickyNote } from "react-icons/fa"; import { FaRegStickyNote } from "react-icons/fa";
import { logImEXEvent } from "../../firebase/firebase.utils"; import { logImEXEvent } from "../../firebase/firebase.utils";
@@ -20,6 +20,7 @@ function ProductionListColumnProductionNote({ record, setNoteUpsertContext, useP
const { t } = useTranslation(); const { t } = useTranslation();
const [note, setNote] = useState(record.production_vars?.note || ""); const [note, setNote] = useState(record.production_vars?.note || "");
const [open, setOpen] = useState(false); const [open, setOpen] = useState(false);
const textAreaRef = useRef(null);
const [updateAlert] = useMutation(UPDATE_JOB); const [updateAlert] = useMutation(UPDATE_JOB);
@@ -53,24 +54,29 @@ function ProductionListColumnProductionNote({ record, setNoteUpsertContext, useP
const handleOpenChange = useCallback( const handleOpenChange = useCallback(
(flag) => { (flag) => {
setOpen(flag); setOpen(flag);
if (flag) setNote(record.production_vars?.note || ""); if (flag) {
setNote(record.production_vars?.note || "");
requestAnimationFrame(() => {
try {
textAreaRef.current?.focus?.({ preventScroll: true });
} catch {
textAreaRef.current?.focus?.();
}
});
}
}, },
[record] [record]
); );
const content = ( const content = (
<div <div style={{ width: "30em" }} onClick={(e) => e.stopPropagation()} onPointerDown={(e) => e.stopPropagation()}>
style={{ width: "30em" }}
onClick={(e) => e.stopPropagation()}
onPointerDown={(e) => e.stopPropagation()}
>
<Input.TextArea <Input.TextArea
id={`job-production-note-${record.id}`} id={`job-production-note-${record.id}`}
name="production_note" name="production_note"
rows={5} rows={5}
value={note} value={note}
onChange={handleChange} onChange={handleChange}
autoFocus ref={textAreaRef}
allowClear allowClear
style={{ marginBottom: "1em" }} style={{ marginBottom: "1em" }}
/> />
@@ -96,13 +102,13 @@ function ProductionListColumnProductionNote({ record, setNoteUpsertContext, useP
); );
return ( return (
<Popover <Popover
onOpenChange={handleOpenChange} onOpenChange={handleOpenChange}
open={open} open={open}
content={content} content={content}
trigger="click" trigger="click"
destroyOnHidden destroyOnHidden
styles={{ body: { padding: '12px' } }} styles={{ body: { padding: "12px" } }}
{...(usePortal ? { getPopupContainer: (trigger) => trigger.parentElement || document.body } : {})} {...(usePortal ? { getPopupContainer: (trigger) => trigger.parentElement || document.body } : {})}
> >
<div <div