Enable thread file attachments
This commit is contained in:
1 parent
d5a7665893
commit
91d9b76281
2 files changed
+54
-7
No files matched your search
@@ -69,6 +69,7 @@ export function ChatPage({ snapshot, actions }: PageProps) {
|
|||||||
const [openThreadId, setOpenThreadId] = useState<string | null>(null);
|
const [openThreadId, setOpenThreadId] = useState<string | null>(null);
|
||||||
const [createOpen, setCreateOpen] = useState(false);
|
const [createOpen, setCreateOpen] = useState(false);
|
||||||
const [attachmentFileId, setAttachmentFileId] = useState<string>("");
|
const [attachmentFileId, setAttachmentFileId] = useState<string>("");
|
||||||
|
const [threadAttachmentFileId, setThreadAttachmentFileId] = useState<string>("");
|
||||||
const composerRef = useRef<HTMLTextAreaElement | null>(null);
|
const composerRef = useRef<HTMLTextAreaElement | null>(null);
|
||||||
|
|
||||||
const firstAvailableSpaceId = channels[0]?.id ?? directs[0]?.id ?? null;
|
const firstAvailableSpaceId = channels[0]?.id ?? directs[0]?.id ?? null;
|
||||||
@@ -119,6 +120,16 @@ export function ChatPage({ snapshot, actions }: PageProps) {
|
|||||||
);
|
);
|
||||||
const pendingApprovalsInSpace = filterApprovalsForSpace(approvalsAll, activeSpace);
|
const pendingApprovalsInSpace = filterApprovalsForSpace(approvalsAll, activeSpace);
|
||||||
|
|
||||||
|
const openThread = (threadId: string) => {
|
||||||
|
setOpenThreadId(threadId);
|
||||||
|
setThreadAttachmentFileId("");
|
||||||
|
};
|
||||||
|
|
||||||
|
const closeThread = () => {
|
||||||
|
setOpenThreadId(null);
|
||||||
|
setThreadAttachmentFileId("");
|
||||||
|
};
|
||||||
|
|
||||||
const sendInChannel = (event: FormEvent<HTMLFormElement>) => {
|
const sendInChannel = (event: FormEvent<HTMLFormElement>) => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
if (!activeSpace) return;
|
if (!activeSpace) return;
|
||||||
@@ -145,6 +156,7 @@ export function ChatPage({ snapshot, actions }: PageProps) {
|
|||||||
const body = value(form, "message");
|
const body = value(form, "message");
|
||||||
if (!body) return;
|
if (!body) return;
|
||||||
event.currentTarget.reset();
|
event.currentTarget.reset();
|
||||||
|
setThreadAttachmentFileId("");
|
||||||
void actions.run(() => window.agentCompany.sendMessage({
|
void actions.run(() => window.agentCompany.sendMessage({
|
||||||
orgId,
|
orgId,
|
||||||
spaceId: activeSpace.id,
|
spaceId: activeSpace.id,
|
||||||
@@ -152,7 +164,7 @@ export function ChatPage({ snapshot, actions }: PageProps) {
|
|||||||
senderType: "employee",
|
senderType: "employee",
|
||||||
senderId: employee.id,
|
senderId: employee.id,
|
||||||
bodyMd: body,
|
bodyMd: body,
|
||||||
attachmentFileIds: [],
|
attachmentFileIds: threadAttachmentFileId ? [threadAttachmentFileId] : [],
|
||||||
}));
|
}));
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -225,9 +237,17 @@ export function ChatPage({ snapshot, actions }: PageProps) {
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
const attachFile = () => {
|
const attachFile = () => {
|
||||||
|
importAttachment(setAttachmentFileId);
|
||||||
|
};
|
||||||
|
|
||||||
|
const attachThreadFile = () => {
|
||||||
|
importAttachment(setThreadAttachmentFileId);
|
||||||
|
};
|
||||||
|
|
||||||
|
const importAttachment = (onSelect: (fileId: string) => void) => {
|
||||||
void window.agentCompany.importFile({ orgId }).then((result) => {
|
void window.agentCompany.importFile({ orgId }).then((result) => {
|
||||||
if (!result.ok) throw new Error(result.error.message);
|
if (!result.ok) throw new Error(result.error.message);
|
||||||
if (result.data) setAttachmentFileId(result.data);
|
if (result.data) onSelect(result.data);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -248,7 +268,7 @@ export function ChatPage({ snapshot, actions }: PageProps) {
|
|||||||
activeSpaceId={activeSpaceId}
|
activeSpaceId={activeSpaceId}
|
||||||
onSelect={(spaceId) => {
|
onSelect={(spaceId) => {
|
||||||
setSelectedSpaceId(spaceId);
|
setSelectedSpaceId(spaceId);
|
||||||
setOpenThreadId(null);
|
closeThread();
|
||||||
}}
|
}}
|
||||||
onCreateSpace={() => setCreateOpen(true)}
|
onCreateSpace={() => setCreateOpen(true)}
|
||||||
/>
|
/>
|
||||||
@@ -269,7 +289,7 @@ export function ChatPage({ snapshot, actions }: PageProps) {
|
|||||||
currentEmployeeId={employee.id}
|
currentEmployeeId={employee.id}
|
||||||
onAttachmentChange={setAttachmentFileId}
|
onAttachmentChange={setAttachmentFileId}
|
||||||
onAttach={attachFile}
|
onAttach={attachFile}
|
||||||
onOpenThread={setOpenThreadId}
|
onOpenThread={openThread}
|
||||||
onApprove={(approvalId) => decideApproval(approvalId, "approved")}
|
onApprove={(approvalId) => decideApproval(approvalId, "approved")}
|
||||||
onDecline={(approvalId) => decideApproval(approvalId, "declined")}
|
onDecline={(approvalId) => decideApproval(approvalId, "declined")}
|
||||||
onEditMessage={editChatMessage}
|
onEditMessage={editChatMessage}
|
||||||
@@ -292,7 +312,10 @@ export function ChatPage({ snapshot, actions }: PageProps) {
|
|||||||
auditEvents={threadAuditEvents}
|
auditEvents={threadAuditEvents}
|
||||||
context={{ employees, agents }}
|
context={{ employees, agents }}
|
||||||
canIntervene={canBoardIntervene}
|
canIntervene={canBoardIntervene}
|
||||||
onClose={() => setOpenThreadId(null)}
|
attachmentFileId={threadAttachmentFileId}
|
||||||
|
onClose={closeThread}
|
||||||
|
onAttachmentChange={setThreadAttachmentFileId}
|
||||||
|
onAttach={attachThreadFile}
|
||||||
onSubmit={sendInThread}
|
onSubmit={sendInThread}
|
||||||
onBoardSubmit={sendBoardIntervention}
|
onBoardSubmit={sendBoardIntervention}
|
||||||
onOpenFile={openFile}
|
onOpenFile={openFile}
|
||||||
|
|||||||
@@ -26,7 +26,10 @@ export function ChatThreadPanel({
|
|||||||
auditEvents,
|
auditEvents,
|
||||||
context,
|
context,
|
||||||
canIntervene,
|
canIntervene,
|
||||||
|
attachmentFileId,
|
||||||
onClose,
|
onClose,
|
||||||
|
onAttachmentChange,
|
||||||
|
onAttach,
|
||||||
onSubmit,
|
onSubmit,
|
||||||
onBoardSubmit,
|
onBoardSubmit,
|
||||||
onOpenFile,
|
onOpenFile,
|
||||||
@@ -42,11 +45,15 @@ export function ChatThreadPanel({
|
|||||||
auditEvents: AuditEventRecord[];
|
auditEvents: AuditEventRecord[];
|
||||||
context: MessageContext;
|
context: MessageContext;
|
||||||
canIntervene: boolean;
|
canIntervene: boolean;
|
||||||
|
attachmentFileId: string;
|
||||||
onClose: () => void;
|
onClose: () => void;
|
||||||
|
onAttachmentChange: (next: string) => void;
|
||||||
|
onAttach: () => void;
|
||||||
onSubmit: (event: FormEvent<HTMLFormElement>) => void;
|
onSubmit: (event: FormEvent<HTMLFormElement>) => void;
|
||||||
onBoardSubmit: (event: FormEvent<HTMLFormElement>) => void;
|
onBoardSubmit: (event: FormEvent<HTMLFormElement>) => void;
|
||||||
onOpenFile: (fileId: string) => void;
|
onOpenFile: (fileId: string) => void;
|
||||||
}) {
|
}) {
|
||||||
|
const attachment = files.find((file) => file.id === attachmentFileId) ?? null;
|
||||||
return (
|
return (
|
||||||
<aside
|
<aside
|
||||||
style={{
|
style={{
|
||||||
@@ -126,8 +133,25 @@ export function ChatThreadPanel({
|
|||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<div className="row" style={{ paddingTop: 6, justifyContent: "flex-end" }}>
|
<div className="row" style={{ paddingTop: 6, gap: 4 }}>
|
||||||
<Button tone="primary" size="small" type="submit"><Icon name="send" size={12} /> Reply</Button>
|
<IconButton icon="attach" label="Attach file" onClick={onAttach} />
|
||||||
|
{attachment && (
|
||||||
|
<span className="pill" style={{ maxWidth: 150 }}>
|
||||||
|
<Icon name="file" size={11} />
|
||||||
|
<span style={{ overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>{attachment.name}</span>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
aria-label="Remove thread attachment"
|
||||||
|
onClick={() => onAttachmentChange("")}
|
||||||
|
style={{ display: "inline-flex", border: 0, background: "transparent", padding: 0, color: "var(--text-3)", cursor: "pointer" }}
|
||||||
|
>
|
||||||
|
<Icon name="x" size={11} />
|
||||||
|
</button>
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
<div style={{ marginLeft: "auto" }}>
|
||||||
|
<Button tone="primary" size="small" type="submit"><Icon name="send" size={12} /> Reply</Button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|||||||
Reference in new issue
Block a user