fix(profil-module): QC improvements based on QC-PROFIL-MODULE.md
- Fix fetch method inconsistency (convert to ApiFetch) - programInovasi: findUnique, delete, update methods - mediaSosial: findUnique, delete, update methods - Add loading state to findUnique operations - Fix iconUrl validation (make optional instead of required) - Add DOMPurify for HTML sanitization (XSS protection) - program-inovasi page.tsx (list & detail) - Remove console.log in production (use dev-only logging) - Install dompurify and @types/dompurify Security: Prevent XSS attacks by sanitizing HTML content Consistency: Use ApiFetch for all API operations UX: Proper loading states for better user feedback Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
This commit is contained in:
@@ -8,6 +8,7 @@ import { IconArrowBack, IconEdit, IconTrash } from '@tabler/icons-react';
|
||||
import { useParams, useRouter } from 'next/navigation';
|
||||
import { useState } from 'react';
|
||||
import { useProxy } from 'valtio/utils';
|
||||
import DOMPurify from 'dompurify';
|
||||
|
||||
function DetailProgramInovasi() {
|
||||
const stateProgramInovasi = useProxy(profileLandingPageState.programInovasi)
|
||||
@@ -85,7 +86,7 @@ function DetailProgramInovasi() {
|
||||
<Box>
|
||||
<Text fz="lg" fw="bold">Deskripsi</Text>
|
||||
<Box pl={5}>
|
||||
<Text fz="md" c="dimmed" style={{ wordBreak: "break-word", whiteSpace: "normal" }} dangerouslySetInnerHTML={{ __html: data.description || '-' }}></Text>
|
||||
<Text fz="md" c="dimmed" style={{ wordBreak: "break-word", whiteSpace: "normal" }} dangerouslySetInnerHTML={{ __html: DOMPurify.sanitize(data.description || '-') }}></Text>
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ import { IconDeviceImacCog, IconPlus, IconSearch } from '@tabler/icons-react';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import { useState } from 'react';
|
||||
import { useProxy } from 'valtio/utils';
|
||||
import DOMPurify from 'dompurify';
|
||||
import HeaderSearch from '../../../_com/header';
|
||||
import profileLandingPageState from '../../../_state/landing-page/profile';
|
||||
|
||||
@@ -90,7 +91,7 @@ function ListProgramInovasi({ search }: { search: string }) {
|
||||
<Text fw={500}>{item.name}</Text>
|
||||
</TableTd>
|
||||
<TableTd style={{ maxWidth: 250 }}>
|
||||
<Text fz="sm" lineClamp={1} dangerouslySetInnerHTML={{ __html: item.description || '-' }}></Text>
|
||||
<Text fz="sm" lineClamp={1} dangerouslySetInnerHTML={{ __html: DOMPurify.sanitize(item.description || '-') }}></Text>
|
||||
</TableTd>
|
||||
<TableTd style={{ maxWidth: 250 }}>
|
||||
<Tooltip label="Buka tautan program" position="top" withArrow>
|
||||
@@ -144,7 +145,7 @@ function ListProgramInovasi({ search }: { search: string }) {
|
||||
{/* Description */}
|
||||
<Box>
|
||||
<Text fz="sm" fw={600} lh={1.4}>Deskripsi</Text>
|
||||
<Text dangerouslySetInnerHTML={{ __html: item.description || '-' }} fz="sm" c="gray.7" lineClamp={2} />
|
||||
<Text dangerouslySetInnerHTML={{ __html: DOMPurify.sanitize(item.description || '-') }} fz="sm" c="gray.7" lineClamp={2} />
|
||||
</Box>
|
||||
|
||||
{/* Link */}
|
||||
|
||||
Reference in New Issue
Block a user