+
{isReadOnly ? (
-
) : (
-
+ // onTimeChange([
+ // [time, timeSpan.flat()[1]],
+ // [timeSpan.flat()[2], timeSpan.flat()[3]],
+ // ])
+ // }
+ // />
+ //
+ // onTimeChange([
+ // [value as string, timeSpan.flat()[1]],
+ // [timeSpan.flat()[2], timeSpan.flat()[3]],
+ // ])
+ // } />
+
+ disabled={disabled}
+ onChange={(value) =>
onTimeChange([
- [time, timeSpan.flat()[1]],
+ [value as string, timeSpan.flat()[1]],
[timeSpan.flat()[2], timeSpan.flat()[3]],
])
}
@@ -51,18 +72,38 @@ const TimeSelectSection: React.FC = ({
{isReadOnly ? (
-
) : (
-
+ // onTimeChange([
+ // [timeSpan.flat()[0], time],
+ // [timeSpan.flat()[2], timeSpan.flat()[3]],
+ // ])
+ // }
+ // />
+ //
+ // onTimeChange([
+ // [timeSpan.flat()[0], value as string],
+ // [timeSpan.flat()[2], timeSpan.flat()[3]],
+ // ])
+ // } />
+
+ disabled={disabled}
+ onChange={(value) =>
onTimeChange([
- [timeSpan.flat()[0], time],
+ [timeSpan.flat()[0], value],
[timeSpan.flat()[2], timeSpan.flat()[3]],
])
}
@@ -71,44 +112,84 @@ const TimeSelectSection: React.FC = ({
-
Fascia Oraria 2
+ {(isReadOnly && !(timeSpan.flat()[2] && timeSpan.flat()[3])) ? null :
Fascia Oraria 2
}
- {isReadOnly ? (
-
- ) : (
-
+ // onTimeChange([
+ // [timeSpan.flat()[0], timeSpan.flat()[1]],
+ // [time, timeSpan.flat()[3]],
+ // ])
+ // }
+ // />
+ //
+ // onTimeChange([
+ // [timeSpan.flat()[0], timeSpan.flat()[1]],
+ // [value as string, timeSpan.flat()[3]],
+ // ])
+ // } />
+
+ disabled={disabled}
+ onChange={(value) =>
onTimeChange([
[timeSpan.flat()[0], timeSpan.flat()[1]],
- [time, timeSpan.flat()[3]],
+ [value as string, timeSpan.flat()[3]],
])
}
/>
)}
- {isReadOnly ? (
-
- ) : (
-
+ // onTimeChange([
+ // [timeSpan.flat()[0], timeSpan.flat()[1]],
+ // [timeSpan.flat()[2], time],
+ // ])
+ // }
+ // />
+ //
+ // onTimeChange([
+ // [timeSpan.flat()[0], timeSpan.flat()[1]],
+ // [timeSpan.flat()[2], value as string],
+ // ])
+ // } />
+
+ disabled={disabled}
+ onChange={(value) =>
onTimeChange([
[timeSpan.flat()[0], timeSpan.flat()[1]],
- [timeSpan.flat()[2], time],
+ [timeSpan.flat()[2], value as string],
])
}
/>
diff --git a/fe-piattaforma/src/components/AdministrativeArea/Entities/Surveys/ManageOTP/ManageOTP.tsx b/fe-piattaforma/src/components/AdministrativeArea/Entities/Surveys/ManageOTP/ManageOTP.tsx
index 89d86c1da..59ff27ca4 100644
--- a/fe-piattaforma/src/components/AdministrativeArea/Entities/Surveys/ManageOTP/ManageOTP.tsx
+++ b/fe-piattaforma/src/components/AdministrativeArea/Entities/Surveys/ManageOTP/ManageOTP.tsx
@@ -56,16 +56,14 @@ const ManageOTP = () => {
content = (
<>
- {' '}
- Inserisci il codice OTP pr verifica{' '}
+ Inserisci il codice OTP pr verifica
- {' '}
- Non hai ricevuto l SMS?{' '}
- Invia di nuovo {' '}
+ Non hai ricevuto l SMS?
+ Invia di nuovo
>
);
diff --git a/fe-piattaforma/src/components/AnteprimaNews/anteprimaNews.scss b/fe-piattaforma/src/components/AnteprimaNews/anteprimaNews.scss
new file mode 100644
index 000000000..1fcfa7da3
--- /dev/null
+++ b/fe-piattaforma/src/components/AnteprimaNews/anteprimaNews.scss
@@ -0,0 +1,66 @@
+.anteprima-news-container {
+ background: #ffffff;
+ border: 1px solid #eceff1;
+ box-shadow: 4px 4px 8px rgba(0, 0, 0, 0.1);
+ border-radius: 4px;
+ width: 95%;
+
+ @media screen and (min-width: 600px) and (max-width: 992px) {
+ margin-top: -100px;
+ margin-left: 16px;
+ }
+ @media screen and (min-width: 993px) and (max-width: 1200px) {
+ margin-top: -150px;
+ }
+ @media screen and (min-width: 1201px) {
+ margin-top: -200px;
+ }
+
+ &__category {
+ font-size: 18px;
+ line-height: 27px;
+ letter-spacing: 1.1px;
+ color: #455b71;
+ }
+ &__title {
+ font-size: 24px;
+ line-height: 28px;
+ color: #222222;
+ }
+ &__description {
+ word-break: break-all;
+ }
+ &__news-dropdown {
+ button {
+ padding: 5px;
+ color: #ffffff;
+ border: none;
+ }
+ button:hover {
+ border: none;
+ background-color: #ffffff;
+ box-shadow: none;
+ }
+ }
+}
+
+.border-box-container {
+ opacity: 0.3;
+ border-bottom: 0.5px solid #3686d6;
+}
+
+.bg-image {
+ max-width: 1200px;
+ max-height: 600px;
+
+ @media screen and (max-width: 576px) {
+ height: 200px;
+ margin-right: 18px;
+ }
+ @media screen and (min-width: 577px) and (max-width: 992px) {
+ height: 300px;
+ }
+ @media screen and (min-width: 993px) {
+ height: 600px;
+ }
+}
diff --git a/fe-piattaforma/src/components/AnteprimaNews/anteprimaNews.tsx b/fe-piattaforma/src/components/AnteprimaNews/anteprimaNews.tsx
new file mode 100644
index 000000000..aae1e786c
--- /dev/null
+++ b/fe-piattaforma/src/components/AnteprimaNews/anteprimaNews.tsx
@@ -0,0 +1,332 @@
+import React, { useEffect, useState } from 'react';
+import './anteprimaNews.scss';
+import {
+ Button,
+ Dropdown,
+ DropdownMenu,
+ DropdownToggle,
+ Icon,
+ LinkList,
+} from 'design-react-kit';
+import { DetailCard } from '../index';
+import clsx from 'clsx';
+import { useAppSelector } from '../../redux/hooks';
+import { selectDevice } from '../../redux/features/app/appSlice';
+import SocialBar from '../Comments/socialBar';
+import { useDispatch } from 'react-redux';
+import { openModal } from '../../redux/features/modal/modalSlice';
+import coverPlaceholder from '/public/assets/img/placeholder-news.png';
+import HTMLParser from '../General/HTMLParser/HTMLParse';
+import {
+ ActionTracker,
+ GetItemDetail,
+ ManageItemEvent,
+} from '../../redux/features/forum/forumThunk';
+import { selectUser } from '../../redux/features/user/userSlice';
+import { cleanDrupalFileURL } from '../../utils/common';
+import { formatDate } from '../../utils/datesHelper';
+import useGuard from '../../hooks/guard';
+
+export interface AnteprimaBachecaNewsI {
+ author?: string;
+ id?: string;
+ category?: string;
+ category_label?: string;
+ date?: string;
+ title?: string;
+ description?: string;
+ program_label?: string | undefined;
+ intervention?: string;
+ entity?: string | undefined;
+ entity_type?: string | undefined;
+ attachment?: any;
+ cover?: any;
+ enable_comments?: boolean;
+ likes?: number;
+ views?: number;
+ user_like?: boolean;
+ comment_count?: number;
+ isModalPreview?: boolean;
+ onDeleteNews?: () => void;
+ onEditNews?: () => void;
+ onReportNews?: () => void;
+}
+
+const AnteprimaBachecaNews: React.FC = (props) => {
+ const {
+ author,
+ id,
+ category,
+ category_label,
+ date,
+ title,
+ cover,
+ description,
+ attachment,
+ program_label,
+ intervention,
+ entity,
+ entity_type,
+ likes,
+ views,
+ user_like,
+ enable_comments,
+ comment_count,
+ isModalPreview,
+ onDeleteNews = () => ({}),
+ onEditNews = () => ({}),
+ onReportNews = () => ({}),
+ } = props;
+
+ const [newsDetailDropdownOptions, setNewsDetailDropdownOptions] = useState<
+ any[]
+ >([]);
+ const device = useAppSelector(selectDevice);
+ const [isOpen, setIsOpen] = useState(false);
+ const dispatch = useDispatch();
+ const userId = useAppSelector(selectUser)?.id;
+ const { hasUserPermission } = useGuard();
+
+ const deleteOption = {
+ optionName: 'ELIMINA',
+ DropdownIcon: {
+ icon: 'it-delete',
+ color: 'primary',
+ },
+ action: onDeleteNews,
+ };
+
+ const editOption = {
+ optionName: 'MODIFICA',
+ DropdownIcon: {
+ icon: 'it-pencil',
+ color: 'primary',
+ },
+ action: onEditNews,
+ };
+
+ const reportOption = {
+ optionName: 'SEGNALA',
+ DropdownIcon: {
+ icon: 'it-error',
+ color: 'danger',
+ },
+ action: onReportNews,
+ };
+
+ const setNewsDetailDropdownOptionsByPermission = () => {
+ const authorizedOption = [];
+ if (
+ hasUserPermission(['del.news']) ||
+ (author?.toString() === userId?.toString() &&
+ hasUserPermission(['new.news']))
+ ) {
+ authorizedOption.push(deleteOption);
+ }
+ if (
+ hasUserPermission(['upd.news']) ||
+ (author?.toString() === userId?.toString() &&
+ hasUserPermission(['new.news']))
+ ) {
+ authorizedOption.push(editOption);
+ }
+ if (hasUserPermission(['rprt.news'])) {
+ authorizedOption.push(reportOption);
+ }
+ setNewsDetailDropdownOptions(authorizedOption);
+ };
+
+ useEffect(() => {
+ setNewsDetailDropdownOptionsByPermission();
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [author, userId]);
+
+ const newsDetailDropdown = () => (
+ setIsOpen(!isOpen)}
+ >
+
+
+
+
+
+
+
+ {newsDetailDropdownOptions.map((item, i) => (
+ setIsOpen(!isOpen)}>
+
+
+ ))}
+
+
+
+ );
+
+ return (
+
+
+
+
+
+
+
+
+ {category_label} {date ? ' — ' : ''}{' '}
+
+ {date && formatDate(date, 'shortDate')}
+
+ {!isModalPreview && (
+
{newsDetailDropdown()}
+ )}
+
+
+ {title}
+
+
+
+
+ {attachment ? (
+
+ ) : null}
+
+ {!isModalPreview && (
+ <>
+
+
{
+ if (id) {
+ if (user_like as boolean) {
+ await dispatch(ManageItemEvent(id, 'unlike'));
+ } else {
+ await dispatch(ManageItemEvent(id, 'like'));
+ dispatch(
+ ActionTracker({
+ target: 'tnd',
+ action_type: 'LIKE',
+ event_type: 'NEWS',
+ category: category_label || category,
+ })
+ );
+ }
+ userId && dispatch(GetItemDetail(id, userId, 'board'));
+ }
+ }}
+ onComment={
+ enable_comments
+ ? () =>
+ dispatch(
+ openModal({
+ id: 'comment-modal',
+ payload: {
+ title: 'Aggiungi commento',
+ action: 'comment',
+ entity: 'board',
+ category: category_label || category,
+ textLabel: 'Digita qui sotto il testo',
+ },
+ })
+ )
+ : undefined
+ }
+ />
+ >
+ )}
+
+
+
+ );
+};
+
+export default AnteprimaBachecaNews;
diff --git a/fe-piattaforma/src/components/Avatar/AvatarInitials/avatarInitials.scss b/fe-piattaforma/src/components/Avatar/AvatarInitials/avatarInitials.scss
new file mode 100644
index 000000000..08d1590e9
--- /dev/null
+++ b/fe-piattaforma/src/components/Avatar/AvatarInitials/avatarInitials.scss
@@ -0,0 +1,31 @@
+.avatar-initials-container {
+ &__circle-width {
+ &__preview {
+ width: 120px;
+ height: 120px;
+ }
+ &__big {
+ width: 67px !important;
+ height: 67px !important;
+ }
+ &__medium {
+ width: 58px !important;
+ height: 58px !important;
+ }
+ &__small {
+ width: 39px !important;
+ height: 39px !important;
+ }
+ }
+}
+.initials {
+ &__font-small {
+ font-size: 15px;
+ }
+ &__font-medium {
+ font-size: 20px;
+ }
+ &__font-big {
+ font-size: 32px;
+ }
+}
diff --git a/fe-piattaforma/src/components/AvatarInitials/avatarInitials.tsx b/fe-piattaforma/src/components/Avatar/AvatarInitials/avatarInitials.tsx
similarity index 62%
rename from fe-piattaforma/src/components/AvatarInitials/avatarInitials.tsx
rename to fe-piattaforma/src/components/Avatar/AvatarInitials/avatarInitials.tsx
index df1740a5d..6b4cfc081 100644
--- a/fe-piattaforma/src/components/AvatarInitials/avatarInitials.tsx
+++ b/fe-piattaforma/src/components/Avatar/AvatarInitials/avatarInitials.tsx
@@ -5,18 +5,21 @@ import './avatarInitials.scss';
export enum AvatarSizes {
Big = '__big',
+ Medium = '__medium',
Small = '__small',
+ Preview = '__preview',
}
export enum AvatarTextSizes {
Big = '__font-big',
+ Medium = '__font-medium',
Small = '__font-small',
}
export interface AvatarInitialsI {
user: {
- uName: string | undefined;
uSurname: string | undefined;
+ uName: string | undefined;
};
lightColor?: boolean | undefined;
size?: AvatarSizes;
@@ -25,41 +28,43 @@ export interface AvatarInitialsI {
const AvatarInitials: React.FC = (props) => {
const {
- user: { uName = '', uSurname = '' },
- lightColor = false,
+ user: { uSurname = '', uName = '' },
+ /* lightColor = false, */
size,
font,
} = props;
- const getInitials = (name: string, surname: string) => {
- const userName = name.charAt(0).toUpperCase();
+ const getInitials = (surname: string, name: string) => {
const userSurname = surname.charAt(0).toUpperCase();
+ const userName = name.charAt(0).toUpperCase();
- return userName + userSurname;
+ return userSurname + userName;
};
return (
{uName && uSurname ? (
-
- {' '}
- {getInitials(uName, uSurname)}{' '}
-
+
{getInitials(uSurname, uName)}
) : (
-
+
)}
);
diff --git a/fe-piattaforma/src/components/Avatar/ProfileImage/ProfileImageForm.tsx b/fe-piattaforma/src/components/Avatar/ProfileImage/ProfileImageForm.tsx
new file mode 100644
index 000000000..b9ca38ab4
--- /dev/null
+++ b/fe-piattaforma/src/components/Avatar/ProfileImage/ProfileImageForm.tsx
@@ -0,0 +1,132 @@
+import { Button, Icon } from 'design-react-kit';
+import React, { /* useEffect, */ useRef } from 'react';
+import { withFormHandlerProps } from '../../../hoc/withFormHandler';
+import { formFieldI } from '../../../utils/formHelper';
+import Form from '../../Form/form';
+import {useAppSelector} from "../../../redux/hooks";
+import {selectDevice} from "../../../redux/features/app/appSlice";
+import clsx from "clsx";
+
+interface ProfilePictureI extends withFormHandlerProps {
+ formDisabled?: boolean;
+ newFormValues?: { [key: string]: formFieldI['value'] };
+ sendNewValues?: (param?: { [key: string]: formFieldI['value'] }) => void;
+ setIsFormValid?: (param: boolean | undefined) => void;
+ creation?: boolean;
+ profilePic?: string | File | undefined;
+ image?: {
+ name?: string | undefined;
+ data?: string | File | undefined;
+ };
+ setImage?: (image: {
+ name?: string | undefined;
+ data?: string | File | undefined;
+ }) => void;
+ setSelectedImage?: (value: File | string) => void;
+}
+
+const ProfileImageForm: React.FC = (props) => {
+ const device = useAppSelector(selectDevice);
+ const {
+ setSelectedImage = () => ({}),
+ setImage = () => ({}),
+ image = { name: 'Seleziona immagine profilo', data: '' },
+ setIsFormValid = () => ({}),
+ } = props;
+ const bootClass = 'justify-content-between px-0 px-lg-5 mx-2';
+ const inputRef = useRef(null);
+
+ const removeImage = (e: any) => {
+ setImage({ name: 'Carica foto profilo', data: '' });
+ setSelectedImage('');
+ setIsFormValid(true);
+ if (inputRef.current !== null) {
+ inputRef.current.value = '';
+ }
+ e.preventDefault();
+ };
+
+ const addImage = () => {
+ if (inputRef.current !== null) {
+ inputRef.current.click();
+ }
+ };
+
+ const updateImage = async () => {
+ const input: HTMLInputElement = document.getElementById(
+ 'profile_pic'
+ ) as HTMLInputElement;
+
+ if (input.files?.length) {
+ const selectedImage = input.files[0];
+ const reader = new FileReader();
+ reader.readAsDataURL(selectedImage);
+ reader.onloadend = () => {
+ setImage({ name: selectedImage.name, data: reader.result as string });
+ setSelectedImage(selectedImage);
+ setIsFormValid(true);
+ };
+ }
+ };
+
+ return (
+
+
+
+
+
+
+ massimo 10 Mb
+
+
+
+ );
+};
+
+export default ProfileImageForm;
diff --git a/fe-piattaforma/src/components/Avatar/UserAvatar/UserAvatar.scss b/fe-piattaforma/src/components/Avatar/UserAvatar/UserAvatar.scss
new file mode 100644
index 000000000..9d012c66e
--- /dev/null
+++ b/fe-piattaforma/src/components/Avatar/UserAvatar/UserAvatar.scss
@@ -0,0 +1,17 @@
+.avatar-user-container {
+ &__circle-width {
+ &__big {
+ width: 67px !important;
+ height: 67px !important;
+ }
+ &__small {
+ width: 39px !important;
+ height: 39px !important;
+ }
+ }
+ &__avatar-image {
+ border-radius: 50%;
+ width: 100%;
+ height: 100%;
+ }
+}
diff --git a/fe-piattaforma/src/components/Avatar/UserAvatar/UserAvatar.tsx b/fe-piattaforma/src/components/Avatar/UserAvatar/UserAvatar.tsx
new file mode 100644
index 000000000..76c61733c
--- /dev/null
+++ b/fe-piattaforma/src/components/Avatar/UserAvatar/UserAvatar.tsx
@@ -0,0 +1,100 @@
+import clsx from 'clsx';
+import React from 'react';
+import { selectDevice } from '../../../redux/features/app/appSlice';
+import { useAppSelector } from '../../../redux/hooks';
+import AvatarInitials, {
+ AvatarSizes,
+ AvatarTextSizes,
+} from '../AvatarInitials/avatarInitials';
+
+interface UserAvatarI {
+ avatarImage?: string | File | undefined;
+ user?: {
+ uSurname: string | undefined;
+ uName: string | undefined;
+ };
+ lightColor?: boolean | undefined;
+ size?: AvatarSizes;
+ font?: AvatarTextSizes;
+ isUserProfile?: boolean | string | undefined;
+ isPreview?: boolean;
+}
+
+const UserAvatar: React.FC = (props) => {
+ const device = useAppSelector(selectDevice);
+ const {
+ avatarImage = '',
+ size,
+ user = { uSurname: '', uName: '' },
+ /* lightColor = false,
+ font, */
+ isUserProfile = false,
+ isPreview = false,
+ } = props;
+
+ return (
+
+ {avatarImage ? (
+
+ ) : (
+
+ )}
+
+ );
+};
+
+export default UserAvatar;
diff --git a/fe-piattaforma/src/components/AvatarInitials/avatarInitials.scss b/fe-piattaforma/src/components/AvatarInitials/avatarInitials.scss
deleted file mode 100644
index 2e3b139c2..000000000
--- a/fe-piattaforma/src/components/AvatarInitials/avatarInitials.scss
+++ /dev/null
@@ -1,20 +0,0 @@
-.avatar-initials-container {
- &__circle-width {
- &__big {
- width: 53px;
- min-height: 53px;
- }
- &__small {
- width: 35px;
- min-height: 35px;
- }
- }
-}
-.initials {
- &__font-small {
- font-size: 15px;
- }
- &__font-big {
- font-size: 24px;
- }
-}
diff --git a/fe-piattaforma/src/components/Breadcrumb/breadCrumb.scss b/fe-piattaforma/src/components/Breadcrumb/breadCrumb.scss
new file mode 100644
index 000000000..e42b3b7a5
--- /dev/null
+++ b/fe-piattaforma/src/components/Breadcrumb/breadCrumb.scss
@@ -0,0 +1,3 @@
+.breadcrumb {
+ margin: 0;
+}
\ No newline at end of file
diff --git a/fe-piattaforma/src/components/Breadcrumb/breadCrumb.tsx b/fe-piattaforma/src/components/Breadcrumb/breadCrumb.tsx
index 0796fd690..146d543d3 100644
--- a/fe-piattaforma/src/components/Breadcrumb/breadCrumb.tsx
+++ b/fe-piattaforma/src/components/Breadcrumb/breadCrumb.tsx
@@ -1,13 +1,22 @@
-import React from 'react';
+import React, { useEffect, useState } from 'react';
import {
Breadcrumb as BreadcrumbKit,
BreadcrumbItem,
Container,
} from 'design-react-kit';
+import './breadCrumb.scss';
import clsx from 'clsx';
-import { NavLink } from 'react-router-dom';
+import { NavLink, useLocation } from 'react-router-dom';
+import isEqual from 'lodash.isequal';
import { useSelector } from 'react-redux';
-import { selectBreadcrumb } from '../../redux/features/app/appSlice';
+import {
+ selectCustomBreadcrumb,
+ selectInfoIdsBreadcrumb,
+ selectIsBreadcrumbPresent,
+} from '../../redux/features/app/appSlice';
+import { useAppSelector } from '../../redux/hooks';
+import { selectProfile } from '../../redux/features/user/userSlice';
+import { userRoles } from '../../pages/administrator/AdministrativeArea/Entities/utils';
export interface BreadcrumbI {
label?: string;
@@ -16,17 +25,132 @@ export interface BreadcrumbI {
}
const Breadcrumb = () => {
- const breadcrumbList = useSelector(selectBreadcrumb);
+ const userProfile = useAppSelector(selectProfile);
+ const isBreadcrumbPresent = useAppSelector(selectIsBreadcrumbPresent);
+ const breadcrumbList = useSelector(selectCustomBreadcrumb);
+ const idsBreadcrumb = useSelector(selectInfoIdsBreadcrumb);
+ const urlCurrentLocation = useLocation().pathname;
+ const location = useLocation()
+ .pathname.split('/')
+ .filter((elem) => elem !== '');
+ const [currentLocation, setCurrentLocation] = useState();
+ const [navigationList, setNavigationList] = useState([]);
+
+ const createUrl = (index: number) => {
+ let url = '';
+ (currentLocation || []).map((elem: string, i: number) => {
+ if (elem !== '' && i <= index) {
+ url = url + '/' + currentLocation?.[i];
+ }
+ });
+ return url;
+ };
+
+ const getLabelBreadcrumb = (pathElem: string) => {
+ let breadcrumbLabel;
+ if (idsBreadcrumb.filter((x) => x?.id?.toString() === pathElem)[0]) {
+ breadcrumbLabel = idsBreadcrumb.filter(
+ (x) => x?.id?.toString() === pathElem
+ )[0].nome;
+ } else {
+ switch (pathElem) {
+ case 'area-amministrativa':
+ return 'Area amministrativa';
+ case 'area-cittadini':
+ return 'Area cittadini';
+ default:
+ breadcrumbLabel =
+ pathElem.charAt(0).toUpperCase() +
+ pathElem.slice(1, pathElem.length).replaceAll('-', ' ');
+ break;
+ }
+ }
+ try {
+ return decodeURI(breadcrumbLabel);
+ } catch (error) {
+ return breadcrumbLabel;
+ }
+ };
+
+ useEffect(() => {
+ if (!isEqual(location, currentLocation)) {
+ setCurrentLocation(location);
+ }
+ }, [location]);
+
+ useEffect(() => {
+ if (
+ breadcrumbList?.length &&
+ breadcrumbList[breadcrumbList?.length - 1]?.url === urlCurrentLocation
+ ) {
+ setNavigationList(breadcrumbList);
+ } else if (currentLocation && currentLocation?.length) {
+ const newList: { label: string; url: string; link: boolean }[] = [];
+ (currentLocation || []).map((elem: string, index: number) => {
+ if (elem !== '') {
+ if(elem?.toLowerCase() === 'sedi'){
+ newList.pop();
+ }
+ if (
+ currentLocation?.length > 3 &&
+ index < currentLocation?.length - 1
+ ) {
+ newList.push({
+ label: getLabelBreadcrumb(elem),
+ url: createUrl(index),
+ link:
+ ((userProfile?.codiceRuolo === userRoles.REGP ||
+ userProfile?.codiceRuolo === userRoles.DEGP ||
+ userProfile?.codiceRuolo === userRoles.REPP ||
+ userProfile?.codiceRuolo === userRoles.DEPP ||
+ userProfile?.codiceRuolo === userRoles.FAC ||
+ userProfile?.codiceRuolo === userRoles.VOL) &&
+ getLabelBreadcrumb(elem) === 'Progetti') ||
+ ((userProfile?.codiceRuolo === userRoles.REG ||
+ userProfile?.codiceRuolo === userRoles.DEG ||
+ userProfile?.codiceRuolo === userRoles.REGP ||
+ userProfile?.codiceRuolo === userRoles.DEGP ||
+ userProfile?.codiceRuolo === userRoles.REPP ||
+ userProfile?.codiceRuolo === userRoles.DEPP ||
+ userProfile?.codiceRuolo === userRoles.FAC ||
+ userProfile?.codiceRuolo === userRoles.VOL) &&
+ getLabelBreadcrumb(elem) === 'Programmi')
+ ? false
+ : index !== 0 && index !== currentLocation?.length - 2,
+ });
+ } else if (currentLocation?.length <= 3) {
+ newList.push({
+ label: getLabelBreadcrumb(elem),
+ url: createUrl(index),
+ link:
+ ((userProfile?.codiceRuolo === userRoles.REGP ||
+ userProfile?.codiceRuolo === userRoles.DEGP ||
+ userProfile?.codiceRuolo === userRoles.REPP ||
+ userProfile?.codiceRuolo === userRoles.DEPP) &&
+ getLabelBreadcrumb(elem) === 'Progetti') ||
+ ((userProfile?.codiceRuolo === userRoles.REG ||
+ userProfile?.codiceRuolo === userRoles.DEG) &&
+ getLabelBreadcrumb(elem) === 'Programmi')
+ ? false
+ : index !== 0 && index !== currentLocation?.length - 1,
+ });
+ }
+ }
+ setNavigationList(newList);
+ });
+ }
+ }, [currentLocation, currentLocation?.length, idsBreadcrumb, breadcrumbList]);
- return (
-
-
- {breadcrumbList.map((item, index) => (
+ return isBreadcrumbPresent ? (
+
+
+ {(navigationList || []).map((item, index) => (
{item.link && item.url ? (
{item.label}
@@ -40,14 +164,14 @@ const Breadcrumb = () => {
{item.label}
)}
- {index < breadcrumbList.length - 1 && (
+ {index < navigationList.length - 1 && (
/
)}
))}
- );
+ ) : null;
};
export default Breadcrumb;
diff --git a/fe-piattaforma/src/components/ButtonsBar/buttonsBar.scss b/fe-piattaforma/src/components/ButtonsBar/buttonsBar.scss
index 4876b3976..1f9718ce5 100644
--- a/fe-piattaforma/src/components/ButtonsBar/buttonsBar.scss
+++ b/fe-piattaforma/src/components/ButtonsBar/buttonsBar.scss
@@ -1,12 +1,10 @@
.buttons-bar {
display: flex;
justify-content: flex-end;
- padding: rem(22px 0);
- background: white;
+ padding: rem(15px 0);
+ // margin-right: rem(20px);
flex-wrap: wrap;
- gap: rem(15px);
-
-
+ gap: rem(5px);
@media (max-width: 764px) {
justify-content: space-between;
@@ -21,3 +19,40 @@
justify-content: flex-end;
}
}
+
+.buttons-mobile-tablet {
+ @media screen and (min-width: 250px) and (max-width: 700px) {
+ margin-right: 1.3rem;
+ }
+}
+
+
+.buttons-bar-alignment {
+ display: flex;
+ justify-content: flex-end;
+ padding: rem(15px 0);
+ // margin-right: rem(20px);
+ flex-wrap: wrap;
+ gap: rem(5px);
+
+ @media (max-width: 764px) {
+ justify-content: end;
+ .btn-xs {
+ min-width: rem(160px);
+ max-width: rem(220px);
+ max-height: rem(48px);
+ width: unset;
+ }
+ }
+
+ /* .btn:last-child {
+ @media screen and (min-width: 360px) and (max-width: 576px) {
+ margin-right: 1.3rem;
+ }
+ }
+ .btn:first-child {
+ @media screen and (min-width: 360px) and (max-width: 442px) {
+ margin-right: 1.3rem;
+ }
+ } */
+}
\ No newline at end of file
diff --git a/fe-piattaforma/src/components/ButtonsBar/buttonsBar.tsx b/fe-piattaforma/src/components/ButtonsBar/buttonsBar.tsx
index 42c81d81a..7ebc016b4 100644
--- a/fe-piattaforma/src/components/ButtonsBar/buttonsBar.tsx
+++ b/fe-piattaforma/src/components/ButtonsBar/buttonsBar.tsx
@@ -8,44 +8,80 @@ export interface ButtonInButtonsBar extends ButtonProps {
text: string;
iconForButton?: string;
iconColor?: string;
+ buttonClass?: string;
}
interface StickyButtonsI {
buttons: ButtonInButtonsBar[];
+ citizenList?: boolean;
+ citizenDeleteChange?: boolean;
+ isUserProfile?: boolean;
+ notActiveSurvey?: boolean;
+ isDocumentsCta?: boolean;
+ forumAlignment?: boolean;
}
-const ButtonsBar: React.FC = ({ buttons = [] }) => {
+const ButtonsBar: React.FC = ({
+ buttons = [],
+ citizenList = false,
+ citizenDeleteChange = false,
+ isUserProfile = false,
+ notActiveSurvey = false,
+ isDocumentsCta = false,
+ forumAlignment = false,
+}) => {
const device = useAppSelector(selectDevice);
return (
- {buttons.map((button: ButtonInButtonsBar, index: number) => (
-
- ))}
+ {buttons.map((button: ButtonInButtonsBar, index: number) => {
+ const buttonProps = {
+ ...button,
+ buttonClass: undefined,
+ iconColor: undefined,
+ iconForButton: undefined,
+ text: undefined, // for accessibility
+ };
+ return (
+
+ );
+ })}
);
};
diff --git a/fe-piattaforma/src/components/Card/card.tsx b/fe-piattaforma/src/components/Card/card.tsx
index 709e5c13a..f80d56b63 100644
--- a/fe-piattaforma/src/components/Card/card.tsx
+++ b/fe-piattaforma/src/components/Card/card.tsx
@@ -81,7 +81,7 @@ const Card: React.FC = (props) => {
color='primary'
icon='it-calendar'
size='xs'
- aria-label='calendar'
+ aria-label={category}
/>
{category}
diff --git a/fe-piattaforma/src/components/CardCommunity/cardCommunity.scss b/fe-piattaforma/src/components/CardCommunity/cardCommunity.scss
index 4ea47dfbe..61cbea69d 100644
--- a/fe-piattaforma/src/components/CardCommunity/cardCommunity.scss
+++ b/fe-piattaforma/src/components/CardCommunity/cardCommunity.scss
@@ -1,50 +1,64 @@
-.community-card {
- box-shadow: 0 0 40px rgba(0, 0, 0, 0.1);
- border-radius: 10px;
-
- &__maxWidthCard {
- max-width: 376px;
- }
-
- &__line {
- margin: 0;
- width: 90%;
- }
-
- &__last-comment {
- box-shadow: 0 0 40px rgba(0, 0, 0, 0.1);
+.card-community {
+ border: 1px solid #eceff1;
+ box-shadow: 0px 0px 80px rgba(0, 43, 85, 0.1);
+ border-radius: 4px;
+ width: 365px;
+ height: 260px;
+ border-left: 4px solid #4392e0;
+ @media screen and (max-width: 1200px) {
+ width: 292px;
}
- &__picture-comment {
- width: 32px;
- height: 32px;
+ &__pre-title {
+ color: #455b71;
+ font-weight: 400;
+ font-size: 16px;
+ line-height: 24px;
+ letter-spacing: 1.1px;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
}
- &__white-card {
- border-top-right-radius: 10px;
- border-bottom-right-radius: 10px;
+ &__bookmark {
+ display: flex;
+ margin-left: 300px;
+ margin-top: -22px;
}
-
- &__dots {
- background-color: grey;
- vertical-align: middle;
- border-radius: 50%;
- height: 8px;
- width: 8px;
- display: inline-block;
+ &__body {
+ margin-top: -22px;
}
-
- &__maxLinesTitle {
- display: -webkit-box;
- -webkit-line-clamp: 1;
- -webkit-box-orient: vertical;
+ &__title {
+ color: #1c2024;
+ font-size: 24px;
+ line-height: 40px;
overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
}
-
- &__maxLinesParagraph {
+ &__text {
+ color: #455b71;
+ font-weight: 400;
+ font-size: 16px;
+ line-height: 24px;
+ height: 45px;
+ overflow: hidden;
+ text-overflow: ellipsis;
display: -webkit-box;
- -webkit-line-clamp: 4;
+ -webkit-line-clamp: 2;
-webkit-box-orient: vertical;
- overflow: hidden;
+ }
+ &__span-icons {
+ font-weight: 400;
+ line-height: 18px;
+ letter-spacing: 0.933333px;
+ }
+ &__date {
+ color: #455b71;
+ font-weight: 400;
+ font-size: 16px;
+ line-height: 24px;
+ letter-spacing: 1.1px;
+ padding-left: 6px;
}
}
diff --git a/fe-piattaforma/src/components/CardCommunity/cardCommunity.tsx b/fe-piattaforma/src/components/CardCommunity/cardCommunity.tsx
index 44520ceae..a185d29fc 100644
--- a/fe-piattaforma/src/components/CardCommunity/cardCommunity.tsx
+++ b/fe-piattaforma/src/components/CardCommunity/cardCommunity.tsx
@@ -1,211 +1,145 @@
import clsx from 'clsx';
-import {
- Button,
- CardProps,
- CardText,
- CardTitle,
- Col,
- Icon,
-} from 'design-react-kit';
+import { CardText, CardTitle, Col, Icon } from 'design-react-kit';
import React, { memo } from 'react';
-import { useTranslation } from 'react-i18next';
-import { selectDevice } from '../../redux/features/app/appSlice';
-import { useAppSelector } from '../../redux/hooks';
+import Heart from '/public/assets/img/hollow-grey-heart.png';
import './cardCommunity.scss';
-import Avatar from '/public/assets/img/avatar-icon-test.png';
+import { useNavigate } from 'react-router-dom';
+import PublishingAuthority from '../CardDocument/PublishingAuthority';
+import { formatDate } from '../../utils/datesHelper';
+import { ForumCardsI } from '../CardShowcase/cardShowcase';
-interface CommentI {
- user?: string;
- picture?: string;
- commmentText?: string;
- commentDate?: string;
-}
-
-interface CardCommunityI extends CardProps {
- title?: string;
- community?: string;
- text?: string;
- colorLeft?: string;
- date?: string;
- likes?: string;
- commentsTot?: number;
- fullCard?: boolean;
- comments?: CommentI[];
-}
-
-const CardCommunity: React.FC
= (props) => {
+const CardCommunity: React.FC = (props) => {
const {
+ id,
title,
- community,
- text,
- colorLeft,
+ description,
date,
likes,
- commentsTot,
- fullCard,
- comments,
+ comment_count,
+ category_label,
+ views,
+ entity,
} = props;
+ const navigate = useNavigate();
- const { t } = useTranslation();
-
- const device = useAppSelector(selectDevice);
+ const navigateTo = () => {
+ navigate(`/community/${id}`);
+ };
return (
- <>
+ {
+ if (e.key === ' ') {
+ e.preventDefault();
+ navigateTo();
+ }
+ }}
+ onClick={navigateTo}
+ tabIndex={0}
+ aria-label={`Categoria: ${category_label}. Data: ${
+ date && formatDate(date, 'shortDate')
+ }. Titolo topic: ${title}. Descrizione: ${description}. Editore: ${entity}. ${likes} like. ${comment_count} ${
+ Number(comment_count) === 1 ? 'commento' : 'commenti'
+ }. ${views} ${
+ Number(views) === 1 ? 'visualizzazione' : 'visualizzazioni'
+ }`}
+ >
+
+ {category_label ? (
+
+
+ {category_label}
+ {/* — */}
+
+
+ ) : null}
+ {title ? (
+
+ {title}
+
+ ) : null}
+ {description ? (
+
+ {description}
+
+ ) : null}
+ {entity ?
: null}
+
-
-
- {title ? (
-
- {title}
-
- ) : null}
-
- {text ? (
-
- {text}
-
- ) : null}
-
+
+ {date && formatDate(date, 'shortDate')}
+
+
-
-
- {date}
-
-
-
- {likes}
-
-
-
- {commentsTot}
-
-
-
-
- {fullCard && (
- <>
-
-
+
+ {likes}
- >
- )}
- >
+
+
+ {views}
+
+
+
+
);
};
diff --git a/fe-piattaforma/src/components/CardCounter/cardCounter.tsx b/fe-piattaforma/src/components/CardCounter/cardCounter.tsx
index 7db7dc749..440d7b499 100644
--- a/fe-piattaforma/src/components/CardCounter/cardCounter.tsx
+++ b/fe-piattaforma/src/components/CardCounter/cardCounter.tsx
@@ -1,6 +1,8 @@
import clsx from 'clsx';
import { Icon } from 'design-react-kit';
import React, { memo } from 'react';
+import { selectDevice } from '../../redux/features/app/appSlice';
+import { useAppSelector } from '../../redux/hooks';
import './cardCounter.scss';
export interface CardCounterI {
@@ -12,6 +14,7 @@ export interface CardCounterI {
const CardCounter: React.FC
= (props) => {
const { title, counter, icon, className } = props;
+ const device = useAppSelector(selectDevice);
return (
= (props) => {
'flex-row',
'card-counter',
'px-3',
- 'py-3'
+ 'py-3',
+ device.mediaIsPhone && 'my-2 w-100'
)}
>
= ({
+ authority,
+ isDocument,
+}) => {
+ return (
+
+ );
+};
+
+export default PublishingAuthority;
diff --git a/fe-piattaforma/src/components/CardDocument/cardDocument.scss b/fe-piattaforma/src/components/CardDocument/cardDocument.scss
index 8bea09099..b80e2e3ec 100644
--- a/fe-piattaforma/src/components/CardDocument/cardDocument.scss
+++ b/fe-piattaforma/src/components/CardDocument/cardDocument.scss
@@ -1,26 +1,74 @@
-.document-card {
- &__vertical {
- vertical-align: middle;
- margin-top: auto;
- margin-bottom: auto;
+.document-card-container {
+ width: 365px;
+ box-shadow: 0px 0px 80px rgba(0, 43, 85, 0.1);
+ border-radius: 4px;
+ @media screen and (max-width: 576px) {
+ box-shadow: 0px 0px 40px rgba(23, 50, 77, 0.08);
+ width: 292px;
}
- &__file-icon {
- max-width: 32px;
- max-height: 32px;
+ &__home-document-card {
+ height: 216px;
}
- &__maxLinesTitle {
- display: -webkit-box;
- -webkit-line-clamp: 1;
- -webkit-box-orient: vertical;
- overflow: hidden;
+ &__page-document-card {
+ height: 260px;
}
- &__maxLinesParagraph {
+ &__pre-title {
+ color: #455b71;
+ font-size: 16px;
+ font-weight: 400;
+ line-height: 24px;
+ letter-spacing: 1.1px;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ }
+ &__title {
+ font-size: 24px;
+ color: #1c2024;
+ line-height: 40px;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ }
+ &__description {
+ color: #455b71;
+ font-weight: 400;
+ font-size: 16px;
+ line-height: 24px;
+ height: 48px;
+ width: 252px;
+ overflow: hidden;
+ text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
+ }
+ &__authority {
+ color: #455b71;
overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ }
+ &__span-icons {
+ font-weight: 400;
+ line-height: 18px;
+ letter-spacing: 0.933333px;
+ }
+ &__date {
+ color: #455b71;
+ font-size: 16px;
+ font-weight: 400;
+ line-height: 24px;
+ letter-spacing: 1.1px;
+ padding-left: 6px;
+ }
+}
+@media screen and (max-width: 767px) {
+ .align-cards {
+ display: flex;
+ justify-content: center;
}
}
diff --git a/fe-piattaforma/src/components/CardDocument/cardDocument.tsx b/fe-piattaforma/src/components/CardDocument/cardDocument.tsx
index c621f664f..a6af1e278 100644
--- a/fe-piattaforma/src/components/CardDocument/cardDocument.tsx
+++ b/fe-piattaforma/src/components/CardDocument/cardDocument.tsx
@@ -1,18 +1,47 @@
import React, { memo } from 'react';
import './cardDocument.scss';
-import PDF from '/public/assets/img/pdf-icon-test.png';
-import MP4 from '/public/assets/img/mp4-icon-test.png';
+import iconFile from '../../../public/assets/img/icon-file-blue.png';
+/* import PDF from '/public/assets/img/pdf-icon-test.png';
+import MP4 from '/public/assets/img/mp4-icon-test.png';*/
+import { Col, Icon } from 'design-react-kit';
+import PublishingAuthority from './PublishingAuthority';
+import clsx from 'clsx';
+import { useAppSelector } from '../../redux/hooks';
+import { selectDevice } from '../../redux/features/app/appSlice';
+import { useNavigate } from 'react-router-dom';
+import { formatDate } from '../../utils/datesHelper';
+import { ForumCardsI } from '../CardShowcase/cardShowcase';
+/* import File from '/public/assets/img/icon-file-fill.png'; */
-interface CardDocumentI {
+/* interface CardDocumentI {
+ id?: string;
+ category_label?: string;
+ date?: string;
title?: string;
description?: string;
fileType?: string;
-}
+ entity?: string;
+ downloads?: number;
+ comment_count?: number;
+ isHome?: boolean;
+} */
-const CardDocument: React.FC = (props) => {
- const { title, description, fileType } = props;
+const CardDocument: React.FC = (props) => {
+ const {
+ id,
+ category_label,
+ date,
+ title,
+ description,
+ /* fileType, */ entity,
+ downloads,
+ comment_count,
+ isHome,
+ } = props;
- const getFileIcon = (type: string) => {
+ const device = useAppSelector(selectDevice);
+
+ /* const getFileIcon = (type: string) => {
switch (type) {
case 'PDF':
return PDF;
@@ -23,29 +52,108 @@ const CardDocument: React.FC = (props) => {
// case 'WORD':
default:
return '';
- }
+ }
+ }; */
+ const navigate = useNavigate();
+ const navigateTo = () => {
+ navigate(`/documenti/${id}`);
};
return (
-
-
-
-
- {fileType}
-
-
-
-
- {title}
-
-
- {description}
+
{
+ if (e.key === ' ') {
+ e.preventDefault();
+ navigateTo();
+ }
+ }}
+ tabIndex={0}
+ aria-label={`Categoria: ${category_label}. Data: ${
+ date && formatDate(date, 'shortDate')
+ }. Titolo documento: ${title}. Descrizione: ${description}. Editore: ${entity}. ${downloads} download. ${comment_count} ${
+ Number(comment_count) === 1 ? 'commento' : 'commenti'
+ }`}
+ >
+
+
+
+ {category_label}
+ {/* — */}
+
+
+
+ {title}
-
+
+
+
+ {description}
+
+
+
+ {!isHome ? (
+
+
+
+
+ {date && formatDate(date, 'shortDate')}
+
+
+
+
+ {downloads}
+
+
+
+ {comment_count}
+
+
+
+
+ ) : (
+
+
+ {date && formatDate(date, 'shortDate')}
+
+
+ )}
);
};
diff --git a/fe-piattaforma/src/components/CardProfile/cardProfile.tsx b/fe-piattaforma/src/components/CardProfile/cardProfile.tsx
index 4b1d13280..795836d86 100644
--- a/fe-piattaforma/src/components/CardProfile/cardProfile.tsx
+++ b/fe-piattaforma/src/components/CardProfile/cardProfile.tsx
@@ -4,22 +4,30 @@ import React, { memo } from 'react';
import { selectDevice } from '../../redux/features/app/appSlice';
import { useAppSelector } from '../../redux/hooks';
-import AvatarInitials, {
+import {
AvatarSizes,
AvatarTextSizes,
-} from '../AvatarInitials/avatarInitials';
+} from '../Avatar/AvatarInitials/avatarInitials';
import './cardProfile.scss';
+import { UserStateI } from '../../redux/features/user/userSlice';
+import UserAvatar from '../Avatar/UserAvatar/UserAvatar';
interface CardProfileI extends CardProps {
- name?: string;
- program?: string;
className?: string;
activeProfile?: boolean;
- user: { name: string; surname: string; role?: string };
+ user: UserStateI['user'];
+ profile?: any;
+ profilePicture?: string | undefined;
}
const CardProfile: React.FC
= (props) => {
- const { program, className, activeProfile, user } = props;
+ const {
+ className,
+ activeProfile,
+ user = {},
+ profile = {},
+ profilePicture,
+ } = props;
const device = useAppSelector(selectDevice);
@@ -38,14 +46,15 @@ const CardProfile: React.FC = (props) => {
className={clsx(
'ml-2',
'bg-white',
- 'px-2',
+ 'pr-2',
'py-3',
'h-100',
'd-flex',
'flex-row',
'align-items-center',
'justify-content-between',
- 'card-profile-container__white-card'
+ 'card-profile-container__white-card',
+ 'position-relative'
)}
>
= (props) => {
- ) : null}
+ ) : (
+
+ )}
-
- {activeProfile ? (
-
- Delegato
-
- {user.name}
+
+
+ {profile?.descrizioneRuolo}
+ {device.mediaIsPhone &&
}
+ {profile?.nomeEnte ? (
+
+ {` "${profile?.nomeEnte}" `}
-
- ) : (
-
- Referente
-
- {user.name}
-
-
- )}
+ ) : null}
+
- {program}
+ {profile?.nomeProgramma}
+ {profile?.nomeProgettoBreve
+ ? `, ${profile?.nomeProgettoBreve}`
+ : ''}
{activeProfile && (
-
+
void | undefined;
+ isHome?: boolean | undefined;
+ fileType?: string | undefined;
+ downloads?: number | undefined;
+ isDocument?: boolean | undefined;
+ isNews?: boolean | undefined;
+ isCommunity?: boolean | undefined;
+}
+
+const CardShowcase: React.FC = (props) => {
+ const {
+ id,
+ title,
+ description,
+ entity,
+ date,
+ likes,
+ comment_count,
+ cover,
+ category_label,
+ views,
+ highlighted,
+ } = props;
+
+ const device = useAppSelector(selectDevice);
+ const isMobile = device.mediaIsPhone;
+ const navigate = useNavigate();
+ const navigateTo = () => {
+ navigate(`/bacheca/${id}`);
+ };
+
+ return (
+ {
+ if (e.key === ' ') {
+ e.preventDefault();
+ navigateTo();
+ }
+ }}
+ onClick={navigateTo}
+ tabIndex={0}
+ aria-label={`Categoria: ${category_label}. Data: ${
+ date && formatDate(date, 'shortDate')
+ }. Titolo news: ${title}. Descrizione: ${description?.replace(
+ /<[^>]+>/g,
+ ''
+ )}. Editore: ${entity}. ${likes} like. ${comment_count} ${
+ Number(comment_count) === 1 ? 'commento' : 'commenti'
+ }. ${views} ${
+ Number(views) === 1 ? 'visualizzazione' : 'visualizzazioni'
+ }`}
+ >
+
+
+
+
+ {highlighted ? (
+
+
+
+ ) : null}
+
+
+
+ {category_label ? (
+
+
+ {category_label}
+ {/* — */}
+
+
+ ) : null}
+ {title ? (
+
+ {title}
+
+ ) : null}
+ {description ? (
+
+
+
+ ) : null}
+ {entity ? (
+
+ ) : (
+
+ )}
+
+
+
+ {date && formatDate(date, 'shortDate')}
+
+
+
+
+ {likes}
+
+
+
+
+ {comment_count}
+
+
+
+
+ {views}
+
+
+
+
+
+ );
+};
+
+export default CardShowcase;
diff --git a/fe-piattaforma/src/components/CardSlider/cardSlider.scss b/fe-piattaforma/src/components/CardSlider/cardSlider.scss
new file mode 100644
index 000000000..620d605ee
--- /dev/null
+++ b/fe-piattaforma/src/components/CardSlider/cardSlider.scss
@@ -0,0 +1,66 @@
+.card-slider-container {
+ height: 180px;
+ width: 100%;
+ background-color: #ffffff;
+ border: 1px solid #eceff1;
+ position: relative;
+
+ &__pre-title {
+ color: #455b71;
+ font-weight: 400;
+ font-size: 16px;
+ line-height: 24px;
+ letter-spacing: 1.1px;
+ text-align: start;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ @media screen and (max-width: 576px) {
+ width: 85%;
+ }
+ }
+ &__title {
+ font-size: 18px;
+ color: #1c2024;
+ text-align: left;
+ height: 65px;
+ p {
+ overflow: hidden;
+ text-overflow: ellipsis;
+ display: -webkit-box;
+ -webkit-line-clamp: 2;
+ -webkit-box-orient: vertical;
+ }
+ }
+ &__span-icons {
+ font-weight: 400;
+ line-height: 18px;
+ letter-spacing: 0.933333px;
+ }
+ &__date {
+ color: #455b71;
+ font-weight: 400;
+ font-size: 16px;
+ line-height: 24px;
+ letter-spacing: 1.1px;
+ }
+}
+
+.card-icons-rx {
+ position: absolute;
+ top: 60px;
+ right: -10px;
+ overflow: visible;
+}
+.card-icons-sx {
+ position: absolute;
+ top: 60px;
+ left: -10px;
+ overflow: visible;
+}
+
+.card-slider-mobile {
+ @media screen and (max-width: 1200px) {
+ overflow-x: unset;
+ }
+}
diff --git a/fe-piattaforma/src/components/CardSlider/cardSlider.tsx b/fe-piattaforma/src/components/CardSlider/cardSlider.tsx
new file mode 100644
index 000000000..2082f4c28
--- /dev/null
+++ b/fe-piattaforma/src/components/CardSlider/cardSlider.tsx
@@ -0,0 +1,147 @@
+import { Icon } from 'design-react-kit';
+import React from 'react';
+import './cardSlider.scss';
+import CuoreVuoto from '../../../public/assets/img/hollow-grey-heart.png';
+import clsx from 'clsx';
+import { useNavigate } from 'react-router-dom';
+import { formatDate } from '../../utils/datesHelper';
+import { ForumCardsI } from '../CardShowcase/cardShowcase';
+
+const CardSlider: React.FC = (props) => {
+ const {
+ id = '',
+ category_label,
+ date,
+ title,
+ downloads = '0',
+ comment_count = '0',
+ likes = '0',
+ views = '0',
+ isDocument = false,
+ isNews = false,
+ isCommunity = false,
+ /* rightArrow,
+ leftArrow,
+ increment,
+ decrement, */
+ } = props;
+ const navigate = useNavigate();
+
+ const navigateByType = () => {
+ if (id) {
+ if (isNews) {
+ navigate(`/bacheca/${id}`);
+ } else if (isCommunity) {
+ navigate(`/community/${id}`);
+ } else if (isDocument) {
+ navigate(`/documenti/${id}`);
+ }
+ }
+ };
+
+ return (
+ {
+ if (e.key === ' ') {
+ e.preventDefault();
+ navigateByType();
+ }
+ }}
+ onClick={navigateByType}
+ tabIndex={0}
+ className={clsx('card-slider-container', 'py-3', 'px-4')}
+ aria-label={`Categoria: ${category_label}. Data: ${
+ date && formatDate(date, 'shortDate')
+ }. Titolo ${
+ isDocument ? 'documento' : isNews ? 'news' : 'topic'
+ }: ${title}. ${likes} like. ${comment_count} ${
+ Number(comment_count) === 1 ? 'commento' : 'commenti'
+ }. ${downloads} download. ${views} ${
+ Number(views) === 1 ? 'visualizzazione' : 'visualizzazioni'
+ }`}
+ >
+
+
+
+ {category_label}
+ {/* — */}
+
+
+
+ {title}
+
+
+
+ {date && formatDate(date, 'shortDate')}
+
+
+ {!isDocument ? (
+
+
+
+ {likes}
+
+
+ ) : null}
+
+
+
+ {comment_count}
+
+
+ {isDocument ? (
+
+
+
+ {downloads}
+
+
+ ) : null}
+ {!isDocument ? (
+
+
+
+ {views}
+
+
+ ) : null}
+
+
+
+
+ );
+};
+
+export default CardSlider;
diff --git a/fe-piattaforma/src/components/CardStatusAction/cardStatusAction.scss b/fe-piattaforma/src/components/CardStatusAction/cardStatusAction.scss
index 99065dbad..04567f1ac 100644
--- a/fe-piattaforma/src/components/CardStatusAction/cardStatusAction.scss
+++ b/fe-piattaforma/src/components/CardStatusAction/cardStatusAction.scss
@@ -1,7 +1,7 @@
.card-status-action {
- border-radius: rem(10px);
- box-shadow: rem(0px) rem(0px) rem(80px) rgba(0, 43, 85, 0.1);
- padding: rem(24px);
+ border-radius: rem(5px);
+ box-shadow: rem(0px) rem(0px) rem(40px) rgba(0, 43, 85, 0.1);
+ padding: 0 rem(24px);
&__status-button {
border-radius: rem(5px);
@@ -14,6 +14,13 @@
justify-content: center;
}
+ .card-crud {
+ @media screen and (max-width: 1200px) {
+ right: 0;
+ top: 0;
+ }
+ }
+
.section-chip {
min-width: rem(112px);
}
@@ -22,6 +29,43 @@
}
&__title {
- min-width: rem(100px);
+ min-width: rem(200px);
+ max-width: rem(250px);
+ display: block;
}
}
+
+.active-role-border {
+ border-left: 8px solid #0066CC;
+}
+
+.partner-card {
+ &__title {
+ @media screen and (min-width: 600px) and (max-width: 1000px) {
+ min-width: rem(80px);
+ max-width: rem(120px);
+ }
+ }
+
+ &__content {
+ @media screen and (min-width: 600px) and (max-width: 1000px) {
+ padding-right: 0px !important;
+ }
+ }
+
+ &__margins {
+ @media screen and (min-width: 600px) and (max-width: 1000px) {
+ margin-right: 4px !important;
+ margin-left: 4px !important;
+ }
+ }
+}
+
+.status-action-width {
+ @media screen and (min-width: 770px) {
+ width: 33%
+ }
+ @media screen and (max-width: 770px) {
+ width: 100%
+ }
+}
\ No newline at end of file
diff --git a/fe-piattaforma/src/components/CardStatusAction/cardStatusAction.tsx b/fe-piattaforma/src/components/CardStatusAction/cardStatusAction.tsx
index 8bbd4bb43..c91734536 100644
--- a/fe-piattaforma/src/components/CardStatusAction/cardStatusAction.tsx
+++ b/fe-piattaforma/src/components/CardStatusAction/cardStatusAction.tsx
@@ -2,19 +2,19 @@ import clsx from 'clsx';
import {
Button,
CardReadMore,
- Chip,
- ChipLabel,
FormGroup,
Icon,
Label,
+ UncontrolledTooltip,
} from 'design-react-kit';
import React, { memo, useState, useEffect } from 'react';
import { useTranslation } from 'react-i18next';
import { CRUDActionsI, CRUDActionTypes } from '../../utils/common';
import { useAppSelector } from '../../redux/hooks';
import { selectDevice } from '../../redux/features/app/appSlice';
-import isEqual from 'lodash.isequal';
+// import isEqual from 'lodash.isequal';
import Input from '../Form/input';
+import StatusChip from '../StatusChip/statusChip';
const fieldMappedForTranslations: { [key: string]: string } = {
serviziErogati: 'provided_services',
@@ -22,23 +22,30 @@ const fieldMappedForTranslations: { [key: string]: string } = {
ente: 'body',
id: 'id',
ente_ref: 'ente_ref',
+ profilo: 'Profilo',
+ ruoli: 'Ruolo',
+ ref: 'Referenti',
+ progetto: 'Progetto',
+ programma: 'Programma',
};
interface CardStatusActionI {
- title: string;
+ title?: string | undefined;
subtitle?: string;
status?: string | undefined;
actionView?: boolean;
referente?: string;
fullInfo?:
| {
- [key: string]: string;
+ [key: string]: string | undefined;
}
| undefined;
onActionClick?: CRUDActionsI;
id?: string | undefined;
+ cf?: string | undefined;
moreThanOneSurvey?: boolean;
onCheckedChange?: (checked: string) => void;
+ activeRole?: boolean;
}
const CardStatusAction: React.FC = (props) => {
@@ -50,23 +57,11 @@ const CardStatusAction: React.FC = (props) => {
fullInfo,
onActionClick,
id,
+ cf,
moreThanOneSurvey = false,
onCheckedChange,
+ activeRole = false,
} = props;
-
- const getStatusLabel = (status: string) => {
- switch (status.toUpperCase()) {
- case 'COMPLETED':
- return 'COMPLETATO';
- case 'ACTIVE':
- case 'ATTIVO':
- return 'ATTIVO';
- case 'NOT_COMPLETED':
- return 'DA COMPLETARE';
- default:
- return status.toUpperCase;
- }
- };
const device = useAppSelector(selectDevice);
const [isChecked, setIsChecked] = useState('');
@@ -82,11 +77,12 @@ const CardStatusAction: React.FC = (props) => {
= (props) => {
{moreThanOneSurvey && (
setIsChecked(`${id}`)}
checked={isChecked === `radio${id}`}
/>
-
+
)}
-
-
- {title}
- {subtitle && {subtitle}}
-
+
+ {title || subtitle ? (
+
+
+ {title ? {title} : null}
+ {subtitle ? (
+ {subtitle}
+ ) : null}
+
+
+ ) : null}
+ {fullInfo && Object.keys(fullInfo).length ? (
+
+ {Object.keys(fullInfo).map((key, index) => {
+ if (!fullInfo[key]) return null;
+ return (
+
+
+ {t(fieldMappedForTranslations[key])}
+
+
+ {fullInfo[key] === null ? '---' : fullInfo[key]}
+
+
+ );
+ })}
+
+ ) : null}
-
- {fullInfo && Object.keys(fullInfo).length ? (
-
- {Object.keys(fullInfo).map((key, index) => {
- return (
-
-
- {t(fieldMappedForTranslations[key])}
-
-
- {fullInfo[key]}
-
-
- );
- })}
-
- ) : null}
-
+
{status && (
-
-
- {getStatusLabel(status)}
-
-
+ status={status}
+ rowTableId={id}
+ chipWidth
+ />
)}
{!device.mediaIsPhone && actionView && (
@@ -183,35 +229,63 @@ const CardStatusAction: React.FC
= (props) => {
/>
)}
- {device.mediaIsDesktop && onActionClick && id ? (
+ {onActionClick && id ? (
{onActionClick[CRUDActionTypes.DELETE] ? (
+ device.mediaIsPhone ? null : (
+ <>
+
+
+ Rimuovi
+
+ >
+ )
+ ) : null}
+ {onActionClick[CRUDActionTypes.VIEW] ? (
) : null}
- {onActionClick[CRUDActionTypes.VIEW] ? (
+ {onActionClick[CRUDActionTypes.PREVIEW] ? (
) : null}
@@ -223,7 +297,8 @@ const CardStatusAction: React.FC = (props) => {
);
};
-export default memo(CardStatusAction, (prevProps, currentProps) => {
- // TODO: check
- return !isEqual(prevProps, currentProps);
-});
+// export default memo(CardStatusAction, (prevProps, currentProps) => {
+// // TODO: check
+// return !isEqual(prevProps, currentProps);
+// });
+export default memo(CardStatusAction);
diff --git a/fe-piattaforma/src/components/CardStatusAction/cardStatusActionHeadquarters.tsx b/fe-piattaforma/src/components/CardStatusAction/cardStatusActionHeadquarters.tsx
new file mode 100644
index 000000000..ffbb315b2
--- /dev/null
+++ b/fe-piattaforma/src/components/CardStatusAction/cardStatusActionHeadquarters.tsx
@@ -0,0 +1,216 @@
+import clsx from 'clsx';
+import {
+ Button,
+ CardReadMore,
+ Icon,
+ UncontrolledTooltip,
+} from 'design-react-kit';
+import React from 'react';
+import { useTranslation } from 'react-i18next';
+import { CRUDActionsI, CRUDActionTypes } from '../../utils/common';
+import { useAppSelector } from '../../redux/hooks';
+import { selectDevice } from '../../redux/features/app/appSlice';
+import StatusChip from '../StatusChip/statusChip';
+
+const fieldMappedForTranslations: { [key: string]: string } = {
+ serviziErogati: 'provided_services',
+ nFacilitatori: 'nr_facilitators',
+ nVolontari: 'nr_volunteers',
+ id: 'id',
+ ente_ref: 'ente_ref',
+};
+
+interface CardStatusActionI {
+ title: string;
+ subtitle?: string;
+ status?: string | undefined;
+ actionView?: boolean;
+ referente?: string;
+ fullInfo?:
+ | {
+ [key: string]: string;
+ }
+ | undefined;
+ onActionClick?: CRUDActionsI;
+ id?: string | undefined;
+ moreThanOneSurvey?: boolean;
+ onCheckedChange?: (checked: string) => void;
+}
+
+const CardStatusActionHeadquarters: React.FC = (props) => {
+ const { title, subtitle, status, actionView, fullInfo, onActionClick, id } =
+ props;
+ const device = useAppSelector(selectDevice);
+
+ const { t } = useTranslation();
+
+ return (
+
+
+
+
+ {title}
+ {subtitle && {subtitle}}
+
+
+
+
+
+ {status && (
+
+ )}
+
+ {!device.mediaIsPhone && actionView && (
+
+ )}
+
+ {onActionClick && id ? (
+
+ {onActionClick[CRUDActionTypes.DELETE] ? (
+ device.mediaIsPhone ? null : (
+ <>
+
+
+ Rimuovi
+
+ >
+ )
+ ) : null}
+ {onActionClick[CRUDActionTypes.VIEW] ? (
+
+ ) : null}
+ {onActionClick[CRUDActionTypes.PREVIEW] ? (
+
+ ) : null}
+
+ ) : null}
+
+
+
+ {fullInfo && Object.keys(fullInfo).length ? (
+
+ {Object.keys(fullInfo).map((key, index) => {
+ return (
+
+
+ {t(fieldMappedForTranslations[key])}
+
+
+ {fullInfo[key] === null ? '---' : fullInfo[key]}
+
+
+ );
+ })}
+
+ ) : null}
+
+
+ );
+};
+
+// export default memo(CardStatusAction, (prevProps, currentProps) => {
+// // TODO: check
+// return !isEqual(prevProps, currentProps);
+// });
+export default CardStatusActionHeadquarters;
diff --git a/fe-piattaforma/src/components/CardStatusAction/cardStatusActionPartnerAuthority.tsx b/fe-piattaforma/src/components/CardStatusAction/cardStatusActionPartnerAuthority.tsx
new file mode 100644
index 000000000..4345d48c3
--- /dev/null
+++ b/fe-piattaforma/src/components/CardStatusAction/cardStatusActionPartnerAuthority.tsx
@@ -0,0 +1,219 @@
+import clsx from 'clsx';
+import {
+ Button,
+ CardReadMore,
+ Icon,
+ UncontrolledTooltip,
+} from 'design-react-kit';
+import React from 'react';
+import { useTranslation } from 'react-i18next';
+import { CRUDActionsI, CRUDActionTypes } from '../../utils/common';
+import { useAppSelector } from '../../redux/hooks';
+import { selectDevice } from '../../redux/features/app/appSlice';
+import StatusChip from '../StatusChip/statusChip';
+
+const fieldMappedForTranslations: { [key: string]: string } = {
+ ref: 'Referente',
+};
+
+interface CardStatusActionI {
+ title: string;
+ subtitle?: string;
+ status?: string | undefined;
+ actionView?: boolean;
+ referente?: string;
+ fullInfo?:
+ | {
+ [key: string]: string;
+ }
+ | undefined;
+ onActionClick?: CRUDActionsI;
+ id?: string | undefined;
+}
+
+const CardStatusActionPartnerAuthority: React.FC = (
+ props
+) => {
+ const { title, subtitle, status, actionView, fullInfo, onActionClick, id } =
+ props;
+ const device = useAppSelector(selectDevice);
+ const { t } = useTranslation();
+
+ return (
+
+
+
+
+
+ {title}
+ {subtitle && (
+ {subtitle}
+ )}
+
+
+
+
+ {fullInfo && Object.keys(fullInfo).length ? (
+
+ {Object.keys(fullInfo).map((key, index) => {
+ return (
+
+
+ {t(fieldMappedForTranslations[key])}
+
+
+ {fullInfo[key] === null
+ ? '---'
+ : fullInfo[key].toString().replaceAll(',', ', ')}
+
+
+ );
+ })}
+
+ ) : null}
+
+
+
+ {status && (
+
+ )}
+
+
+
+ {actionView && (
+
+ )}
+
+ {onActionClick && id ? (
+
+ {onActionClick[CRUDActionTypes.DELETE] ? (
+ device.mediaIsPhone ? null : (
+ <>
+
+
+ Rimuovi
+
+ >
+ )
+ ) : null}
+ {onActionClick[CRUDActionTypes.VIEW] ? (
+
+ ) : null}
+ {onActionClick[CRUDActionTypes.PREVIEW] ? (
+
+ ) : null}
+
+ ) : null}
+
+
+ );
+};
+
+export default CardStatusActionPartnerAuthority;
diff --git a/fe-piattaforma/src/components/CardStatusAction/cardStatusActionProject.tsx b/fe-piattaforma/src/components/CardStatusAction/cardStatusActionProject.tsx
new file mode 100644
index 000000000..535134ab4
--- /dev/null
+++ b/fe-piattaforma/src/components/CardStatusAction/cardStatusActionProject.tsx
@@ -0,0 +1,204 @@
+import clsx from 'clsx';
+import {
+ Button,
+ CardReadMore,
+ Icon,
+ UncontrolledTooltip,
+} from 'design-react-kit';
+import React from 'react';
+import { useTranslation } from 'react-i18next';
+import { CRUDActionsI, CRUDActionTypes } from '../../utils/common';
+import { useAppSelector } from '../../redux/hooks';
+import { selectDevice } from '../../redux/features/app/appSlice';
+import StatusChip from '../StatusChip/statusChip';
+
+const fieldMappedForTranslations: { [key: string]: string } = {
+ id: 'id',
+};
+
+interface CardStatusActionI {
+ title: string;
+ subtitle?: string;
+ status?: string | undefined;
+ actionView?: boolean;
+ referente?: string;
+ fullInfo?:
+ | {
+ [key: string]: string;
+ }
+ | undefined;
+ onActionClick?: CRUDActionsI;
+ id?: string | undefined;
+}
+
+const CardStatusActionProject: React.FC = (props) => {
+ const { title, subtitle, status, actionView, fullInfo, onActionClick, id } =
+ props;
+ const device = useAppSelector(selectDevice);
+ const { t } = useTranslation();
+
+ return (
+
+
+
+
+
+ {title}
+ {subtitle && (
+ {subtitle}
+ )}
+
+
+
+
+ {fullInfo && Object.keys(fullInfo).length ? (
+
+ {Object.keys(fullInfo).map((key, index) => {
+ return (
+
+
+ {t(fieldMappedForTranslations[key])}
+
+
+ {fullInfo[key] === null ? '---' : fullInfo[key]}
+
+
+ );
+ })}
+
+ ) : null}
+
+
+
+ {status && (
+
+ )}
+
+
+
+ {actionView && (
+
+ )}
+
+ {onActionClick && id ? (
+
+ {onActionClick[CRUDActionTypes.DELETE] ? (
+ device.mediaIsPhone ? null : (
+ <>
+
+
+ Rimuovi
+
+ >
+ )
+ ) : null}
+ {onActionClick[CRUDActionTypes.VIEW] ? (
+
+ ) : null}
+ {onActionClick[CRUDActionTypes.PREVIEW] ? (
+
+ ) : null}
+
+ ) : null}
+
+
+ );
+};
+
+export default CardStatusActionProject;
diff --git a/fe-piattaforma/src/components/CardStatusAction/cardStatusActionSurveys.tsx b/fe-piattaforma/src/components/CardStatusAction/cardStatusActionSurveys.tsx
new file mode 100644
index 000000000..25089553e
--- /dev/null
+++ b/fe-piattaforma/src/components/CardStatusAction/cardStatusActionSurveys.tsx
@@ -0,0 +1,248 @@
+import clsx from 'clsx';
+import {
+ Button,
+ CardReadMore,
+ Icon,
+ Label,
+ UncontrolledTooltip,
+} from 'design-react-kit';
+import React, { useState, useEffect } from 'react';
+import { useTranslation } from 'react-i18next';
+import { CRUDActionsI, CRUDActionTypes } from '../../utils/common';
+import { useAppSelector } from '../../redux/hooks';
+import { selectDevice } from '../../redux/features/app/appSlice';
+import Input from '../Form/input';
+import StatusChip from '../StatusChip/statusChip';
+
+const fieldMappedForTranslations: { [key: string]: string } = {
+ serviziErogati: 'provided_services',
+ nFacilitatori: 'nr_facilitators',
+ ente: 'body',
+ id: 'id',
+ ente_ref: 'ente_ref',
+};
+
+interface CardStatusActionI {
+ title: string;
+ subtitle?: string;
+ status?: string | undefined;
+ actionView?: boolean;
+ referente?: string;
+ fullInfo?:
+ | {
+ [key: string]: string;
+ }
+ | undefined;
+ onActionClick?: CRUDActionsI;
+ id?: string | undefined;
+ moreThanOneSurvey?: boolean;
+ onCheckedChange?: (checked: string) => void;
+}
+
+const CardStatusActionSurveys: React.FC = (props) => {
+ const {
+ title,
+ subtitle,
+ status,
+ actionView,
+ fullInfo,
+ onActionClick,
+ id,
+ moreThanOneSurvey = false,
+ onCheckedChange,
+ } = props;
+ const device = useAppSelector(selectDevice);
+ const [isChecked, setIsChecked] = useState('');
+
+ useEffect(() => {
+ if (onCheckedChange) {
+ onCheckedChange(isChecked);
+ }
+ }, [isChecked]);
+
+ const { t } = useTranslation();
+
+ return (
+
+ {moreThanOneSurvey && (
+
+ setIsChecked(`${id}`)}
+ checked={isChecked === `radio${id}`}
+ />
+
+
+ )}
+
+
+
+
+ {title}
+ {subtitle && (
+ {subtitle}
+ )}
+
+
+
+
+ {fullInfo && Object.keys(fullInfo).length ? (
+
+ {Object.keys(fullInfo).map((key, index) => {
+ return (
+
+
+ {t(fieldMappedForTranslations[key])}
+
+
+ {fullInfo[key] === null ? '---' : fullInfo[key]}
+
+
+ );
+ })}
+
+ ) : null}
+
+
+
+ {status && (
+
+ )}
+
+
+
+ {actionView && (
+
+ )}
+
+ {onActionClick && id ? (
+
+ {onActionClick[CRUDActionTypes.DELETE] ? (
+ device.mediaIsPhone ? null : (
+ <>
+
+
+ Rimuovi
+
+ >
+ )
+ ) : null}
+ {onActionClick[CRUDActionTypes.VIEW] ? (
+
+ ) : null}
+ {onActionClick[CRUDActionTypes.PREVIEW] ? (
+
+ ) : null}
+
+ ) : null}
+
+
+ );
+};
+
+// export default memo(CardStatusAction, (prevProps, currentProps) => {
+// // TODO: check
+// return !isEqual(prevProps, currentProps);
+// });
+export default CardStatusActionSurveys;
diff --git a/fe-piattaforma/src/components/Comments/answersSection.tsx b/fe-piattaforma/src/components/Comments/answersSection.tsx
new file mode 100644
index 000000000..e8f3a86da
--- /dev/null
+++ b/fe-piattaforma/src/components/Comments/answersSection.tsx
@@ -0,0 +1,79 @@
+import clsx from 'clsx';
+import React from 'react';
+import { useDispatch } from 'react-redux';
+import { selectDevice } from '../../redux/features/app/appSlice';
+import { openModal } from '../../redux/features/modal/modalSlice';
+import { useAppSelector } from '../../redux/hooks';
+import { CommentI } from './comment';
+import CommentAnswer from './commentAnswer';
+
+interface AnswerSectionI {
+ replies?: CommentI[];
+ thread?: boolean;
+ showReplies?: boolean;
+}
+
+const AnswersSection: React.FC = (props) => {
+ const { thread, showReplies, replies = [] } = props;
+ const device = useAppSelector(selectDevice);
+
+ const dispatch = useDispatch();
+
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
+ // @ts-ignore
+ if (replies === '[]') return null;
+
+ return (
+
+ {showReplies && (
+
+ {(replies || []).map((comment, index: number) => (
+ 1 && index < replies.length - 1}
+ onDeleteComment={() =>
+ dispatch(
+ openModal({
+ id: 'delete-forum-entity',
+ payload: {
+ text: 'Confermi di voler eliminare questo contenuto?',
+ entity: 'comment',
+ id: comment.id,
+ author: comment.author,
+ textLabel: "Inserisci il motivo dell'eliminazione",
+ },
+ })
+ )
+ }
+ onEditComment={() =>
+ dispatch(
+ openModal({
+ id: 'comment-modal',
+ payload: {
+ title: 'Modifica commento',
+ action: 'edit',
+ id: comment.id,
+ body: comment.body,
+ textLabel: 'Digita qui sotto il testo',
+ },
+ })
+ )
+ }
+ />
+ ))}
+
+ )}
+
+ );
+};
+
+export default AnswersSection;
diff --git a/fe-piattaforma/src/components/Comments/comment.scss b/fe-piattaforma/src/components/Comments/comment.scss
new file mode 100644
index 000000000..7ad9e5bce
--- /dev/null
+++ b/fe-piattaforma/src/components/Comments/comment.scss
@@ -0,0 +1,80 @@
+.comment-container {
+ &__comment-card {
+ padding: 0px rem(10px);
+ }
+
+ &__social-bar {
+ gap: rem(30px);
+ }
+
+ &__border {
+ opacity: 0.3;
+ border-bottom: 0.5px solid #3686d6;
+ }
+
+ &__comment-dropdown {
+ button {
+ padding: 5px;
+ color: #ffffff;
+ border: none;
+ }
+ button:hover {
+ border: none;
+ background-color: #ffffff;
+ box-shadow: none;
+ }
+
+ &__option {
+ cursor: pointer;
+ }
+ }
+
+ &__answer {
+ padding-left: rem(32px);
+ background: rgba(242, 246, 250, 0.5);
+ }
+
+ &__thread {
+ border-left: 2px dashed rgba(121, 124, 128, 0.4);
+ }
+ /*
+
+this animation in now commented, the intent is to keep it, but it needs some work to do.
+
+ .answer-div {
+ max-height: 0;
+ }
+
+ .answer-box {
+ top: 0;
+ left: 0;
+ bottom: 0;
+ width: 300px;
+ height: 100vh;
+ z-index: 100;
+ transform: translateY(-100%);
+ transition: all 0.75s;
+ position: fixed;
+ }
+
+ .show-answer-box {
+ transform: translateY(0%);
+ } */
+}
+
+.letter-spacing {
+ letter-spacing: 1px;
+}
+.border-bottom-box-answer {
+ opacity: 0.3;
+ border: 0.5px solid #3686d6;
+ width: 97%;
+}
+.border-bottom-box-comments {
+ opacity: 0.7;
+ border: 1px solid #979797;
+}
+.left-alignment {
+ margin-left: 30px;
+ padding-left: 40px;
+}
\ No newline at end of file
diff --git a/fe-piattaforma/src/components/Comments/comment.tsx b/fe-piattaforma/src/components/Comments/comment.tsx
new file mode 100644
index 000000000..79c42b20f
--- /dev/null
+++ b/fe-piattaforma/src/components/Comments/comment.tsx
@@ -0,0 +1,388 @@
+import {
+ Button,
+ Dropdown,
+ DropdownMenu,
+ DropdownToggle,
+ Icon,
+ LinkList,
+} from 'design-react-kit';
+import React, { useEffect, useState } from 'react';
+
+import clsx from 'clsx';
+import AnswersSection from './answersSection';
+import SocialBar from './socialBar';
+import { useAppSelector } from '../../redux/hooks';
+import { selectDevice } from '../../redux/features/app/appSlice';
+import { useDispatch } from 'react-redux';
+import { openModal } from '../../redux/features/modal/modalSlice';
+import AvatarInitials, {
+ AvatarSizes,
+ AvatarTextSizes,
+} from '../Avatar/AvatarInitials/avatarInitials';
+import {
+ GetCommentsList,
+ ManageCommentEvent,
+} from '../../redux/features/forum/comments/commentsThunk';
+import { useParams } from 'react-router-dom';
+import { selectUser } from '../../redux/features/user/userSlice';
+import {
+ getAnagraphicID,
+ selectAnagraphics,
+} from '../../redux/features/anagraphic/anagraphicSlice';
+import { formatDate } from '../../utils/datesHelper';
+import useGuard from '../../hooks/guard';
+
+export interface CommentI {
+ id?: string | undefined;
+ body: string | undefined;
+ date: string | undefined;
+ author?: string;
+ likes: number;
+ user_like?: boolean;
+ views?: number;
+ replies: any[];
+ isAnswer?: boolean;
+ thread?: boolean;
+ noBorder?: boolean;
+ section: 'board' | 'community' | 'documents';
+ onDeleteComment?: () => void;
+ onEditComment?: () => void;
+ reported: 0 | 1;
+ isReply?: boolean;
+}
+
+const Comment: React.FC = (props) => {
+ const {
+ body,
+ date,
+ author,
+ section,
+ replies = [],
+ likes,
+ user_like,
+ views,
+ id,
+ isAnswer,
+ thread = false,
+ onDeleteComment = () => ({}),
+ onEditComment = () => ({}),
+ reported = 0,
+ isReply = false,
+ } = props;
+
+ const [detailDropdownOptions, setDetailDropdownOptions] = useState([]);
+ const [isOpen, setIsOpen] = useState(false);
+ const [showReplies, setShowReplies] = useState(false);
+ const device = useAppSelector(selectDevice);
+ const dispatch = useDispatch();
+ const { hasUserPermission } = useGuard();
+ const [isReported, setIsReported] = useState(reported === 1);
+
+ useEffect(() => {
+ setIsReported(reported === 1 && hasUserPermission(['btn.rprt']));
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [reported]);
+
+ const { id: itemId } = useParams();
+ const userId = useAppSelector(selectUser)?.id;
+
+ const authorAnagraphic = useAppSelector(selectAnagraphics)[author || 0] || {
+ nome: 'Utente',
+ cognome: 'Anonimo',
+ };
+
+ const deleteOption = {
+ optionName: 'ELIMINA',
+ DropdownIcon: {
+ icon: 'it-delete',
+ color: 'primary',
+ },
+ action: onDeleteComment,
+ };
+
+ const editOption = {
+ optionName: 'MODIFICA',
+ DropdownIcon: {
+ icon: 'it-pencil',
+ color: 'primary',
+ },
+ action: onEditComment,
+ };
+
+ const reportOption = {
+ optionName: 'SEGNALA',
+ DropdownIcon: {
+ icon: 'it-error',
+ color: 'danger',
+ },
+ action: () => {
+ dispatch(
+ openModal({
+ id: 'report-modal',
+ payload: {
+ entity: 'comment',
+ id: id,
+ },
+ })
+ );
+ },
+ };
+
+ const setDetailDropdownOptionsByPermission = () => {
+ const authorizedOption = [];
+ if (
+ hasUserPermission([
+ section === 'board'
+ ? 'del.news'
+ : section === 'community'
+ ? 'del.topic'
+ : section === 'documents'
+ ? 'del.doc'
+ : 'hidden',
+ ]) ||
+ author?.toString() === userId?.toString()
+ ) {
+ authorizedOption.push(deleteOption);
+ }
+ if (
+ hasUserPermission([
+ section === 'board'
+ ? 'upd.news'
+ : section === 'community'
+ ? 'upd.topic'
+ : section === 'documents'
+ ? 'upd.doc'
+ : 'hidden',
+ ]) ||
+ author?.toString() === userId?.toString()
+ ) {
+ authorizedOption.push(editOption);
+ }
+ if (
+ hasUserPermission([
+ section === 'board'
+ ? 'rprt.news'
+ : section === 'community'
+ ? 'rprt.topic'
+ : section === 'documents'
+ ? 'rprt.doc'
+ : 'hidden',
+ ])
+ ) {
+ authorizedOption.push(reportOption);
+ }
+ setDetailDropdownOptions(authorizedOption);
+ };
+
+ useEffect(() => {
+ setDetailDropdownOptionsByPermission();
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, []);
+
+ useEffect(() => {
+ if (author && !authorAnagraphic?.id) {
+ dispatch(getAnagraphicID({ id: author }));
+ }
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [authorAnagraphic]);
+
+ const commentDropdown = () =>
+ detailDropdownOptions?.length ? (
+ setIsOpen(!isOpen)}
+ >
+
+
+
+
+
+
+
+ {detailDropdownOptions.map((item, i) => (
+ setIsOpen(!isOpen)}>
+
+
+ ))}
+
+
+
+ ) : null;
+
+ return (
+
+
+
+
+
+
+
+ {authorAnagraphic?.nome} {authorAnagraphic?.cognome}
+
+ {' — '}
+ {date && formatDate(date, 'dateTime')}
+
+
+
+
+ {isReported ? : null}
+ {commentDropdown()}
+
+ {/* comment heading ^^^^ */}
+
+
+
{body}
+
+
setShowReplies((prev) => !prev)
+ : undefined
+ }
+ isReply={isReply}
+ showReplies={section === 'community' ? showReplies : undefined}
+ likes={likes}
+ user_like={user_like}
+ onLike={async () => {
+ if (id) {
+ if (user_like as boolean) {
+ await dispatch(ManageCommentEvent(id, 'unlike'));
+ } else {
+ await dispatch(ManageCommentEvent(id, 'like'));
+ }
+
+ itemId && userId && dispatch(GetCommentsList(itemId, userId));
+ }
+ }}
+ onComment={
+ section === 'community'
+ ? () =>
+ dispatch(
+ openModal({
+ id: 'comment-modal',
+ payload: {
+ title: 'Aggiungi risposta al commento',
+ action: 'reply',
+ id: id,
+ textLabel: 'Digita qui sotto il testo',
+ },
+ })
+ )
+ : undefined
+ }
+ />
+
+
+ {/* conditional will be added one we have the comment array to let this be rendered only when the length is > 0
+ AnswerSection will take an Array in input to let the .map() render the answers which are now mocked in the component itself
+ */}
+
+
+ );
+};
+
+export default Comment;
diff --git a/fe-piattaforma/src/components/Comments/commentAnswer.tsx b/fe-piattaforma/src/components/Comments/commentAnswer.tsx
new file mode 100644
index 000000000..c32f3b9e7
--- /dev/null
+++ b/fe-piattaforma/src/components/Comments/commentAnswer.tsx
@@ -0,0 +1,235 @@
+import clsx from 'clsx';
+import {
+ Button,
+ Dropdown,
+ DropdownMenu,
+ DropdownToggle,
+ Icon,
+ LinkList,
+} from 'design-react-kit';
+import React, { useEffect, useState } from 'react';
+import { useDispatch } from 'react-redux';
+import {
+ getAnagraphicID,
+ selectAnagraphics,
+} from '../../redux/features/anagraphic/anagraphicSlice';
+import { selectDevice } from '../../redux/features/app/appSlice';
+import { openModal } from '../../redux/features/modal/modalSlice';
+import { useAppSelector } from '../../redux/hooks';
+import { formatDate } from '../../utils/datesHelper';
+import AvatarInitials, {
+ AvatarSizes,
+ AvatarTextSizes,
+} from '../Avatar/AvatarInitials/avatarInitials';
+
+import { CommentI } from './comment';
+
+const CommentAnswer: React.FC = (props) => {
+ const {
+ author,
+ body,
+ date,
+ id,
+ noBorder = false,
+ onEditComment = () => ({}),
+ onDeleteComment = () => ({}),
+ } = props;
+
+ const [isOpen, setIsOpen] = useState(false);
+ const dispatch = useDispatch();
+ const device = useAppSelector(selectDevice);
+
+ const authorAnagraphic = useAppSelector(selectAnagraphics)[author || 0] || {
+ nome: 'Utente',
+ cognome: 'Anonimo',
+ };
+
+ useEffect(() => {
+ if (author && !authorAnagraphic?.id) {
+ dispatch(getAnagraphicID({ id: author }));
+ }
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [authorAnagraphic]);
+
+ const commentDropdownOptions = [
+ {
+ optionName: 'ELIMINA',
+ DropdowniIcon: {
+ icon: 'it-delete',
+ color: 'primary',
+ },
+ action: () => onDeleteComment(),
+ },
+ {
+ optionName: 'MODIFICA',
+ DropdowniIcon: {
+ icon: 'it-pencil',
+ color: 'primary',
+ },
+ action: () => onEditComment(),
+ },
+ {
+ optionName: 'SEGNALA',
+ DropdowniIcon: {
+ icon: 'it-error',
+ color: 'danger',
+ },
+ action: () =>
+ dispatch(
+ openModal({
+ id: 'report-modal',
+ payload: {
+ entity: 'comment',
+ id: id,
+ },
+ })
+ ),
+ },
+ ];
+
+ /*
+ funzione da legare alla modale con annesse chiamate API per aggiornare il campo
+
+ const editComment = () => {
+
+ }
+ */
+
+ /* const reportComment = () => {
+ commentArray.filter((singleComment: CommentI) => singleComment.id !== id)
+ if ( singleComment.id === id ) {
+ setIsReported(true)
+ }
+ } */
+
+ /* const deleteComment = () => {
+ commentArray.filter((singleComment: CommentI) => singleComment.id !== id)
+ if ( singleComment.id === id ) {
+ commentArray.pop(singleComment);
+ } */
+
+ const commentDropdown = () => (
+ setIsOpen(!isOpen)}
+ >
+
+
+
+
+
+
+
+ {commentDropdownOptions.map((item, i) => (
+ setIsOpen(!isOpen)}>
+
+
+ ))}
+
+
+
+ );
+ return (
+
+
+
+
+
+
+
+ {authorAnagraphic?.nome} {authorAnagraphic?.cognome}
+ {' '}
+ {' — '}
+ {date && formatDate(date, 'shortDate')}
+
+
+
+
+ {/* {isReported && } */}
+ {commentDropdown()}
+
+ {/* comment heading ^^^^ */}
+
+
+ {body}
+
+ {noBorder &&
}
+ {/* conditional will be added one we have the comment array to let this be rendered only when the length is > 0
+ AnswerSection will take an Array in input to let the .map() render the answers which are now mocked in the component itself
+ */}
+
+ );
+};
+
+export default CommentAnswer;
diff --git a/fe-piattaforma/src/components/Comments/commentSection.tsx b/fe-piattaforma/src/components/Comments/commentSection.tsx
new file mode 100644
index 000000000..814b21739
--- /dev/null
+++ b/fe-piattaforma/src/components/Comments/commentSection.tsx
@@ -0,0 +1,66 @@
+import clsx from 'clsx';
+import React from 'react';
+import { useDispatch } from 'react-redux';
+import { selectCommentsList } from '../../redux/features/forum/forumSlice';
+import { openModal } from '../../redux/features/modal/modalSlice';
+import { useAppSelector } from '../../redux/hooks';
+import SectionTitle from '../SectionTitle/sectionTitle';
+import Comment from './comment';
+
+interface commentSectionI {
+ section: 'board' | 'community' | 'documents';
+}
+
+const CommentSection: React.FC = ({ section }) => {
+ const comments = useAppSelector(selectCommentsList);
+ const dispatch = useDispatch();
+
+ return (
+
+
+
+
+ {comments.map((comment, i) => (
+
1 && i < comments.length - 1}
+ isReply={true}
+ {...comment}
+ onDeleteComment={() =>
+ dispatch(
+ openModal({
+ id: 'delete-forum-entity',
+ payload: {
+ text: 'Confermi di voler eliminare questo contenuto?',
+ entity: 'comment',
+ id: comment.id,
+ author: comment.author,
+ textLabel: "Inserisci il motivo dell'eliminazione",
+ },
+ })
+ )
+ }
+ onEditComment={() =>
+ dispatch(
+ openModal({
+ id: 'comment-modal',
+ payload: {
+ title: 'Modifica commento',
+ action: 'edit',
+ id: comment.id,
+ body: comment.body,
+ textLabel: 'Digita qui sotto il testo',
+ },
+ })
+ )
+ }
+ />
+ ))}
+
+ );
+};
+
+export default CommentSection;
diff --git a/fe-piattaforma/src/components/Comments/socialBar.tsx b/fe-piattaforma/src/components/Comments/socialBar.tsx
new file mode 100644
index 000000000..371d09955
--- /dev/null
+++ b/fe-piattaforma/src/components/Comments/socialBar.tsx
@@ -0,0 +1,211 @@
+import React from 'react';
+import { Button, Icon } from 'design-react-kit';
+import CuoreVuoto from '../../../public/assets/img/hollow-grey-heart.png';
+import CuoreBluVuoto from '../../../public/assets/img/hollow-blue-heart.png';
+import CuoreBluPieno from '../../../public/assets/img/filled-blue-heart.png';
+import clsx from 'clsx';
+import { useAppSelector } from '../../redux/hooks';
+import { selectDevice } from '../../redux/features/app/appSlice';
+
+export interface SocialI {
+ onLike?: (() => void) | undefined;
+ onComment?: (() => void) | undefined;
+ views?: number | undefined;
+ likes?: number | undefined;
+ comments?: number | undefined;
+ replies?: number | undefined;
+ downloads?: number | undefined;
+ showReplies?: boolean | undefined;
+ user_like?: boolean | undefined;
+ onShowReplies?: (() => void) | undefined;
+ isReply?: boolean;
+}
+
+const SocialBar: React.FC = (props) => {
+ const {
+ showReplies,
+ onShowReplies,
+ onLike,
+ onComment,
+ views,
+ likes,
+ comments,
+ user_like,
+ downloads,
+ replies,
+ isReply = false,
+ } = props;
+
+ const device = useAppSelector(selectDevice);
+
+ return (
+
+
+
+ {likes !== undefined ? (
+
+ ) : null}
+ {comments !== undefined ? (
+
+ ) : null}
+ {views !== undefined ? (
+
+ ) : null}
+ {downloads !== undefined ? (
+
+ ) : null}
+
+
+ {onLike ? (
+
+ ) : null}
+
+ {onComment ? (
+
+ ) : null}
+
+
+ {onShowReplies ? (
+
+
+
+ ) : null}
+
+ );
+};
+
+export default SocialBar;
diff --git a/fe-piattaforma/src/components/ConfirmItemCreation/confirmItemCreation.tsx b/fe-piattaforma/src/components/ConfirmItemCreation/confirmItemCreation.tsx
new file mode 100644
index 000000000..e4bc5be23
--- /dev/null
+++ b/fe-piattaforma/src/components/ConfirmItemCreation/confirmItemCreation.tsx
@@ -0,0 +1,26 @@
+import clsx from 'clsx';
+import React from 'react';
+import BigCheckGreen from '../../../public/assets/img/green-check-circle.png';
+
+interface ConfirmModalI {
+ description?: string;
+}
+const ConfirmItemCreation: React.FC = ({ description }) => {
+ return (
+
+
+
+
{description}
+
+ );
+};
+
+export default ConfirmItemCreation;
diff --git a/fe-piattaforma/src/components/Curtain/curtain.scss b/fe-piattaforma/src/components/Curtain/curtain.scss
index 7a9bef6e2..d79ac311f 100644
--- a/fe-piattaforma/src/components/Curtain/curtain.scss
+++ b/fe-piattaforma/src/components/Curtain/curtain.scss
@@ -1,6 +1,7 @@
.curtain-wrapper {
top: 0;
left: 0;
+ right: 0;
background-color: rgba(51, 51, 51, 0.5);
z-index: $z-index-curtain;
}
diff --git a/fe-piattaforma/src/components/Curtain/curtain.tsx b/fe-piattaforma/src/components/Curtain/curtain.tsx
index 7eef2998d..4fe782fa7 100644
--- a/fe-piattaforma/src/components/Curtain/curtain.tsx
+++ b/fe-piattaforma/src/components/Curtain/curtain.tsx
@@ -5,7 +5,7 @@ import ReactDOM from 'react-dom';
interface CurtainI {
open: boolean;
noscroll: boolean;
- onClick: () => void;
+ onClick?: () => void;
}
const Curtain: React.FC = (props) => {
@@ -16,16 +16,16 @@ const Curtain: React.FC = (props) => {
return null;
}
- // if (!noscroll) {
- // return null;
- // }
+ const handleOnClick = () => {
+ if (onClick) onClick();
+ };
return ReactDOM.createPortal(
// eslint-disable-next-line jsx-a11y/no-noninteractive-element-interactions
{children}
diff --git a/fe-piattaforma/src/components/DetailCard/detailCard.scss b/fe-piattaforma/src/components/DetailCard/detailCard.scss
new file mode 100644
index 000000000..4b7b9f811
--- /dev/null
+++ b/fe-piattaforma/src/components/DetailCard/detailCard.scss
@@ -0,0 +1,23 @@
+.detail-card-container {
+ width: auto;
+
+ .icon-it-pa-container {
+ border-radius: 100%;
+ background-color: #d1e7ff;
+ min-width: 101px;
+ height: 101px;
+
+ &__phone {
+ border-radius: 100%;
+ background-color: #d1e7ff;
+ min-width: 49px;
+ height: 49px;
+ }
+ &__community {
+ border-radius: 100%;
+ background-color: #d1e7ff;
+ min-width: 59px;
+ height: 59px;
+ }
+ }
+}
diff --git a/fe-piattaforma/src/components/DetailCard/detailCard.tsx b/fe-piattaforma/src/components/DetailCard/detailCard.tsx
new file mode 100644
index 000000000..460841a9f
--- /dev/null
+++ b/fe-piattaforma/src/components/DetailCard/detailCard.tsx
@@ -0,0 +1,110 @@
+import React from 'react';
+import { Icon } from 'design-react-kit';
+import clsx from 'clsx';
+import { selectDevice } from '../../redux/features/app/appSlice';
+import { useAppSelector } from '../../redux/hooks';
+
+export interface DetailCardI {
+ isCommunity?: boolean | undefined;
+ entity?: string | undefined;
+ entity_type?: string | undefined;
+ program_label?: string | undefined;
+ intervention?: string | undefined;
+}
+
+const DetailCard: React.FC
= (props) => {
+ const { isCommunity, intervention, program_label, entity, entity_type } =
+ props;
+ const device = useAppSelector(selectDevice);
+ return (
+
+
+
+
+
+
+ {!device.mediaIsPhone ? (
+
+ Ente: {entity}
+ {entity_type && entity_type !== '-' ? (
+ <>
+ |
+ Tipologia: {entity_type}
+ >
+ ) : null}
+
+ ) : (
+
+
+ Ente: {entity}
+
+ {entity_type && entity_type !== '-' ? (
+
+ Tipologia: {entity_type}
+
+ ) : null}
+
+ )}
+ {intervention || program_label ? (
+
+ {intervention ? (
+
+ Intervento:
+ {intervention === 'public'
+ ? 'Tutti gli interventi'
+ : intervention}
+
+ ) : null}
+ {program_label ? (
+
+ Programma: {program_label}
+
+ ) : null}
+
+ ) : null}
+
+
+ );
+};
+
+export default DetailCard;
diff --git a/fe-piattaforma/src/components/DetailLayout/detailLayout.tsx b/fe-piattaforma/src/components/DetailLayout/detailLayout.tsx
index 3558fa05c..7c51be439 100644
--- a/fe-piattaforma/src/components/DetailLayout/detailLayout.tsx
+++ b/fe-piattaforma/src/components/DetailLayout/detailLayout.tsx
@@ -5,7 +5,7 @@ import { Accordion, ButtonsBar } from '../index';
import { ButtonInButtonsBar } from '../ButtonsBar/buttonsBar';
import CardStatusAction from '../CardStatusAction/cardStatusAction';
import SectionTitle from '../SectionTitle/sectionTitle';
-import { Button, Icon } from 'design-react-kit';
+import { Button, FormGroup, Icon } from 'design-react-kit';
import { useNavigate } from 'react-router-dom';
import { useAppSelector } from '../../redux/hooks';
import { selectDevice } from '../../redux/features/app/appSlice';
@@ -13,6 +13,12 @@ import clsx from 'clsx';
import { openModal } from '../../redux/features/modal/modalSlice';
import { useDispatch } from 'react-redux';
import { formTypes } from '../../pages/administrator/AdministrativeArea/Entities/utils';
+import CardStatusActionProject from '../CardStatusAction/cardStatusActionProject';
+import CardStatusActionHeadquarters from '../CardStatusAction/cardStatusActionHeadquarters';
+import CardStatusActionSurveys from '../CardStatusAction/cardStatusActionSurveys';
+import CardStatusActionPartnerAuthority from '../CardStatusAction/cardStatusActionPartnerAuthority';
+import EmptySection from '../EmptySection/emptySection';
+import IconNote from '/public/assets/img/it-note-primary.png';
interface DetailLayoutI {
nav?: ReactElement;
@@ -20,27 +26,37 @@ interface DetailLayoutI {
itemsAccordionList?: ItemsListI[] | null | undefined;
titleInfo: {
title: string;
- status: string;
+ status?: string | undefined;
upperTitle: {
- icon: string | any;
+ icon: string;
text: string;
};
subTitle?: string;
headingRole?: boolean;
iconAvatar?: boolean;
- name?: string;
- surname?: string;
+ name?: string | undefined;
+ surname?: string | undefined;
};
itemsList?: ItemsListI | null | undefined;
showItemsList?: boolean;
- buttonsPosition: 'TOP' | 'BOTTOM';
+ buttonsPosition?: 'TOP' | 'BOTTOM';
showGoBack?: boolean;
goBackTitle?: string;
+ goBackPath?: string;
children?: ReactElement | undefined;
currentTab?: string;
surveyDefault?: ItemsListI | null | undefined;
isRadioButtonItem?: boolean;
onRadioChange?: (surveyDefault: string) => void;
+ isUserProfile?: boolean | string | undefined;
+ citizenList?: boolean;
+ citizenDeleteChange?: boolean;
+ enteIcon?: boolean;
+ profilePicture?: string | undefined;
+ isRoleManagement?: boolean;
+ infoProgBtn?: boolean;
+ infoProjBtn?: boolean;
+ noTitleEllipsis?: boolean;
}
const DetailLayout: React.FC = ({
formButtons,
@@ -49,14 +65,24 @@ const DetailLayout: React.FC = ({
nav,
itemsList,
showItemsList = true,
- buttonsPosition,
+ buttonsPosition = 'BOTTOM',
showGoBack = true,
goBackTitle = 'Torna indietro',
+ goBackPath,
children,
currentTab,
surveyDefault,
isRadioButtonItem = false,
+ isUserProfile = false,
onRadioChange,
+ citizenList = false,
+ citizenDeleteChange = false,
+ enteIcon = false,
+ profilePicture,
+ isRoleManagement = false,
+ infoProgBtn = false,
+ infoProjBtn = false,
+ noTitleEllipsis = false,
}) => {
const navigate = useNavigate();
const device = useAppSelector(selectDevice);
@@ -64,167 +90,263 @@ const DetailLayout: React.FC = ({
return (
<>
- {showGoBack && (
-
- )}
-
- {nav && (
-
- {nav}
-
- )}
- {children}
- {buttonsPosition === 'TOP' && formButtons && formButtons.length !== 0 ? (
- <>
-
-
- {formButtons.length === 3 ? (
- device.mediaIsPhone ? (
-
-
-
-
- ) : (
-
-
-
-
- )
- ) : (
-
- )}
-
-
-
-
+
+ {showGoBack && (
+
+ )}
+
+ {nav && (
+
+ {nav}
- >
- ) : null}
- {itemsAccordionList && itemsAccordionList.length
- ? itemsAccordionList.map((singleItem, index) => (
-
- dispatch(
- openModal({
- id:
- singleItem.title === 'Referenti'
- ? formTypes.REFERENTE
- : formTypes.DELEGATO,
- payload: { title: `Aggiungi ${singleItem.title}` },
- })
- )
- }
- key={index}
- lastBottom={index === itemsAccordionList.length - 1}
- >
- {singleItem.items.map((item, index: number) => (
- {children}
+ {itemsAccordionList?.length
+ ? itemsAccordionList.map((singleItem, index) => (
+
+ dispatch(
+ openModal({
+ id:
+ singleItem.title === 'Referenti'
+ ? formTypes.REFERENTE
+ : singleItem.title === 'Delegati'
+ ? formTypes.DELEGATO
+ : singleItem.title === 'Facilitatori'
+ ? formTypes.FACILITATORE
+ : formTypes.SEDE,
+ payload: { title: `Aggiungi ${singleItem.title}` },
+ })
+ )
+ }
+ key={index}
+ lastBottom={index === itemsAccordionList.length - 1}
+ >
+ {singleItem.items?.length ? (
+ singleItem.items.map((item) => (
+
+ ))
+ ) : (
+
+ )}
+
+ ))
+ : null}
+ {currentTab === 'questionari' ? (
+ surveyDefault?.items?.length && showItemsList ? (
+
+
+ {isRadioButtonItem &&
+ !device.mediaIsPhone &&
+ currentTab === 'questionari' &&
+ itemsList?.items?.length && (
+
+ Questionari disponibili
+
+ )}
+
+ ) : null
+ ) : null}
+ {showItemsList &&
+ itemsList?.items?.length &&
+ currentTab === 'questionari' ? (
+ <>
+ {itemsList.title && (
+
{itemsList.title}
+ )}
+ {((currentTab === 'questionari' && isRadioButtonItem) ||
+ currentTab !== 'questionari') && (
+
+ {itemsList.items.map((item) => {
+ return (
+
+ onRadioChange ? onRadioChange(surveyChecked) : null
+ }
+ />
+ );
+ })}
+
+ )}
+ >
+ ) : null}
+ {currentTab === 'progetti' && showItemsList && itemsList?.items?.length
+ ? itemsList.items.map((item) => {
+ return (
+
+ );
+ })
+ : null}
+ {currentTab === 'enti-partner' &&
+ showItemsList &&
+ itemsList?.items?.length
+ ? itemsList.items.map((item) => {
+ return (
+
- ))}
-
- ))
- : null}
- {currentTab === 'questionari' && surveyDefault && (
-
-
- {isRadioButtonItem &&
- device.mediaIsDesktop &&
- currentTab === 'questionari' &&
- itemsList?.items.length && (
-
Altri questionari
+ );
+ })
+ : null}
+ {currentTab === 'sedi' && showItemsList && itemsList?.items?.length
+ ? itemsList.items.map((item) => {
+ return (
+
+ );
+ })
+ : null}
+ {showItemsList && itemsList?.items?.length && currentTab === 'info' ? (
+ <>
+ {itemsList.title && (
+ {itemsList.title}
)}
-
- )}
- {showItemsList && itemsList?.items?.length ? (
- <>
- {itemsList.title && (
-
{itemsList.title}
- )}{' '}
- {((currentTab === 'questionari' && isRadioButtonItem) ||
- currentTab !== 'questionari') &&
- itemsList.items.map((item) => {
+ {itemsList.items.map((item) => {
return (
- onRadioChange ? onRadioChange(surveyChecked) : null
- }
/>
);
- })}{' '}
- >
- ) : null}
+ })}
+ >
+ ) : null}
+ {buttonsPosition === 'TOP' &&
+ formButtons &&
+ formButtons.length !== 0 ? (
+
+
+
+ ) : null}
+
+
{buttonsPosition === 'BOTTOM' &&
formButtons &&
formButtons.length !== 0 ? (
- <>
-
-
-
-
-
-
-
-
- >
+
+
+ {formButtons.length === 2 &&
+ (infoProgBtn ||
+ (infoProjBtn &&
+ titleInfo?.status !== 'ATTIVABILE' &&
+ titleInfo?.status !== 'NON ATTIVO')) ? (
+
+
+
+
+ ) : (
+
+
+
+ )}
+
+
) : null}
>
);
diff --git a/fe-piattaforma/src/components/DetailsRow/detailsRow.scss b/fe-piattaforma/src/components/DetailsRow/detailsRow.scss
index 84250cb6f..af576cfe5 100644
--- a/fe-piattaforma/src/components/DetailsRow/detailsRow.scss
+++ b/fe-piattaforma/src/components/DetailsRow/detailsRow.scss
@@ -2,13 +2,30 @@
display: grid;
grid-template-columns: 1fr 2fr 1fr;
grid-column-gap: rem(10px);
- box-shadow: 0 0 rem(80px) rgba(0, 43, 85, 0.1);
+ box-shadow: 0 0 40px rgba(0, 0, 0, 0.1);
margin-bottom: rem(13px);
padding: rem(33px 25px);
+ @media screen and (max-width: 576px){
+ display: flex;
+ flex-direction: column;
+ gap: 15px;
+ }
+
+ @media screen and (min-width:577px) and (max-width: 992px){
+ display: flex;
+ flex-direction: row;
+ justify-content: space-between;
+ flex-wrap: wrap;
+ }
+
&__name {
display: flex;
align-items: flex-start;
+
+ h2 {
+ width: 130px;
+ }
}
&__info {
@@ -22,13 +39,19 @@
display: flex;
flex-direction: column;
}
+
+ div > span {
+ @media screen and (max-width: 992px){
+ min-width: 80px;
+ }
+ }
}
&__left-section {
grid-area: 1 / 1 / 2 / 4;
display: flex;
flex-wrap: nowrap;
- align-items: start;
+ align-items: center;
gap: rem(10px);
}
@@ -51,3 +74,9 @@
}
}
}
+
+.icons {
+ &__icon-visible-password {
+ object-fit: contain;
+ }
+}
\ No newline at end of file
diff --git a/fe-piattaforma/src/components/DetailsRow/detailsRow.tsx b/fe-piattaforma/src/components/DetailsRow/detailsRow.tsx
index 568c91933..738bc0fc7 100644
--- a/fe-piattaforma/src/components/DetailsRow/detailsRow.tsx
+++ b/fe-piattaforma/src/components/DetailsRow/detailsRow.tsx
@@ -1,7 +1,11 @@
import React from 'react';
-import { Button, Icon } from 'design-react-kit';
+import { Button, Icon, UncontrolledTooltip } from 'design-react-kit';
import { CRUDActionsI, CRUDActionTypes } from '../../utils/common';
import StatusChip from '../StatusChip/statusChip';
+import PasswordVisible from '/public/assets/img/it-password-visible.png';
+import ItPlusCircle from '/public/assets/img/it-plus-circle-primary.png';
+import ItMail from '/public/assets/img/it-mail-primary.png';
+import ItPencil from '/public/assets/img/it-pencil-primary.png';
interface DetailsRowI {
id: string;
@@ -10,11 +14,12 @@ interface DetailsRowI {
onActionClick: CRUDActionsI;
innerInfo: { [key: string]: string };
rowInfoType: string;
+ idQuestionario?: string;
}
const statusCases = {
SENT: 'INVIATO',
- NOT_SENT: 'NON INVIATO',
+ NOT_FILLED: 'NON COMPILATO',
FILLED_OUT: 'COMPILATO',
};
@@ -25,77 +30,117 @@ const DetailsRow: React.FC = ({
onActionClick,
innerInfo,
rowInfoType,
+ idQuestionario = '',
}) => {
const loadIcons = () => {
switch (stato.toUpperCase()) {
- case statusCases.NOT_SENT:
+ case statusCases.SENT:
return (
<>
+
+ Compila questionario
+
+
+ Invia questionario
+
>
);
- case statusCases.SENT:
+ case statusCases.NOT_SENT:
return (
<>
+
+ Compila questionario
+
+
+ Invia questionario
+
>
);
case statusCases.FILLED_OUT:
return (
-
+ <>
+
+
+ Visualizza questionario
+
+ >
);
default:
break;
@@ -106,35 +151,59 @@ const DetailsRow: React.FC = ({
{onActionClick[CRUDActionTypes.EDIT] && (
-
+ <>
+
+
+ Modifica cittadino
+
+ >
)}
{nome}
- {Object.keys(innerInfo).map((x, index) => (
-
- {x}:
- {innerInfo[x]}
-
- ))}
+ {innerInfo?.['Codice Fiscale'] &&
+ innerInfo?.['Codice Fiscale'] !== '-' && (
+
+
+ Codice Fiscale:
+
+
+ {innerInfo['Codice Fiscale']}
+
+
+ )}
+ {innerInfo?.['Numero Documento'] &&
+ innerInfo?.['Codice Fiscale'] === '-' && (
+
+
+ Numero Documento:
+
+
+ {innerInfo['Numero Documento']}
+
+
+ )}
{rowInfoType}
-
+
{loadIcons()}
diff --git a/fe-piattaforma/src/components/DocumentDetail/documentDetail.scss b/fe-piattaforma/src/components/DocumentDetail/documentDetail.scss
new file mode 100644
index 000000000..5f3155591
--- /dev/null
+++ b/fe-piattaforma/src/components/DocumentDetail/documentDetail.scss
@@ -0,0 +1,64 @@
+.document-card-detail-container {
+ max-width: 1174px;
+ border: 1px solid #eceff1;
+ box-shadow: 4px 4px 8px rgba(0, 0, 0, 0.1);
+ border-radius: 4px;
+
+ &__typology {
+ color: #455b71;
+ line-height: 27px;
+ letter-spacing: 1.1px;
+ }
+
+ &__document-detail-dropdown {
+ button {
+ border: none;
+ box-shadow: none;
+ }
+ button:hover {
+ border: none;
+ }
+ }
+
+ &__title {
+ font-size: 24px;
+ color: #1c2024;
+ }
+
+ &__img-icon-file {
+ max-width: 57px;
+ max-height: 72.67px;
+ }
+
+ &__description {
+ font-weight: 400;
+ color: #455B71;
+ align-self: flex-start;
+ word-break: break-all;
+ }
+}
+.btn-download-file,
+.btn-external-link {
+ color: #0073e5;
+ padding-left: 12px;
+ padding-right: 35px;
+}
+
+.border-box-container {
+ opacity: 0.3;
+ border-bottom: 0.5px solid #3686d6;
+}
+
+.forum-chip-tag {
+ justify-content: center;
+ min-width: 71px;
+ min-height: 32px;
+ border-radius: 16px;
+ border: 2px solid #797C80 !important;
+ &:hover {
+ .chip-label {
+ color: #5c6f82 !important;
+ }
+ background-color: #FCFDFF !important;
+ }
+}
diff --git a/fe-piattaforma/src/components/DocumentDetail/sectionDetail.tsx b/fe-piattaforma/src/components/DocumentDetail/sectionDetail.tsx
new file mode 100644
index 000000000..32600d510
--- /dev/null
+++ b/fe-piattaforma/src/components/DocumentDetail/sectionDetail.tsx
@@ -0,0 +1,449 @@
+import {
+ Icon,
+ Dropdown,
+ DropdownToggle,
+ DropdownMenu,
+ LinkList,
+ Button,
+ Chip,
+ ChipLabel,
+} from 'design-react-kit';
+import React, { useEffect, useState } from 'react';
+import iconFile from '../../../public/assets/img/icon-file-blue-medium.png';
+import DetailCard from '../DetailCard/detailCard';
+import './documentDetail.scss';
+import clsx from 'clsx';
+import SocialBar from '../Comments/socialBar';
+import { useAppSelector } from '../../redux/hooks';
+import { selectDevice } from '../../redux/features/app/appSlice';
+import { openModal } from '../../redux/features/modal/modalSlice';
+import { useDispatch } from 'react-redux';
+import { selectUser } from '../../redux/features/user/userSlice';
+import {
+ ActionTracker,
+ GetItemDetail,
+ ManageItemEvent,
+} from '../../redux/features/forum/forumThunk';
+import { cleanDrupalFileURL } from '../../utils/common';
+import { formatDate } from '../../utils/datesHelper';
+import useGuard from '../../hooks/guard';
+
+export interface CardDocumentDetailI {
+ id?: string;
+ author?: string;
+ title: string;
+ category: string;
+ category_label: string;
+ date: string;
+ description: string;
+ comment_count: number;
+ attachment?: string | undefined;
+ external_link?: string;
+ entity?: string;
+ entity_type?: string;
+ intervention?: string;
+ program_label?: string;
+ tags?: string;
+ downloads?: number;
+ user_like?: boolean;
+ likes?: number;
+ views?: number;
+ section?: 'community' | 'documents';
+ isDocument?: boolean | undefined;
+ onDeleteClick?: () => void;
+ onEditClick?: () => void;
+ onReportClick?: () => void;
+}
+
+const SectionDetail: React.FC
= (props) => {
+ const {
+ author,
+ id,
+ title,
+ category,
+ category_label,
+ date,
+ description,
+ comment_count,
+ attachment = '',
+ entity,
+ entity_type,
+ external_link,
+ intervention,
+ program_label,
+ tags,
+ downloads,
+ user_like,
+ likes,
+ views,
+ isDocument,
+ section,
+ onDeleteClick = () => ({}),
+ onEditClick = () => ({}),
+ onReportClick = () => ({}),
+ } = props;
+
+ const [detailDropdownOptions, setDetailDropdownOptions] = useState([]);
+ const device = useAppSelector(selectDevice);
+ const dispatch = useDispatch();
+ const userId = useAppSelector(selectUser)?.id;
+ const [isOpen, setIsOpen] = useState(false);
+ const { hasUserPermission } = useGuard();
+
+ const trackDownload = async () => {
+ if (id && section === 'documents') {
+ await dispatch(ManageItemEvent(id, 'downloaded'));
+ await dispatch(
+ ActionTracker({
+ target: 'tnd',
+ action_type: 'VISUALIZZAZIONE-DOWNLOAD',
+ event_type: 'DOCUMENTI',
+ category: category_label || category,
+ })
+ );
+ }
+ window.open(cleanDrupalFileURL(attachment), '_blank');
+ };
+
+ const deleteOption = {
+ optionName: 'ELIMINA',
+ DropdownIcon: {
+ icon: 'it-delete',
+ color: 'primary',
+ },
+ action: onDeleteClick,
+ };
+
+ const editOption = {
+ optionName: 'MODIFICA',
+ DropdownIcon: {
+ icon: 'it-pencil',
+ color: 'primary',
+ },
+ action: onEditClick,
+ };
+
+ const reportOption = {
+ optionName: 'SEGNALA',
+ DropdownIcon: {
+ icon: 'it-error',
+ color: 'danger',
+ },
+ action: onReportClick,
+ };
+
+ const setDetailDropdownOptionsByPermission = () => {
+ const authorizedOption = [];
+ if (
+ hasUserPermission([
+ section === 'documents' || isDocument
+ ? 'del.doc'
+ : section === 'community'
+ ? 'del.topic'
+ : 'hidden',
+ ]) ||
+ (author?.toString() === userId?.toString() &&
+ hasUserPermission([
+ section === 'documents' || isDocument
+ ? 'new.doc'
+ : section === 'community'
+ ? 'new.topic'
+ : 'hidden',
+ ]))
+ ) {
+ authorizedOption.push(deleteOption);
+ }
+ if (
+ hasUserPermission([
+ section === 'documents' || isDocument
+ ? 'upd.doc'
+ : section === 'community'
+ ? 'upd.topic'
+ : 'hidden',
+ ]) ||
+ (author?.toString() === userId?.toString() &&
+ hasUserPermission([
+ section === 'documents' || isDocument
+ ? 'new.doc'
+ : section === 'community'
+ ? 'new.topic'
+ : 'hidden',
+ ]))
+ ) {
+ authorizedOption.push(editOption);
+ }
+ if (
+ hasUserPermission([
+ section === 'documents' || isDocument
+ ? 'rprt.doc'
+ : section === 'community'
+ ? 'rprt.topic'
+ : 'hidden',
+ ])
+ ) {
+ authorizedOption.push(reportOption);
+ }
+ setDetailDropdownOptions(authorizedOption);
+ };
+
+ useEffect(() => {
+ setDetailDropdownOptionsByPermission();
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [section, author, userId]);
+
+ const documentDetailDropdown = () => (
+ setIsOpen(!isOpen)}
+ >
+
+
+
+
+
+
+
+ {detailDropdownOptions.map((item, i) => (
+ setIsOpen(!isOpen)}>
+
+
+ ))}
+
+
+
+ );
+
+ return (
+
+
+
+ {
+
+ {category_label} —
+ {date && formatDate(date, 'shortDate')}
+
+ }
+
+ {documentDetailDropdown()}
+
+
+ {title}
+
+
+ {section === 'documents' || isDocument ? (
+
+ ) : null}
+
+ {description}
+
+
+
+ {attachment ? (
+
+ ) : null}
+ {external_link ? (
+
+ ) : null}
+
+ {tags ? (
+
+
TAG:
+
+ {tags.split(';').map((tag, i) => (
+
+ {tag}
+
+ ))}
+
+
+ ) : null}
+
+
+
{
+ if (id) {
+ if (user_like as boolean) {
+ await dispatch(ManageItemEvent(id, 'unlike'));
+ } else {
+ await dispatch(ManageItemEvent(id, 'like'));
+ dispatch(
+ ActionTracker({
+ target: 'tnd',
+ action_type: 'LIKE',
+ event_type: 'TOPIC',
+ category: category_label || category,
+ })
+ );
+ }
+ userId && dispatch(GetItemDetail(id, userId, 'community'));
+ }
+ }
+ : undefined
+ }
+ onComment={() =>
+ dispatch(
+ openModal({
+ id: 'comment-modal',
+ payload: {
+ title: 'Aggiungi commento',
+ action: 'comment',
+ entity: section === 'community' ? 'community' : 'document',
+ category: category_label || category,
+ textLabel: 'Digita qui sotto il testo',
+ },
+ })
+ )
+ }
+ />
+
+ );
+};
+
+export default SectionDetail;
diff --git a/fe-piattaforma/src/components/DropdownFilter/dropdownFilter.scss b/fe-piattaforma/src/components/DropdownFilter/dropdownFilter.scss
index 9ff359c34..c73ec1d18 100644
--- a/fe-piattaforma/src/components/DropdownFilter/dropdownFilter.scss
+++ b/fe-piattaforma/src/components/DropdownFilter/dropdownFilter.scss
@@ -1,8 +1,8 @@
.dropdown-filter-container {
- width: 200px;
+ min-width: 200px;
@media screen and (max-width: 576px) {
- width: 140px;
+ min-width: 155px;
}
&__popover {
@@ -15,6 +15,12 @@
}
}
+ &__larger {
+ .popover.show {
+ width: 250px;
+ }
+ }
+
&__search-tooltip {
max-height: 45px;
}
@@ -27,6 +33,12 @@
z-index: 99;
}
+ &__empty-state {
+ font-weight: 400;
+ text-align: start;
+ padding: 0px;
+ }
+
button {
padding: rem(11px) rem(8px) rem(11px) rem(21px);
}
diff --git a/fe-piattaforma/src/components/DropdownFilter/dropdownFilter.tsx b/fe-piattaforma/src/components/DropdownFilter/dropdownFilter.tsx
index d6d305ab4..cc90b3927 100644
--- a/fe-piattaforma/src/components/DropdownFilter/dropdownFilter.tsx
+++ b/fe-piattaforma/src/components/DropdownFilter/dropdownFilter.tsx
@@ -7,10 +7,12 @@ import { focusId } from '../../utils/common';
import { formFieldI } from '../../utils/formHelper';
import ClickOutside from '../../hoc/ClickOutside';
import isEqual from 'lodash.isequal';
+import { capitalize } from 'lodash';
+import FocusTrap from 'focus-trap-react';
export interface FilterI {
label: string;
- value: string | number | any[];
+ value: string | number | string[];
}
export interface DropdownFilterI {
@@ -22,6 +24,9 @@ export interface DropdownFilterI {
id: string;
handleOnSearch?: (searchKey: formFieldI['value']) => void;
valueSearch?: formFieldI['value'] | undefined;
+ isDetail?: boolean | undefined;
+ isGeneric?: boolean | undefined;
+ formatValues?: boolean | undefined;
}
let focusedInput = -1;
@@ -33,14 +38,35 @@ const DropdownFilter: React.FC = (props) => {
values = [],
className,
id,
- handleOnSearch,
- valueSearch,
+ // handleOnSearch,
+ //valueSearch,
+ isDetail,
+ isGeneric,
+ formatValues = false,
} = props;
const [open, setOpen] = useState(false);
const [checkedOptions, setCheckedOptions] = useState(values);
+ const idSearchBar = `search-input-dropdown-${id}`;
const idListOptions = `filter-options-list-${id}`;
const popoverRef = useRef(null);
const { t } = useTranslation();
+ const [searchValue, setSearchValue] = useState('');
+ const [filteredOptions, setFilteredOptions] = useState(
+ options
+ );
+ /* const device = useAppSelector(selectDevice); */
+
+ useEffect(() => {
+ if (searchValue) {
+ const newOptions: FilterI[] =
+ options?.filter((opt) =>
+ opt.label.toLowerCase().includes(searchValue.toLowerCase())
+ ) || [];
+ setFilteredOptions(newOptions);
+ } else if (searchValue === '' || !open) {
+ setFilteredOptions(options);
+ }
+ }, [options, searchValue, open]);
const manageKeyEvent = (e: KeyboardEvent) => {
switch (e.key) {
@@ -82,35 +108,15 @@ const DropdownFilter: React.FC = (props) => {
focusId(`filter-${id}`);
break;
}
- case 'Tab':
- if (focusedInput === (options || [])?.length - 1) {
- e.preventDefault();
- setOpen(!open);
- focusId(`filter-${id}`);
- break;
- } else {
- e.preventDefault();
- document
- .getElementById(
- `input-checkbox-${id}-${Math.max(
- Math.min(focusedInput + 1, (options || [])?.length - 1),
- 0
- )}`
- )
- ?.focus();
- focusedInput = Math.max(
- Math.min(focusedInput + 1, (options || [])?.length - 1),
- 0
- );
- break;
- }
default:
}
};
useEffect(() => {
if (open) {
- focusId(idListOptions, false);
+ const idToFocus =
+ options && options?.length > 4 ? idSearchBar : idListOptions;
+ focusId(idToFocus, false);
document.addEventListener('keydown', manageKeyEvent);
}
@@ -119,7 +125,7 @@ const DropdownFilter: React.FC = (props) => {
focusedInput = -1;
};
// eslint-disable-next-line react-hooks/exhaustive-deps
- }, [open]);
+ }, [open, options]);
useEffect(() => {
if (!isEqual(values, checkedOptions)) {
@@ -160,7 +166,7 @@ const DropdownFilter: React.FC = (props) => {
'dropdown-filter-container',
'mr-lg-4',
'mr-2',
- 'mt-4'
+ isDetail || isGeneric ? 'mt-2' : 'mt-4'
)}
>
@@ -191,100 +198,125 @@ const DropdownFilter: React.FC = (props) => {
isOpen={open}
placement='bottom'
target={popoverRef}
- className='dropdown-filter-container__popover'
+ className={clsx(
+ 'dropdown-filter-container__popover',
+ options && options?.length > 5 && 'dropdown-filter-container__larger'
+ )}
toogle={() => setOpen(!open)}
id={`popover-filter-options-${id}`}
aria-describedby={`descrizione-popover-dropdown-${id}`}
role='combobox'
aria-owns={idListOptions}
>
- {options?.length && options?.length > 5 ? (
-
-