diff --git a/assets/translations/en.json b/assets/translations/en.json index 6849ee51..13fb2d18 100644 --- a/assets/translations/en.json +++ b/assets/translations/en.json @@ -161,6 +161,7 @@ "hour": "Hour", "hours": "Hour", "icon": "Icon", + "image": "Image", "inYourAgenda": "in your agenda", "it": "Italian", "language": "Language", diff --git a/assets/translations/it.json b/assets/translations/it.json index 58318eb3..7c37bdfd 100644 --- a/assets/translations/it.json +++ b/assets/translations/it.json @@ -168,6 +168,7 @@ "hour": "Orario", "hours": "Ore", "icon": "Icona", + "image": "Immagine", "inYourAgenda": "nella tua agenda", "it": "Italiano", "language": "Lingua", diff --git a/src/core/components/TextWithLinks.tsx b/src/core/components/TextWithLinks.tsx index 91f227a0..64ab1c79 100644 --- a/src/core/components/TextWithLinks.tsx +++ b/src/core/components/TextWithLinks.tsx @@ -2,7 +2,7 @@ import { PropsWithChildren } from 'react'; import { TextProps } from 'react-native'; import { MixedStyleDeclaration } from 'react-native-render-html'; -import { linkUrls } from '../../utils/html'; +import { linkUrls, replaceImgWithAnchorTags } from '../../utils/html'; import { HtmlView } from './HtmlView'; type Props = { @@ -11,7 +11,7 @@ type Props = { export const TextWithLinks = ({ baseStyle, children, style }: Props) => { if (!children || typeof children !== 'string') return null; - const html = linkUrls(children); + const html = linkUrls(replaceImgWithAnchorTags(children)); return ( { }); }, [directoryName, navigation, t]); + directoryQuery.data?.sort((a, b) => { + if (a.type !== 'directory' && b.type !== 'directory') { + const dateA = DateTime.fromJSDate(a.createdAt).startOf('minute'); + const dateB = DateTime.fromJSDate(b.createdAt).startOf('minute'); + + if (dateA.equals(dateB)) { + return a.name.toLowerCase().localeCompare(b.name.toLowerCase()); + } + + return dateA > dateB ? -1 : 1; + } + return 0; + }); + return ( @@ -119,7 +135,9 @@ const CourseFileSearchFlatList = ({ courseId, searchFilter }: SearchProps) => { useEffect(() => { if (!recentFilesQuery.data) return; setSearchResults( - recentFilesQuery.data.filter(file => file.name.includes(searchFilter)), + recentFilesQuery.data.filter(file => + file.name.toLowerCase().includes(searchFilter.toLowerCase()), + ), ); }, [recentFilesQuery.data, searchFilter]); diff --git a/src/features/tickets/components/TextMessage.tsx b/src/features/tickets/components/TextMessage.tsx index 64040662..4c3a5db0 100644 --- a/src/features/tickets/components/TextMessage.tsx +++ b/src/features/tickets/components/TextMessage.tsx @@ -5,7 +5,7 @@ import { useStylesheet } from '@lib/ui/hooks/useStylesheet'; import { Theme } from '@lib/ui/types/Theme'; import { TextWithLinks } from '../../../core/components/TextWithLinks'; -import { getHtmlTextContent } from '../../../utils/html'; +import { sanitizeHtml } from '../../../utils/html'; export interface TextMessageProps { message: string; @@ -15,7 +15,7 @@ export const TextMessage = ({ message }: TextMessageProps) => { const styles = useStylesheet(createStyles); const textMessage = useMemo(() => { - return getHtmlTextContent(message); + return sanitizeHtml(message ?? ''); }, [message]); return {textMessage}; diff --git a/src/utils/html.ts b/src/utils/html.ts index d844b23d..c894ce11 100644 --- a/src/utils/html.ts +++ b/src/utils/html.ts @@ -2,6 +2,7 @@ import { Document } from 'react-native-render-html'; import { innerText } from 'domutils'; import { parseDocument } from 'htmlparser2'; +import i18next from 'i18next'; export const sanitizeHtml = (html: string) => html.replace(/\r/g, '').replace(/\\r/g, '').replace(/\\"/g, '"').trim(); @@ -11,9 +12,16 @@ export const getHtmlTextContent = (text: string) => { return innerText(dom.children as any[]); }; +export const replaceImgWithAnchorTags = (html: string) => { + const imgRegex = /]*src="([^">]*)"[^>]*>/gi; + return html.replace(imgRegex, (_, src) => { + return `${i18next.t('common.image')}`; + }); +}; + export const linkUrls = (html: string) => { const regex = - /(?!]*>[^<])(?:https?:\/\/|www\.)(?:\([-A-Z0-9+&@#/%=~_|$?!:,.]*\)|[-A-Z0-9+&@#/%=~_|$?!:,.])*(?:\([-A-Z0-9+&@#/%=~_|$?!:,.]*\)|[A-Z0-9+&@#/%=~_|$])(?![^<]*<\/a>)/gi; + /(?!]*>[^<])(?:https?:\/\/(?:www\.)?|www\.)?(?:[A-Z0-9-]+(?:[-.][A-Z0-9]+)*\.[A-Z]{2,5})(?::[0-9]{1,5})?(?:\/[A-Z0-9\-._~:/?#[\]@!$&'()*+,;=]*)?(?:\?[A-Z0-9\-._~:/?#[\]@!$&'()*+,;=%]*)?(?:#[A-Z0-9\-._~:/?#[\]@!$&'()*+,;=%]*)?(?![^<]*<\/a>)(? { if (!match.startsWith('http')) match = `https://${match}`; return `${match}`;