mirror of
https://github.com/Luchexx/wacrm.git
synced 2026-11-02 09:19:51 +00:00
refactor: address PR feedback for security and cleanups
- refactor: migrate dangerouslySetInnerHTML(t.raw) to t.rich() to prevent HTML injection vectors
- fix: restore per-status wording for flow activation toasts ("Flow activated.", "Archived.", "Saved as draft.")
- chore: remove unused `tComposer` in message-thread.tsx
- chore: remove unused `ROLE_DESCRIPTIONS` in invite-member-dialog.tsx
This commit is contained in:
parent
de75715cff
commit
4690c4d929
@ -1144,7 +1144,9 @@
|
|||||||
"editorState": {
|
"editorState": {
|
||||||
"saved": "Saved.",
|
"saved": "Saved.",
|
||||||
"fixIssues": "Fix the issues below before activating.",
|
"fixIssues": "Fix the issues below before activating.",
|
||||||
"statusChanged": "Flow is now {status}."
|
"statusActivated": "Flow activated.",
|
||||||
|
"statusArchived": "Archived.",
|
||||||
|
"statusDraft": "Saved as draft."
|
||||||
},
|
},
|
||||||
"summary": {
|
"summary": {
|
||||||
"options": "{count} {count, plural, =1 {option} other {options}}",
|
"options": "{count} {count, plural, =1 {option} other {options}}",
|
||||||
|
|||||||
@ -174,7 +174,9 @@ export function FlowBuilder() {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{state.nodes.length === 0 ? (
|
{state.nodes.length === 0 ? (
|
||||||
<div className="border-border bg-card/50 text-muted-foreground rounded-lg border border-dashed p-8 text-center text-sm" dangerouslySetInnerHTML={{ __html: t.raw('nodesEmpty') }} />
|
<div className="border-border bg-card/50 text-muted-foreground rounded-lg border border-dashed p-8 text-center text-sm">
|
||||||
|
{t.rich('nodesEmpty', { strong: (chunks) => <strong>{chunks}</strong> })}
|
||||||
|
</div>
|
||||||
) : (
|
) : (
|
||||||
state.nodes.map((node) => (
|
state.nodes.map((node) => (
|
||||||
<NodeCard
|
<NodeCard
|
||||||
|
|||||||
@ -383,7 +383,13 @@ export function FlowEditorProvider({
|
|||||||
throw new Error(json.error ?? `Status update failed: ${res.status}`);
|
throw new Error(json.error ?? `Status update failed: ${res.status}`);
|
||||||
}
|
}
|
||||||
setStateRaw((s) => ({ ...s, status: next }));
|
setStateRaw((s) => ({ ...s, status: next }));
|
||||||
toast.success(t("statusChanged", { status: next }));
|
toast.success(
|
||||||
|
next === "active"
|
||||||
|
? t("statusActivated")
|
||||||
|
: next === "archived"
|
||||||
|
? t("statusArchived")
|
||||||
|
: t("statusDraft")
|
||||||
|
);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
const msg = err instanceof Error ? err.message : "Status update failed";
|
const msg = err instanceof Error ? err.message : "Status update failed";
|
||||||
toast.error(msg);
|
toast.error(msg);
|
||||||
|
|||||||
@ -168,7 +168,6 @@ export function MessageThread({
|
|||||||
}: MessageThreadProps) {
|
}: MessageThreadProps) {
|
||||||
const t = useTranslations("Inbox.messageThread");
|
const t = useTranslations("Inbox.messageThread");
|
||||||
const tTimer = useTranslations("Inbox.sessionTimer");
|
const tTimer = useTranslations("Inbox.sessionTimer");
|
||||||
const tComposer = useTranslations("Inbox.composer");
|
|
||||||
const tQuote = useTranslations("Inbox.replyQuote");
|
const tQuote = useTranslations("Inbox.replyQuote");
|
||||||
|
|
||||||
const { user } = useAuth();
|
const { user } = useAuth();
|
||||||
|
|||||||
@ -55,12 +55,6 @@ const EXPIRY_OPTIONS = [
|
|||||||
{ value: '30', labelKey: 'days30' },
|
{ value: '30', labelKey: 'days30' },
|
||||||
];
|
];
|
||||||
|
|
||||||
const ROLE_DESCRIPTIONS = [
|
|
||||||
'adminHint',
|
|
||||||
'agentHint',
|
|
||||||
'viewerHint',
|
|
||||||
];
|
|
||||||
|
|
||||||
// Server caps label at 80 chars (see src/app/api/account/invitations/route.ts).
|
// Server caps label at 80 chars (see src/app/api/account/invitations/route.ts).
|
||||||
// Mirror it on the client so we short-circuit before the round-trip
|
// Mirror it on the client so we short-circuit before the round-trip
|
||||||
// rather than letting the user submit and bounce off a 400.
|
// rather than letting the user submit and bounce off a 400.
|
||||||
|
|||||||
@ -503,7 +503,9 @@ export function MembersTab() {
|
|||||||
<p className="mt-2 text-sm text-muted-foreground">
|
<p className="mt-2 text-sm text-muted-foreground">
|
||||||
{t('noPendingTitle')}
|
{t('noPendingTitle')}
|
||||||
</p>
|
</p>
|
||||||
<p className="mt-1 text-xs text-muted-foreground" dangerouslySetInnerHTML={{ __html: t.raw('noPendingDesc') }} />
|
<p className="mt-1 text-xs text-muted-foreground">
|
||||||
|
{t.rich('noPendingDesc', { bold: (chunks) => <strong>{chunks}</strong> })}
|
||||||
|
</p>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
) : (
|
) : (
|
||||||
|
|||||||
@ -653,7 +653,7 @@ export function TemplateManager() {
|
|||||||
{form.category === 'Authentication' && (
|
{form.category === 'Authentication' && (
|
||||||
<div className="flex items-start gap-2 rounded border border-amber-700/40 bg-amber-950/30 px-3 py-2 text-xs text-amber-300">
|
<div className="flex items-start gap-2 rounded border border-amber-700/40 bg-amber-950/30 px-3 py-2 text-xs text-amber-300">
|
||||||
<AlertCircle className="size-4 mt-0.5 shrink-0" />
|
<AlertCircle className="size-4 mt-0.5 shrink-0" />
|
||||||
<p dangerouslySetInnerHTML={{ __html: t.raw('authWarning') }} />
|
<p>{t.rich('authWarning', { bold: (chunks) => <strong>{chunks}</strong> })}</p>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
@ -724,7 +724,7 @@ export function TemplateManager() {
|
|||||||
{editingId ? (
|
{editingId ? (
|
||||||
t('langFixed')
|
t('langFixed')
|
||||||
) : (
|
) : (
|
||||||
<span dangerouslySetInnerHTML={{ __html: t.raw('langHint') }} />
|
<span>{t.rich('langHint', { code: (chunks) => <code>{chunks}</code> })}</span>
|
||||||
)}
|
)}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user