diff --git a/api/net/Areas/Subscriber/Controllers/TonePoolController.cs b/api/net/Areas/Subscriber/Controllers/TonePoolController.cs
index 727ef7bee9..0c02cd33a3 100644
--- a/api/net/Areas/Subscriber/Controllers/TonePoolController.cs
+++ b/api/net/Areas/Subscriber/Controllers/TonePoolController.cs
@@ -48,7 +48,7 @@ public TonePoolController(ITonePoolService service)
#region Endpoints
///
- /// Return an array of TonePool.
+ /// Find all TonePools.
///
///
[HttpGet, HttpHead]
@@ -56,11 +56,24 @@ public TonePoolController(ITonePoolService service)
[ProducesResponseType(typeof(IEnumerable), (int)HttpStatusCode.OK)]
[ProducesResponseType((int)HttpStatusCode.NotModified)]
[SwaggerOperation(Tags = new[] { "TonePool" })]
- [ETagCacheTableFilter("tone_pools")]
- [ResponseCache(Duration = 5 * 60)]
+ public IActionResult FindAll()
+ {
+ return new JsonResult(_service.FindAll());
+ }
+
+ ///
+ /// Find a TonePool by 'id'.
+ ///
+ ///
+ ///
+ [HttpGet("{id}")]
+ [Produces(MediaTypeNames.Application.Json)]
+ [ProducesResponseType(typeof(TonePoolModel), (int)HttpStatusCode.OK)]
+ [ProducesResponseType(typeof(ErrorResponseModel), (int)HttpStatusCode.BadRequest)]
+ [SwaggerOperation(Tags = new[] { "TonePool" })]
public IActionResult FindById(int id)
{
- var result = _service.FindById(id) ?? throw new NoContentException();
+ var result = _service.FindById(id) ?? throw new NoContentException("TonePool does not exist");
return new JsonResult(new TonePoolModel(result));
}
@@ -95,8 +108,6 @@ public IActionResult FindByUserId(int userId)
[ProducesResponseType(typeof(TonePoolModel), (int)HttpStatusCode.Created)]
[ProducesResponseType(typeof(ErrorResponseModel), (int)HttpStatusCode.BadRequest)]
[SwaggerOperation(Tags = new[] { "TonePool" })]
- [ETagCacheTableFilter("tone_pools")]
- [ResponseCache(Duration = 5 * 60)]
public IActionResult Add(TonePoolModel model)
{
var tonePoolEntity = new TonePool(model.Name, model.OwnerId)
diff --git a/app/subscriber/src/features/my-reports/edit/constants/defaultContentTonePool.ts b/app/subscriber/src/features/my-reports/edit/constants/defaultContentTonePool.ts
new file mode 100644
index 0000000000..8bef6e3dad
--- /dev/null
+++ b/app/subscriber/src/features/my-reports/edit/constants/defaultContentTonePool.ts
@@ -0,0 +1,8 @@
+import { IContentTonePoolModel } from 'tno-core';
+
+import { defaultTonePool } from './defaultTonePool';
+
+export const defaultContentTonePool: IContentTonePoolModel = {
+ ...defaultTonePool,
+ value: undefined,
+};
diff --git a/app/subscriber/src/features/my-reports/edit/content/ContentEditForm.tsx b/app/subscriber/src/features/my-reports/edit/content/ContentEditForm.tsx
index 162a8602d5..15ecb44e5e 100644
--- a/app/subscriber/src/features/my-reports/edit/content/ContentEditForm.tsx
+++ b/app/subscriber/src/features/my-reports/edit/content/ContentEditForm.tsx
@@ -6,12 +6,13 @@ import { IContentValidationErrors } from 'features/my-reports/interfaces/IConten
import { toForm } from 'features/my-reports/utils';
import { formatDate } from 'features/utils';
import React from 'react';
+import { FaToggleOff, FaToggleOn } from 'react-icons/fa';
+import { toast } from 'react-toastify';
import { useApp, useContent, useReports } from 'store/hooks';
import { useTonePool } from 'store/hooks/subscriber/useTonePool';
-import { useProfileStore } from 'store/slices';
-import { Col, ContentTypeName, IContentModel, IContentTonePoolModel } from 'tno-core';
+import { Col, ContentTypeName, IContentModel, IContentTonePoolModel, ToggleButton } from 'tno-core';
-import { defaultTonePool } from '../constants/defaultTonePool';
+import { defaultContentTonePool } from '../constants/defaultContentTonePool';
import { useReportEditContext } from '../ReportEditContext';
import { ContentActions, ContentForm, UserContentForm } from './stories';
import * as styled from './styled';
@@ -30,10 +31,9 @@ export interface IContentEditFormProps {
export const ContentEditForm = React.forwardRef(
({ disabled }, ref) => {
const [{ userInfo }] = useApp();
- const [{ myTonePool, init }, { storeMyTonePool }] = useProfileStore();
const [, { updateReport }] = useReports();
const [, { addContent, updateContentSilent, getContent }] = useContent();
- const [, { addMyTonePool, getMyTonePool }] = useTonePool();
+ const [, { addMyTonePool }] = useTonePool();
const { values, onNavigate, isSubmitting, setSubmitting, setValues, activeRow, setActiveRow } =
useReportEditContext();
@@ -45,44 +45,11 @@ export const ContentEditForm = React.forwardRef {
- const getTonePool = async () => {
- try {
- if (!init.myTonePool && userId !== 0) {
- const response = await getMyTonePool(userId);
- if (response?.id) {
- storeMyTonePool(response);
- } else {
- // If no valid tone pool exists, proceed to create one
- await createTonePool(userId);
- }
- }
- } catch (error) {
- console.error('Error loading tone pool:', error);
- } finally {
- }
- };
-
- const createTonePool = async (userId: number) => {
- try {
- await addMyTonePool({
- ...defaultTonePool,
- name: `${userId}`,
- ownerId: userId,
- });
- const newTonePool = await getMyTonePool(userId);
- storeMyTonePool(newTonePool);
- } catch (error) {
- console.error('Error creating tone pool:', error);
- } finally {
- }
- };
-
- if (myTonePool.id === 0) {
- getTonePool();
- }
- }, [getMyTonePool, addMyTonePool, myTonePool.id, userId, init.myTonePool, storeMyTonePool]);
+ const toggleSentiment = React.useCallback(() => {
+ setIsUserSentiment((prev) => !prev);
+ }, []);
React.useEffect(() => {
const updatedUserFormTonePool =
@@ -93,6 +60,7 @@ export const ContentEditForm = React.forwardRef {
setForm(activeRow);
+ setIsUserSentiment(false);
}, [activeRow]);
const validate = (values: IContentModel) => {
@@ -133,6 +101,20 @@ export const ContentEditForm = React.forwardRef {
+ try {
+ const newTonePool = await addMyTonePool({
+ ...defaultContentTonePool,
+ name: `${userId}`,
+ ownerId: userId,
+ });
+ return newTonePool;
+ } catch (error) {
+ console.error('Error creating tone pool:', error);
+ } finally {
+ }
+ }, []);
+
const handleAddUpdateContent = React.useCallback(
async (values: IReportForm, row: IReportInstanceContentForm) => {
try {
@@ -143,6 +125,25 @@ export const ContentEditForm = React.forwardRef tp.ownerId === userId) ?? defaultContentTonePool;
+ if (userTonePool.id === 0) {
+ const newTonePool = await createTonePool(userId);
+
+ if (newTonePool) {
+ userTonePool = {
+ ...userTonePool,
+ id: newTonePool.id,
+ };
+ }
+ if (content?.tonePools) {
+ content.tonePools = [
+ ...content.tonePools.filter((tp) => tp.ownerId !== userId),
+ userTonePool,
+ ];
+ }
+ }
+ if (err.hasErrors) return null;
try {
contentResult = !content.id
? await addContent(content)
@@ -225,6 +226,7 @@ export const ContentEditForm = React.forwardRef
+ }
+ off={}
+ onClick={toggleSentiment}
+ width="25px"
+ height="25px"
+ color="#6750a4"
+ label="User Tone"
+ value={isUserSentiment}
+ />
0
? form.content.tonePools[0].value
: undefined
@@ -347,6 +360,7 @@ export const ContentEditForm = React.forwardRef {
setForm({ ...form, content });
}}
+ isUserSentiment={isUserSentiment}
loading={isSubmitting}
disabled={disabled}
/>
diff --git a/app/subscriber/src/features/my-reports/edit/content/stories/ContentForm.tsx b/app/subscriber/src/features/my-reports/edit/content/stories/ContentForm.tsx
index 79233933bf..5f9f322d81 100644
--- a/app/subscriber/src/features/my-reports/edit/content/stories/ContentForm.tsx
+++ b/app/subscriber/src/features/my-reports/edit/content/stories/ContentForm.tsx
@@ -1,11 +1,10 @@
-import { Form, Formik } from 'formik';
import React from 'react';
-import { useApp, useLookup } from 'store/hooks';
+import { useApp } from 'store/hooks';
+import { useTonePool } from 'store/hooks/subscriber/useTonePool';
import { useProfileStore } from 'store/slices';
import {
Col,
ContentTypeName,
- FormikSentiment,
IContentModel,
IContentTonePoolModel,
Loading,
@@ -15,7 +14,8 @@ import {
Wysiwyg,
} from 'tno-core';
-import { sentimentFormSchema } from '../../validation/SentimentFormSchema';
+import { defaultContentTonePool } from '../../constants/defaultContentTonePool';
+import { ToneSelector } from './ToneSelector';
export interface IContentFormProps extends Omit, 'content'> {
/** The content being edited */
@@ -28,6 +28,8 @@ export interface IContentFormProps extends Omit void;
+ /** User has tone pool defined*/
+ isUserSentiment: boolean;
reportContent: { label: string; url: string; section: string }[];
}
@@ -44,11 +46,13 @@ export const ContentForm: React.FC = ({
className,
reportContent,
onContentChange,
+ isUserSentiment,
...rest
}) => {
const [{ userInfo }] = useApp();
- const [{ impersonate, myTonePool }] = useProfileStore();
- const [{ tonePools }] = useLookup();
+ const [{ impersonate, myTonePool }, { storeMyTonePool }] = useProfileStore();
+ const [, { getMyTonePool }] = useTonePool();
+
const userId = impersonate?.id ?? userInfo?.id ?? 0;
const isAV = content?.contentType === ContentTypeName.AudioVideo;
const versions = content?.versions?.[userId] ?? {
@@ -61,87 +65,68 @@ export const ContentForm: React.FC = ({
: content.summary
: content?.body,
};
- const [initialValues, setInitialValues] = React.useState({
- tonePools:
- content?.tonePools && content?.tonePools.length > 0
- ? content.tonePools.filter((pool: IContentTonePoolModel) => pool.ownerId === userId)
- : [
- {
- ...myTonePool,
- value:
- content?.tonePools.find(
- (pool: { id: number; ownerId: number }) =>
- pool.id === myTonePool?.id && pool.ownerId === userId,
- )?.value ?? undefined,
- },
- ],
- });
- const handleSentimentChange = React.useCallback(
- async (newTonePool: any) => {
- const validTonePool = Array.isArray(newTonePool) ? newTonePool[0] : null;
+ const userDefaultContentTonePool = {
+ ...defaultContentTonePool,
+ ownerId: userId,
+ name: `${userId}`,
+ };
- if (!validTonePool) return;
+ React.useEffect(() => {
+ let isMounted = true;
+ const getMyTones = async () => {
try {
- if (!content?.id) {
- console.error('Content is missing required properties');
- return;
+ const response = await getMyTonePool(userId);
+ if (isMounted && response) {
+ storeMyTonePool(response);
}
+ } catch (error) {
+ console.error('Error fetching tone pool:', error);
+ }
+ };
- const existingTonePoolIndex = content?.tonePools?.findIndex(
- (tonePool) => tonePool.ownerId === userId,
- );
- let updatedContentTonePool;
+ if (userId && !myTonePool) {
+ getMyTones();
+ }
- if (existingTonePoolIndex !== undefined && existingTonePoolIndex >= 0) {
- // Replace the existing TonePool value
- updatedContentTonePool = content?.tonePools?.map((tonePool, index) =>
- index === existingTonePoolIndex
- ? { ...tonePool, value: validTonePool.value }
- : tonePool,
- );
- } else {
- // Add a new TonePool entry
- updatedContentTonePool = [
- ...(content?.tonePools || []),
- { ...validTonePool, ownerId: userId },
- ];
- }
+ // Cleanup function to run when the component unmounts
+ return () => {
+ isMounted = false;
+ };
+ }, [getMyTonePool, storeMyTonePool, userId, myTonePool]);
- const updatedContent: IContentModel = {
- ...content,
- tonePools: updatedContentTonePool as IContentTonePoolModel[],
- };
+ if (!content) return null;
- onContentChange?.(updatedContent);
- } catch (ex) {
- console.error('Error updating tone pools:', ex);
- }
- },
- [content, onContentChange, userId],
- );
+ const handleToneSelect = (value: number) => {
+ const updatedTonePool: IContentTonePoolModel = {
+ ...myTonePool,
+ ownerId:
+ myTonePool?.ownerId !== undefined && myTonePool?.ownerId !== 0
+ ? myTonePool.ownerId
+ : userId,
+ id: myTonePool?.id ?? 0,
+ isPublic: myTonePool?.isPublic ?? true,
+ name:
+ myTonePool?.name !== undefined && myTonePool?.name !== '' ? myTonePool?.name : `${userId}`,
+ value,
+ sortOrder: myTonePool?.sortOrder ?? 0,
+ isEnabled: myTonePool?.isEnabled ?? true,
+ description: myTonePool?.description ?? '',
+ };
- React.useEffect(() => {
- const updatedTonePools =
- content?.tonePools && content?.tonePools.length > 0
- ? content.tonePools.filter((pool: IContentTonePoolModel) => pool.ownerId === userId)
- : [
- {
- ...myTonePool,
- value:
- content?.tonePools.find(
- (pool: { id: number; ownerId: number }) =>
- pool.id === myTonePool?.id && pool.ownerId === userId,
- )?.value ?? undefined,
- },
- ];
+ if (content?.id) {
+ onContentChange?.({
+ ...content,
+ tonePools: [...(content.tonePools || []), updatedTonePool],
+ });
+ } else {
+ console.error('Content ID is missing or invalid.');
+ }
+ };
- // Update the versions state with the new tonePools
- setInitialValues((prevVersions) => ({
- ...prevVersions,
- tonePools: updatedTonePools,
- }));
- }, [content?.tonePools, userId, myTonePool]);
+ const userContentTonePool: IContentTonePoolModel =
+ content?.tonePools?.find((pool: IContentTonePoolModel) => pool.ownerId === userId) ||
+ userDefaultContentTonePool;
return show === 'none' ? null : (
@@ -155,11 +140,6 @@ export const ContentForm: React.FC = ({
rows={1}
disabled={disabled}
onChange={(e) => {
- if (!content || typeof content.id !== 'number') {
- console.error('Content ID is missing or invalid.');
- return;
- }
-
const values = {
...content,
versions: {
@@ -180,10 +160,6 @@ export const ContentForm: React.FC = ({
label="Byline"
disabled={disabled}
onChange={(e) => {
- if (!content || typeof content.id !== 'number') {
- console.error('Content ID is missing or invalid.');
- return;
- }
const values = {
...content,
versions: {
@@ -208,10 +184,6 @@ export const ContentForm: React.FC = ({
value={versions.summary}
disabled={disabled}
onChange={(text) => {
- if (!content || typeof content.id !== 'number') {
- console.error('Content ID is missing or invalid.');
- return;
- }
const values = {
...content,
versions: {
@@ -235,10 +207,6 @@ export const ContentForm: React.FC = ({
disabled={disabled}
urlOptions={reportContent}
onChange={(text) => {
- if (!content || typeof content.id !== 'number') {
- console.error('Content ID is missing or invalid.');
- return;
- }
const values = {
...content,
versions: {
@@ -253,26 +221,9 @@ export const ContentForm: React.FC = ({
onContentChange?.(values);
}}
/>
- {}}
- enableReinitialize={true}
- >
- {() => (
-
- )}
-
+ {isUserSentiment && (
+
+ )}
);
diff --git a/app/subscriber/src/features/my-reports/edit/content/stories/ToneSelector.tsx b/app/subscriber/src/features/my-reports/edit/content/stories/ToneSelector.tsx
new file mode 100644
index 0000000000..7d5f2e0286
--- /dev/null
+++ b/app/subscriber/src/features/my-reports/edit/content/stories/ToneSelector.tsx
@@ -0,0 +1,61 @@
+import React from 'react';
+import { Col, IContentTonePoolModel, Row } from 'tno-core';
+
+import * as styled from './styled';
+
+const toningOptions = [-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5];
+
+interface IToneSelectorProps {
+ label?: string;
+ myTonePool: IContentTonePoolModel;
+ onSelect: (value: number) => void;
+}
+
+export const ToneSelector: React.FC = ({
+ label = 'Tone',
+ onSelect,
+ myTonePool,
+}) => {
+ const facePositive = `${process.env.PUBLIC_URL}/assets/reports/face-positive@2x.png`;
+ const faceNeutral = `${process.env.PUBLIC_URL}/assets/reports/face-neutral@2x.png`;
+ const faceNegative = `${process.env.PUBLIC_URL}/assets/reports/face-negative@2x.png`;
+ const value = myTonePool?.value;
+ const [active, setActive] = React.useState(value);
+
+ const determineIndicator = (option: number) => {
+ if (option === 5) {
+ return ;
+ } else if (option === 0) {
+ return ;
+ } else if (option === -5) {
+ return ;
+ } else {
+ return ;
+ }
+ };
+
+ const handleToneSelect = (option: number) => {
+ setActive(option);
+ onSelect(option);
+ };
+
+ return (
+
+
+
+ {toningOptions.map((option) => (
+
+ {determineIndicator(option)}
+
+
+ ))}
+
+
+ );
+};
diff --git a/app/subscriber/src/features/my-reports/edit/content/stories/styled/ToneSelector.tsx b/app/subscriber/src/features/my-reports/edit/content/stories/styled/ToneSelector.tsx
new file mode 100644
index 0000000000..3d2872e368
--- /dev/null
+++ b/app/subscriber/src/features/my-reports/edit/content/stories/styled/ToneSelector.tsx
@@ -0,0 +1,62 @@
+import styled from 'styled-components';
+
+export interface IToneSelectorProps {
+ required?: boolean;
+ active?: boolean;
+}
+
+export const ToneSelector = styled.div.attrs(({ required }) => ({
+ required,
+}))`
+ display: flex;
+ flex-direction: column;
+
+ img {
+ height: 20px;
+ width: 20px;
+ align-self: center;
+ }
+
+ button {
+ background-color: #f2f2f2;
+ border-radius: 15%;
+ border-color: #f2f2f2;
+ margin: 0 0.25rem;
+ margin-top: 0.5rem;
+ box-shadow: 0px 1px 2px rgba(0, 0, 0, 0.2);
+ min-width: 2rem;
+ min-height: 2rem;
+ align-self: center;
+ &:hover {
+ cursor: pointer;
+ }
+ }
+
+ .blank {
+ height: 20px;
+ width: 20px;
+ }
+
+ .active {
+ background-color: #007af5;
+ color: white;
+ border: none;
+ min-height: 2rem;
+ min-width: 2rem;
+ }
+
+ label {
+ align-self: flex-start;
+ font-weight: 600;
+ :after {
+ content: '${(props) => (props.required ? ' *' : '')}';
+ color: red;
+ }
+ }
+
+ .tone-icon {
+ font-size: 1.4rem;
+ margin-bottom: 0rem;
+ margin-left: 0.5rem;
+ }
+`;
diff --git a/app/subscriber/src/features/my-reports/edit/content/stories/styled/index.ts b/app/subscriber/src/features/my-reports/edit/content/stories/styled/index.ts
index b0dea81ab2..01a565be9c 100644
--- a/app/subscriber/src/features/my-reports/edit/content/stories/styled/index.ts
+++ b/app/subscriber/src/features/my-reports/edit/content/stories/styled/index.ts
@@ -1,2 +1,3 @@
export * from './ContentActions';
export * from './ReportSections';
+export * from './ToneSelector';
diff --git a/app/subscriber/src/features/my-reports/edit/validation/SentimentFormSchema.ts b/app/subscriber/src/features/my-reports/edit/validation/SentimentFormSchema.ts
deleted file mode 100644
index a48f63d476..0000000000
--- a/app/subscriber/src/features/my-reports/edit/validation/SentimentFormSchema.ts
+++ /dev/null
@@ -1,9 +0,0 @@
-import { array, number, object } from 'yup';
-
-export const sentimentFormSchema = object().shape({
- tonePools: array().of(
- object().shape({
- value: number().required('Tone value is required'),
- }),
- ),
-});
diff --git a/app/subscriber/src/store/hooks/lookup/useLookup.ts b/app/subscriber/src/store/hooks/lookup/useLookup.ts
index c4e3f92b13..e87ae665de 100644
--- a/app/subscriber/src/store/hooks/lookup/useLookup.ts
+++ b/app/subscriber/src/store/hooks/lookup/useLookup.ts
@@ -25,7 +25,6 @@ import {
StorageKeys,
useApiSubscriberCache,
useApiSubscriberMinisters,
- useApiSubscriberTonePools,
} from 'tno-core';
import { useAjaxWrapper } from '..';
@@ -45,7 +44,6 @@ export const useLookup = (): [ILookupState, ILookupController] => {
const cache = useApiSubscriberCache();
const lookups = useApiLookups();
const ministers = useApiSubscriberMinisters();
- const tonePools = useApiSubscriberTonePools();
const controller = React.useMemo(
() => ({
@@ -158,27 +156,13 @@ export const useLookup = (): [ILookupState, ILookupController] => {
'lookup',
);
},
- getTonePools: async () => {
- return await fetchIfNoneMatch(
- StorageKeys.TonePools,
- dispatch,
- (etag) => tonePools.getTonePools(etag),
- (results) => {
- const values = results ?? [];
- store.storeTonePools(values);
- return values;
- },
- true,
- 'lookup',
- );
- },
init: async () => {
// TODO: Handle failures
await controller.getLookups();
store.storeIsReady(true);
},
}),
- [cache, dispatch, lookups, ministers, tonePools, store],
+ [cache, dispatch, lookups, ministers, store],
);
return [state, controller];
diff --git a/app/subscriber/src/store/slices/profile/interfaces/IProfileState.ts b/app/subscriber/src/store/slices/profile/interfaces/IProfileState.ts
index d1a781251d..dcb0e58511 100644
--- a/app/subscriber/src/store/slices/profile/interfaces/IProfileState.ts
+++ b/app/subscriber/src/store/slices/profile/interfaces/IProfileState.ts
@@ -31,5 +31,5 @@ export interface IProfileState {
reportContent: { [reportId: number]: number[] };
contributors: IContributorModel[];
messages: ISystemMessageModel[];
- myTonePool: ITonePoolModel;
+ myTonePool: ITonePoolModel | undefined;
}
diff --git a/app/subscriber/src/store/slices/profile/profileSlice.ts b/app/subscriber/src/store/slices/profile/profileSlice.ts
index a9eb0bc45b..cf00fc03ca 100644
--- a/app/subscriber/src/store/slices/profile/profileSlice.ts
+++ b/app/subscriber/src/store/slices/profile/profileSlice.ts
@@ -29,15 +29,7 @@ export const initialProfileState: IProfileState = {
myColleagues: false,
myTonePool: false,
},
- myTonePool: {
- ownerId: 0,
- isPublic: false,
- id: 0,
- name: '',
- description: '',
- sortOrder: 0,
- isEnabled: false,
- },
+ myTonePool: undefined,
};
export const profileSlice = createSlice({
diff --git a/app/subscriber/src/store/slices/profile/useProfileStore.ts b/app/subscriber/src/store/slices/profile/useProfileStore.ts
index a330ffbb8e..66c5f0cd93 100644
--- a/app/subscriber/src/store/slices/profile/useProfileStore.ts
+++ b/app/subscriber/src/store/slices/profile/useProfileStore.ts
@@ -56,7 +56,7 @@ export interface IProfileStore {
storeMyMessages: (
messages: ISystemMessageModel[] | ActionDelegate,
) => void;
- storeMyTonePool: (tonePool: ITonePoolModel | ActionDelegate) => void;
+ storeMyTonePool: (tonePool: ITonePoolModel | ActionDelegate) => void;
}
export const useProfileStore = (): [IProfileState, IProfileStore] => {
@@ -141,10 +141,13 @@ export const useProfileStore = (): [IProfileState, IProfileStore] => {
dispatch(storeMyMessages(messages(state.messages)));
} else dispatch(storeMyMessages(messages));
},
- storeMyTonePool: (tonePool: ITonePoolModel | ActionDelegate) => {
+ storeMyTonePool: (tonePool: ITonePoolModel | ActionDelegate) => {
if (typeof tonePool === 'function') {
- dispatch(storeMyTonePool(tonePool(state.myTonePool)));
- } else {
+ const updatedTonePool = tonePool(state.myTonePool);
+ if (updatedTonePool !== undefined) {
+ dispatch(storeMyTonePool(updatedTonePool));
+ }
+ } else if (tonePool !== undefined) {
dispatch(storeMyTonePool(tonePool));
}
},
diff --git a/libs/net/dal/Extensions/ContentExtensions.cs b/libs/net/dal/Extensions/ContentExtensions.cs
index 8de22086c6..7a7f8b75c1 100644
--- a/libs/net/dal/Extensions/ContentExtensions.cs
+++ b/libs/net/dal/Extensions/ContentExtensions.cs
@@ -163,33 +163,29 @@ public static TNOContext UpdateContext(this TNOContext context, Content original
}
});
- var tonePoolsToAdd = new List();
-
- oTonePools.Except(updated.TonePoolsManyToMany).ForEach(a =>
- {
- context.Entry(a).State = EntityState.Deleted;
- });
updated.TonePoolsManyToMany.ForEach(a =>
{
var current = a.TonePoolId != 0 ? oTonePools.FirstOrDefault(o => o.TonePoolId == a.TonePoolId) : null;
+
+ // If no matching tone pool exists, add it to the original list
if (current == null)
{
a.TonePool ??= context.TonePools.FirstOrDefault(tp => tp.Id == a.TonePoolId);
- tonePoolsToAdd.Add(a);
+
+ if (a.TonePool != null &&
+ !original.TonePoolsManyToMany.Any(x => x.TonePool != null && x.TonePool.Id == a.TonePool.Id))
+ {
+ original.TonePoolsManyToMany.Add(a);
+ }
}
+ // If a matching tone pool is found but the values have changed, update the values
else if (current.Value != a.Value)
{
current.Value = a.Value;
current.Version = a.Version;
}
});
- tonePoolsToAdd.ForEach(a => {
- if (a.TonePool != null &&
- !original.TonePoolsManyToMany.Any(x => x.TonePool != null && x.TonePool.Id == a.TonePool.Id))
- {
- original.TonePoolsManyToMany.Add(a);
- }
- });
+
oTimeTrackings.Except(updated.TimeTrackings).ForEach(a =>
{
context.Entry(a).State = EntityState.Deleted;
diff --git a/libs/net/dal/Services/TonePoolService.cs b/libs/net/dal/Services/TonePoolService.cs
index 73bdbc0efd..3e6a815e85 100644
--- a/libs/net/dal/Services/TonePoolService.cs
+++ b/libs/net/dal/Services/TonePoolService.cs
@@ -27,7 +27,7 @@ public IEnumerable FindAll()
public TonePool? FindByUserId(int userId)
{
- return this.Context.TonePools.FirstOrDefault(tp => tp.OwnerId == userId && tp.IsPublic == true);
+ return this.Context.TonePools.FirstOrDefault(tp => tp.OwnerId == userId);
}
public override TonePool AddAndSave(TonePool entity)
diff --git a/libs/net/entities/Models/ContentVersion.cs b/libs/net/entities/Models/ContentVersion.cs
index 8d70790fdd..2dacc73e7e 100644
--- a/libs/net/entities/Models/ContentVersion.cs
+++ b/libs/net/entities/Models/ContentVersion.cs
@@ -56,10 +56,6 @@ public class ContentVersion
///
public bool IsPrivate { get; set; } = false;
- ///
- /// get/set - Tone for the content
- ///
- public int? Tone {get;set;}
#endregion
@@ -86,7 +82,6 @@ public ContentVersion(Content content, User owner)
this.Body = content.Body;
this.SourceUrl = content.SourceUrl;
this.IsPrivate = content.IsPrivate;
- this.Tone = content.TonePools.Count > 0 ? (int?)content.TonePools[0].Id : null;
}
///
@@ -98,4 +93,4 @@ public ContentVersion(int ownerId)
this.OwnerId = ownerId;
}
#endregion
-}
+}
\ No newline at end of file
diff --git a/libs/npm/core/src/components/formik/sentiment/FormikSentiment.tsx b/libs/npm/core/src/components/formik/sentiment/FormikSentiment.tsx
index de48a6e652..359488dee0 100644
--- a/libs/npm/core/src/components/formik/sentiment/FormikSentiment.tsx
+++ b/libs/npm/core/src/components/formik/sentiment/FormikSentiment.tsx
@@ -1,12 +1,11 @@
import { getIn, useFormikContext } from 'formik';
import React from 'react';
-import { FaFrown, FaMeh, FaSmile } from 'react-icons/fa';
import FaceFrownOpen from '../../../assets/face-frown-open.svg';
import FaceGrinWide from '../../../assets/face-grin-wide.svg';
import FaceMeh from '../../../assets/face-meh.svg';
import { Col, Error, Row } from '../../../components';
-import { IContentTonePoolModel, ITonePoolModel } from '../../../hooks';
+import { ITonePoolModel } from '../../../hooks';
import * as styled from './styled';
const toningOptions = [-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5];
@@ -18,14 +17,10 @@ export interface IFormikSentimentProps {
label?: string;
/** Sentiment options. */
options: ITonePoolModel[];
- /** Sentiment icon colored */
- coloredIcon?: boolean;
/** The name of the default tone pool */
defaultTonePoolName?: string;
/** The id of the default tone pool */
defaultTonePoolId?: number;
- /** Update upper form */
- onSentimentChange?: (tonePools: any) => void;
/** Whether this field is required. */
required?: boolean;
}
@@ -39,10 +34,8 @@ export const FormikSentiment = ({
name,
label = 'Sentiment',
options,
- coloredIcon = false,
defaultTonePoolId,
defaultTonePoolName = 'Default',
- onSentimentChange,
...rest
}: IFormikSentimentProps) => {
const { values, setFieldValue, touched, errors } = useFormikContext();
@@ -51,18 +44,14 @@ export const FormikSentiment = ({
name,
label,
options,
- coloredIcon,
defaultTonePoolId,
defaultTonePoolName,
- onSentimentChange,
...rest,
};
const defaultTonePool = options.find(
(t) => t.id === defaultTonePoolId || t.name === defaultTonePoolName,
);
-
- const tonePools = getIn(values, name.toString()) as IContentTonePoolModel[] | undefined;
-
+ const tonePools = getIn(values, name.toString());
const value =
tonePools && Array.isArray(tonePools) && tonePools.length ? tonePools[0].value : undefined;
@@ -75,65 +64,40 @@ export const FormikSentiment = ({
if (active !== value) {
setActive(value);
}
- }, [value, active]);
+ }, [active, value]);
const determineIndicator = (option: number) => {
if (option === 5) {
- return coloredIcon ? (
-
- ) : (
-
- );
+ return ;
} else if (option === 0) {
- return coloredIcon ? (
-
- ) : (
-
- );
+ return ;
} else if (option === -5) {
- return coloredIcon ? (
-
- ) : (
-
- );
+ return ;
} else {
return ;
}
};
- const handleOptionClick = (option: number) => {
- if (!defaultTonePool) return;
-
- setActive(option);
-
- const existingTonePoolIndex = tonePools?.findIndex((pool) => pool.id === defaultTonePool.id);
- let updatedTonePools;
-
- if (existingTonePoolIndex !== undefined && existingTonePoolIndex >= 0) {
- // Replace the existing TonePool value
- updatedTonePools = tonePools?.map((pool, index) =>
- index === existingTonePoolIndex ? { ...pool, value: option } : pool,
- );
- } else {
- // Add a new TonePool entry
- updatedTonePools = [...(tonePools || []), { ...defaultTonePool, value: option }];
- }
-
- setFieldValue(name.toString(), updatedTonePools, true);
- onSentimentChange?.(updatedTonePools);
- };
-
return (
+ {' '}
{toningOptions.map((option) => (
{determineIndicator(option)}
diff --git a/libs/npm/core/src/components/formik/sentiment/styled/FormikSentiment.tsx b/libs/npm/core/src/components/formik/sentiment/styled/FormikSentiment.tsx
index fe2288be35..4826efdf02 100644
--- a/libs/npm/core/src/components/formik/sentiment/styled/FormikSentiment.tsx
+++ b/libs/npm/core/src/components/formik/sentiment/styled/FormikSentiment.tsx
@@ -50,10 +50,4 @@ export const FormikSentiment = styled.div.attrs>(({ r
color: red;
}
}
-
- .tone-icon {
- font-size: 1.4rem;
- margin-bottom: 0rem;
- margin-left: 0.5rem;
- }
`;
diff --git a/libs/npm/core/src/hooks/api/interfaces/IContentTonePoolModel.ts b/libs/npm/core/src/hooks/api/interfaces/IContentTonePoolModel.ts
index 72bd8cf14e..c0fdf69046 100644
--- a/libs/npm/core/src/hooks/api/interfaces/IContentTonePoolModel.ts
+++ b/libs/npm/core/src/hooks/api/interfaces/IContentTonePoolModel.ts
@@ -1,5 +1,5 @@
import { ITonePoolModel } from '.';
export interface IContentTonePoolModel extends ITonePoolModel {
- value: number;
+ value: number | undefined;
}
diff --git a/libs/npm/core/src/hooks/api/interfaces/IContentVersionModel.ts b/libs/npm/core/src/hooks/api/interfaces/IContentVersionModel.ts
index a83a24618e..c4d79510ce 100644
--- a/libs/npm/core/src/hooks/api/interfaces/IContentVersionModel.ts
+++ b/libs/npm/core/src/hooks/api/interfaces/IContentVersionModel.ts
@@ -9,5 +9,4 @@ export interface IContentVersionModel extends IAuditColumnsModel {
page?: string;
summary?: string;
body?: string;
- tone?: number;
}
diff --git a/libs/npm/core/src/hooks/api/interfaces/ITonePool.ts b/libs/npm/core/src/hooks/api/interfaces/ITonePool.ts
new file mode 100644
index 0000000000..3c91975b4a
--- /dev/null
+++ b/libs/npm/core/src/hooks/api/interfaces/ITonePool.ts
@@ -0,0 +1,5 @@
+export interface ITonePool {
+ id: number;
+ name: string;
+ value?: number;
+}
diff --git a/libs/npm/core/src/hooks/api/interfaces/index.ts b/libs/npm/core/src/hooks/api/interfaces/index.ts
index 8879a3b5cb..f68c669cf9 100644
--- a/libs/npm/core/src/hooks/api/interfaces/index.ts
+++ b/libs/npm/core/src/hooks/api/interfaces/index.ts
@@ -106,6 +106,7 @@ export * from './ISystemMessageModel';
export * from './ITagFilter';
export * from './ITagModel';
export * from './ITimeTrackingModel';
+export * from './ITonePool';
export * from './ITonePoolModel';
export * from './ITopicFilter';
export * from './ITopicModel';
diff --git a/libs/npm/core/src/hooks/api/subscriber/useApiSubscriberTonePools.ts b/libs/npm/core/src/hooks/api/subscriber/useApiSubscriberTonePools.ts
index c9114ebd75..cb4af9f2c0 100644
--- a/libs/npm/core/src/hooks/api/subscriber/useApiSubscriberTonePools.ts
+++ b/libs/npm/core/src/hooks/api/subscriber/useApiSubscriberTonePools.ts
@@ -28,7 +28,6 @@ export const useApiSubscriberTonePools = (
);
},
getMyTonePool: (userId: number) => {
- console.log('getMyTonePool');
return api.get, any>(
`/subscriber/tonePool/user/${userId}`,
);
diff --git a/libs/npm/core/tsconfig.json b/libs/npm/core/tsconfig.json
index 99314a1ff8..adf8c04df1 100644
--- a/libs/npm/core/tsconfig.json
+++ b/libs/npm/core/tsconfig.json
@@ -7,10 +7,11 @@
"declaration": true,
"declarationMap": true,
"emitDeclarationOnly": false,
- "lib": ["dom", "dom.iterable", "esnext"],
- "paths": {
- "@assets/*": ["../../../../app/subscriber/public/assets/*"]
- },
+ "lib": [
+ "dom",
+ "dom.iterable",
+ "esnext"
+ ],
"allowJs": true,
"skipLibCheck": true,
"esModuleInterop": true,
@@ -26,8 +27,13 @@
"inlineSources": true,
"isolatedModules": true,
"jsx": "react-jsx",
- "typeRoots": ["src/@types", "node_modules/@types"]
+ "typeRoots": [
+ "src/@types",
+ "node_modules/@types"
+ ]
},
- "include": ["src"],
+ "include": [
+ "src"
+ ],
"exclude": ["node_modules", "dist"]
-}
+}
\ No newline at end of file
diff --git a/libs/npm/core/webpack.config.js b/libs/npm/core/webpack.config.js
index bd15ff9f6d..3b435267fa 100644
--- a/libs/npm/core/webpack.config.js
+++ b/libs/npm/core/webpack.config.js
@@ -12,9 +12,6 @@ module.exports = {
],
},
resolve: {
- alias: {
- '@assets': path.resolve(__dirname, '../../../../app/subscriber/public/assets'),
- },
extensions: ['.tsx', '.ts', '.js'],
},
output: {
@@ -24,9 +21,3 @@ module.exports = {
},
devtool: 'source-map',
};
-
-// Add this to print the resolved alias path
-console.log(
- 'Resolved @assets path:',
- path.resolve(__dirname, '../../../../app/subscriber/public/assets'),
-);