From 3bf32195c24e24b420c0e00659af1c03da182113 Mon Sep 17 00:00:00 2001 From: Akansha Sakhre Date: Fri, 10 Jan 2025 22:45:34 +0530 Subject: [PATCH 01/38] create and manage polls --- src/assets/images/Polls.svg | 6 + .../images/icons/SideDrawer/WaPolls.tsx | 9 ++ src/common/HelpData.tsx | 5 + src/components/UI/ListIcon/ListIcon.tsx | 6 +- src/config/menu.ts | 39 +++-- .../WaPollOptions/WaPollOptions.module.css | 46 ++++++ .../WaPolls/WaPollOptions/WaPollOptions.tsx | 146 ++++++++++++++++++ .../WaGroups/WaPolls/WaPolls.module.css | 7 + src/containers/WaGroups/WaPolls/WaPolls.tsx | 101 ++++++++++++ .../WaPollsList/WaPollsList.module.css | 26 ++++ .../WaPolls/WaPollsList/WaPollsList.tsx | 128 +++++++++++++++ src/i18n/en/en.json | 3 +- .../AuthenticatedRoute/AuthenticatedRoute.tsx | 6 + 13 files changed, 509 insertions(+), 19 deletions(-) create mode 100644 src/assets/images/Polls.svg create mode 100644 src/assets/images/icons/SideDrawer/WaPolls.tsx create mode 100644 src/containers/WaGroups/WaPolls/WaPollOptions/WaPollOptions.module.css create mode 100644 src/containers/WaGroups/WaPolls/WaPollOptions/WaPollOptions.tsx create mode 100644 src/containers/WaGroups/WaPolls/WaPolls.module.css create mode 100644 src/containers/WaGroups/WaPolls/WaPolls.tsx create mode 100644 src/containers/WaGroups/WaPolls/WaPollsList/WaPollsList.module.css create mode 100644 src/containers/WaGroups/WaPolls/WaPollsList/WaPollsList.tsx diff --git a/src/assets/images/Polls.svg b/src/assets/images/Polls.svg new file mode 100644 index 0000000000..8dbba865e0 --- /dev/null +++ b/src/assets/images/Polls.svg @@ -0,0 +1,6 @@ + + + \ No newline at end of file diff --git a/src/assets/images/icons/SideDrawer/WaPolls.tsx b/src/assets/images/icons/SideDrawer/WaPolls.tsx new file mode 100644 index 0000000000..062ca16a0f --- /dev/null +++ b/src/assets/images/icons/SideDrawer/WaPolls.tsx @@ -0,0 +1,9 @@ +const SvgComponent = ({ color }: { color: string }) => ( + + + +); +export default SvgComponent; diff --git a/src/common/HelpData.tsx b/src/common/HelpData.tsx index 4bd0ea9b3f..a40dbe7456 100644 --- a/src/common/HelpData.tsx +++ b/src/common/HelpData.tsx @@ -129,3 +129,8 @@ export const templateStatusInfo: HelpDataProps = { ), link: 'https://docs.gupshup.io/docs/message-template-approvals-statuses', }; + +export const pollsInfo: HelpDataProps = { + heading: 'An overview of all the polls created to date', + link: 'https://glific.github.io/docs/docs/category/flows', +}; diff --git a/src/components/UI/ListIcon/ListIcon.tsx b/src/components/UI/ListIcon/ListIcon.tsx index d991108572..545e387434 100644 --- a/src/components/UI/ListIcon/ListIcon.tsx +++ b/src/components/UI/ListIcon/ListIcon.tsx @@ -29,10 +29,11 @@ import WaCollectionIcon from 'assets/images/icons/SideDrawer/WaGroupCollection'; import WaGroupIcon from 'assets/images/icons/SideDrawer/WhatsAppGroupIcon'; import KnowledgeBaseIcon from 'assets/images/icons/SideDrawer/KnowledgeBaseIcon'; import Assistant from 'assets/images/icons/SideDrawer/Assistant'; +import WaPolls from 'assets/images/icons/SideDrawer/WaPolls'; import styles from './ListIcon.module.css'; import FiberNewIcon from '@mui/icons-material/FiberNew'; import { Badge } from '@mui/material'; -import DiscordIcon from 'assets/images/icons/Discord/DiscordIcon' +import DiscordIcon from 'assets/images/icons/Discord/DiscordIcon'; export interface ListIconProps { icon: string | undefined; count?: number; @@ -75,7 +76,8 @@ export const ListIcon = ({ icon = '', selected = false, count }: ListIconProps) waGroup: WaGroupIcon, knowledgeBase: KnowledgeBaseIcon, assistant: Assistant, - discord:DiscordIcon + discord: DiscordIcon, + waPolls: WaPolls, }; const iconImage = stringsToIcons[icon] && ( diff --git a/src/config/menu.ts b/src/config/menu.ts index 24245f506b..2ee5504066 100644 --- a/src/config/menu.ts +++ b/src/config/menu.ts @@ -51,6 +51,13 @@ const menus = (): Menu[] => [ type: 'sideDrawer', roles: allRoles, }, + { + title: 'WhatsApp Polls', + path: '/group/polls', + icon: 'waPolls', + type: 'sideDrawer', + roles: allRoles, + }, ], }, { @@ -279,22 +286,22 @@ const menus = (): Menu[] => [ roles: staffLevel, }, - // { - // title: "What's new", - // path: '/changelog', - // url: NEW_UI_BLOG, - // icon: 'new', - // type: 'sideDrawer', - // roles: staffLevel, - // }, - { - title: "Discord", - path: '/discord', - url: DISCORD_URL, - icon: 'discord', - type: 'sideDrawer', - roles: staffLevel, - }, + // { + // title: "What's new", + // path: '/changelog', + // url: NEW_UI_BLOG, + // icon: 'new', + // type: 'sideDrawer', + // roles: staffLevel, + // }, + { + title: 'Discord', + path: '/discord', + url: DISCORD_URL, + icon: 'discord', + type: 'sideDrawer', + roles: staffLevel, + }, ]; export const getMenus = (menuType = 'sideDrawer', role = 'Staff') => diff --git a/src/containers/WaGroups/WaPolls/WaPollOptions/WaPollOptions.module.css b/src/containers/WaGroups/WaPolls/WaPollOptions/WaPollOptions.module.css new file mode 100644 index 0000000000..5494979456 --- /dev/null +++ b/src/containers/WaGroups/WaPolls/WaPollOptions/WaPollOptions.module.css @@ -0,0 +1,46 @@ +.Container { + background-color: #f8faf5; + border: 1px solid #cccccc; + border-radius: 4px; + margin: 1rem 0; + padding: 1rem; +} + +.Title { + color: #555555; + font-weight: 500; + line-height: 18px; + font-size: 16px; + margin-bottom: 1rem; +} + +.OptionField { + display: flex; + gap: 1rem; + align-items: center; +} + +.TextField { + width: 100%; + background-color: #ffffff; + border-radius: 12px; +} + +.Options { + display: flex; + flex-direction: column; + gap: 1rem; +} + +.Options button { + width: 40%; + align-self: flex-end; +} + +.RemoveIcon { + cursor: pointer; +} + +.EmojiButton { + margin-right: -1rem; +} diff --git a/src/containers/WaGroups/WaPolls/WaPollOptions/WaPollOptions.tsx b/src/containers/WaGroups/WaPolls/WaPollOptions/WaPollOptions.tsx new file mode 100644 index 0000000000..20aebc3b4c --- /dev/null +++ b/src/containers/WaGroups/WaPolls/WaPollOptions/WaPollOptions.tsx @@ -0,0 +1,146 @@ +import { ClickAwayListener, FormControl, FormHelperText, IconButton, TextField, Typography } from '@mui/material'; +import styles from './WaPollOptions.module.css'; +import { Button } from 'components/UI/Form/Button/Button'; +import CrossIcon from 'assets/images/icons/Cross.svg?react'; +import EmojiPicker from 'components/UI/EmojiPicker/EmojiPicker'; +import { useState } from 'react'; +import EmojiEmotionsOutlinedIcon from '@mui/icons-material/EmojiEmotionsOutlined'; + +interface WaPollOptionsProps { + form: { field: any; errors: any; touched: any; values: any; setFieldValue: any }; + options: string[]; +} + +const emojiStyles = { + position: 'absolute', + bottom: '25px', + right: '-150px', + zIndex: 100, +}; + +export const WaPollOptions = ({ form: { values, setFieldValue, errors, touched } }: WaPollOptionsProps) => { + const handleAddOption = () => { + setFieldValue('options', [...values.options, '']); + }; + + const handleInput = (value: any, ind: any) => { + const newOptions = [...values.options]; + newOptions[ind] = value; + setFieldValue('options', newOptions); + }; + + const handleEmojiAdd = (emoji: any, ind: number) => { + console.log(emoji); + + const newOptions = [...values.options]; + const value = newOptions[ind] + emoji?.native; + newOptions[ind] = value; + setFieldValue('options', newOptions); + }; + + const handleRemoveClick = (index: any) => { + const newOptions = [...values.options]; + setFieldValue( + 'options', + newOptions.filter((_, ind: any) => ind !== index) + ); + }; + + return ( +
+ + Poll Options + +
+ {values.options.map((option: any, ind: number) => ( + + ))} + {values.options.length < 10 && ( + + )} +
+
+ ); +}; + +interface PollOptionProps { + option: string; + ind: number; + options: any; + errors: any; + touched: any; + handleInput: any; + handleRemoveClick: any; + handleEmojiAdd: any; +} + +const PollOption = ({ + option, + ind, + options, + errors, + touched, + handleInput, + handleRemoveClick, + handleEmojiAdd, +}: PollOptionProps) => { + const [showEmojiPicker, setShowEmojiPicker] = useState(false); + const hasError = errors && touched && errors[ind] && touched[ind]; + + return ( + +
+ handleInput(event.target.value, ind)} + slotProps={{ + input: { + endAdornment: ( + setShowEmojiPicker(false)}> + setShowEmojiPicker(!showEmojiPicker)} + > + + + + ), + }, + }} + /> + + {options.length !== 2 && ( + handleRemoveClick(ind)} + /> + )} + {showEmojiPicker && ( + handleEmojiAdd(emoji, ind)} displayStyle={emojiStyles} /> + )} +
+ {hasError ? {errors[ind]} : null} +
+ ); +}; diff --git a/src/containers/WaGroups/WaPolls/WaPolls.module.css b/src/containers/WaGroups/WaPolls/WaPolls.module.css new file mode 100644 index 0000000000..d3ebe260eb --- /dev/null +++ b/src/containers/WaGroups/WaPolls/WaPolls.module.css @@ -0,0 +1,7 @@ +.AllowMultiple { + color: #555555; + font-weight: 400; + line-height: 18px; + font-size: 16px; + padding: 1rem 0; +} diff --git a/src/containers/WaGroups/WaPolls/WaPolls.tsx b/src/containers/WaGroups/WaPolls/WaPolls.tsx new file mode 100644 index 0000000000..7678a44ed1 --- /dev/null +++ b/src/containers/WaGroups/WaPolls/WaPolls.tsx @@ -0,0 +1,101 @@ +import { Typography } from '@mui/material'; +import { Input } from 'components/UI/Form/Input/Input'; +import { FormLayout } from 'containers/Form/FormLayout'; +import { CREATE_COLLECTION, DELETE_COLLECTION, UPDATE_COLLECTION } from 'graphql/mutations/Collection'; +import { GET_COLLECTION } from 'graphql/queries/Collection'; +import { useState } from 'react'; +import { useTranslation } from 'react-i18next'; +import * as Yup from 'yup'; +import PollsIcon from 'assets/images/Polls.svg?react'; +import { Checkbox } from 'components/UI/Form/Checkbox/Checkbox'; +import styles from './WaPolls.module.css'; +import { WaPollOptions } from './WaPollOptions/WaPollOptions'; +const queries = { + getItemQuery: GET_COLLECTION, + createItemQuery: CREATE_COLLECTION, + updateItemQuery: UPDATE_COLLECTION, + deleteItemQuery: DELETE_COLLECTION, +}; +const pollsIcon = ; + +export const WaPolls = () => { + const [title, setTitle] = useState(''); + const [content, setContent] = useState(''); + const [options, setOptions] = useState(['', '']); + const [allowMultiple, setAllowMultiple] = useState(false); + + const { t } = useTranslation(); + const states = { + title, + content, + options, + allowMultiple, + }; + + const setPayload = (payload: any) => { + console.log(payload); + return payload; + }; + const setStates = (payload: any) => {}; + + const FormSchema = Yup.object().shape({ + title: Yup.string().required(t('Title is required.')).max(50, t('Title is too long.')), + content: Yup.string().required('Content is required.').max(150, 'Content is too long.'), + options: Yup.array().of(Yup.string().required('Required')).min(2, 'At least two options are required'), + }); + + const dialogMessage = "You won't be able to use this poll again."; + + const formFields = [ + { + component: Input, + name: 'title', + type: 'text', + label: t('Title'), + }, + + { + component: Input, + name: 'content', + type: 'text', + label: 'Content', + textArea: true, + rows: 6, + }, + { + component: WaPollOptions, + name: 'options', + }, + { + component: Checkbox, + name: 'allowMultiple', + title: ( + + Allow multiple options + + ), + darkCheckbox: true, + }, + ]; + + return ( + + ); +}; + +export default WaPolls; diff --git a/src/containers/WaGroups/WaPolls/WaPollsList/WaPollsList.module.css b/src/containers/WaGroups/WaPolls/WaPollsList/WaPollsList.module.css new file mode 100644 index 0000000000..be8204cbb0 --- /dev/null +++ b/src/containers/WaGroups/WaPolls/WaPollsList/WaPollsList.module.css @@ -0,0 +1,26 @@ +.Label { + width: 300px; +} + +.Content { + width: 400px; +} + +.Actions { + width: 30%; + min-width: 200px; + text-align: end; +} + +.LabelText { + font-weight: 500; + font-size: 17px; + line-height: 20px; + color: #191c1a; + display: flex; + align-items: center; +} + +.DialogText { + text-align: center; +} diff --git a/src/containers/WaGroups/WaPolls/WaPollsList/WaPollsList.tsx b/src/containers/WaGroups/WaPolls/WaPollsList/WaPollsList.tsx new file mode 100644 index 0000000000..5f09091f70 --- /dev/null +++ b/src/containers/WaGroups/WaPolls/WaPollsList/WaPollsList.tsx @@ -0,0 +1,128 @@ +import { useTranslation } from 'react-i18next'; +import CollectionIcon from 'assets/images/icons/Collection/Dark.svg?react'; +import DeleteIcon from 'assets/images/icons/Delete/Red.svg?react'; +import DuplicateIcon from 'assets/images/icons/Duplicate.svg?react'; +import { FILTER_COLLECTIONS, GET_COLLECTIONS_COUNT } from 'graphql/queries/Collection'; +import { DELETE_COLLECTION } from 'graphql/mutations/Collection'; +const queries = { + countQuery: GET_COLLECTIONS_COUNT, + filterItemsQuery: FILTER_COLLECTIONS, + deleteItemQuery: DELETE_COLLECTION, +}; + +import styles from './WaPollsList.module.css'; +import { List } from 'containers/List/List'; +import { useState } from 'react'; +import { useNavigate } from 'react-router'; +import { pollsInfo } from 'common/HelpData'; +import { DialogBox } from 'components/UI/DialogBox/DialogBox'; + +const getLabel = (label: string) =>
{label}
; + +const getContent = (content: string, id: number) => { + const content1 = + 'Which of our communication channels do you find most effective for staying updated on our activities?'; + const content2 = + 'How frequently do you participate in our activities or events, and what influences your level of involvement? Which day works best for our upcoming community workshops?'; + if (!content) { + content = id % 2 === 0 ? content1 : content2; + } + + return
{content.length < 100 ? content : `${content.slice(0, 100)}...`}
; +}; +export const WaPollsList = () => { + const [deleteItemId, setDeleteItemId] = useState(null); + + const { t } = useTranslation(); + const navigate = useNavigate(); + + const columnNames = [{ name: 'label', label: 'Title' }, { label: 'Content' }, { label: t('Actions') }]; + const title = t('Group polls'); + const collectionIcon = ; + const dialogMessage = t("You won't be able to use this collection again."); + const columnStyles = [styles.Label, styles.Content, styles.Actions]; + + const getColumns = ({ label, content, id }: any) => { + return { + label: getLabel(label), + content: getContent(content, id), + }; + }; + + const columnAttributes = { + columns: getColumns, + columnStyles, + }; + + const handleCopy = (id: any) => { + navigate(`/group/polls/${id}/edit`, { state: 'copy' }); + }; + + const handleDelete = () => { + console.log('deleteItemId', deleteItemId); + }; + + const getRestrictedAction = () => { + const action: any = { edit: false, delete: false }; + return action; + }; + + const additionalAction = () => [ + { + label: t('Copy'), + icon: , + parameter: 'id', + insideMore: false, + dialog: handleCopy, + }, + { + label: t('Delete'), + icon: , + parameter: 'label', + dialog: (id: any) => setDeleteItemId(id), + insideMore: false, + }, + ]; + + const deletedialog = ( + setDeleteItemId(null)} + alignButtons="center" + colorOk={'warning'} + buttonOk={'Delete'} + > +

+ This action is permanent and cannot be undone. Deleting this poll will remove all associated responses and data + from the platform. +

+
+ ); + + return ( + <> + + {deleteItemId && deletedialog} + + ); +}; + +export default WaPollsList; diff --git a/src/i18n/en/en.json b/src/i18n/en/en.json index 99e5e250c1..e2fb3db4fa 100644 --- a/src/i18n/en/en.json +++ b/src/i18n/en/en.json @@ -532,5 +532,6 @@ "First name is required.": "First Name is required.", "Last name is required.": "Last name is required.", "Failed": "Failed", - "Members": "Members" + "Members": "Members", + "Group polls": "Group polls" } diff --git a/src/routes/AuthenticatedRoute/AuthenticatedRoute.tsx b/src/routes/AuthenticatedRoute/AuthenticatedRoute.tsx index d5bf980390..96e3252dc7 100644 --- a/src/routes/AuthenticatedRoute/AuthenticatedRoute.tsx +++ b/src/routes/AuthenticatedRoute/AuthenticatedRoute.tsx @@ -62,6 +62,8 @@ const RoleList = lazy(() => import('containers/Role/RoleList/RoleList')); const Role = lazy(() => import('containers/Role/Role')); const KnowledgeBase = lazy(() => import('containers/KnowledgeBase/KnowledgeBase')); const Assistant = lazy(() => import('containers/Assistants/Assistants')); +const WaPollsCreate = lazy(() => import('containers/WaGroups/WaPolls/WaPolls')); +const WaPollsList = lazy(() => import('containers/WaGroups/WaPolls/WaPollsList/WaPollsList')); const routeStaff = ( @@ -148,6 +150,10 @@ const routeAdmin = ( } /> } /> + } /> + } /> + } /> + } /> ); From c1aaa7312f1ea5330fb3adf50ff80bf6e262bb70 Mon Sep 17 00:00:00 2001 From: Akansha Sakhre Date: Mon, 13 Jan 2025 18:19:33 +0530 Subject: [PATCH 02/38] connected apis --- src/containers/Form/FormLayout.tsx | 4 +- .../WaPolls/WaPollOptions/WaPollOptions.tsx | 65 ++++++------- src/containers/WaGroups/WaPolls/WaPolls.tsx | 94 +++++++++++++++---- .../WaPolls/WaPollsList/WaPollsList.tsx | 43 ++++++--- src/graphql/mutations/WaPolls.ts | 39 ++++++++ src/graphql/queries/WaPolls.ts | 34 +++++++ 6 files changed, 212 insertions(+), 67 deletions(-) create mode 100644 src/graphql/mutations/WaPolls.ts create mode 100644 src/graphql/queries/WaPolls.ts diff --git a/src/containers/Form/FormLayout.tsx b/src/containers/Form/FormLayout.tsx index ee7ce54b7a..9762b490dc 100644 --- a/src/containers/Form/FormLayout.tsx +++ b/src/containers/Form/FormLayout.tsx @@ -216,10 +216,10 @@ export const FormLayout = ({ // Clearning unnecessary fields delete payloadBody.billingId; } - + // TODO: Change this back updateItem({ variables: { - [idKey]: idVal, + copyWaPollId: idVal, input: payloadBody, }, }); diff --git a/src/containers/WaGroups/WaPolls/WaPollOptions/WaPollOptions.tsx b/src/containers/WaGroups/WaPolls/WaPollOptions/WaPollOptions.tsx index 20aebc3b4c..cfe909cfdd 100644 --- a/src/containers/WaGroups/WaPolls/WaPollOptions/WaPollOptions.tsx +++ b/src/containers/WaGroups/WaPolls/WaPollOptions/WaPollOptions.tsx @@ -9,6 +9,7 @@ import EmojiEmotionsOutlinedIcon from '@mui/icons-material/EmojiEmotionsOutlined interface WaPollOptionsProps { form: { field: any; errors: any; touched: any; values: any; setFieldValue: any }; options: string[]; + isEditing: boolean; } const emojiStyles = { @@ -18,32 +19,27 @@ const emojiStyles = { zIndex: 100, }; -export const WaPollOptions = ({ form: { values, setFieldValue, errors, touched } }: WaPollOptionsProps) => { +export const WaPollOptions = ({ form: { values, setFieldValue, errors, touched }, isEditing }: WaPollOptionsProps) => { const handleAddOption = () => { - setFieldValue('options', [...values.options, '']); + setFieldValue('options', [...values.options, { name: '', id: values.options.length }]); }; - const handleInput = (value: any, ind: any) => { - const newOptions = [...values.options]; - newOptions[ind] = value; + const handleInput = (value: any, id: any) => { + const newOptions = values.options.map((option: any) => (option.id === id ? { ...option, name: value } : option)); setFieldValue('options', newOptions); }; - const handleEmojiAdd = (emoji: any, ind: number) => { - console.log(emoji); + const handleEmojiAdd = (emoji: any, id: number) => { + const newOptions = values.options.map((option: any) => + option.id === id ? { ...option, name: option.name + emoji.native } : option + ); - const newOptions = [...values.options]; - const value = newOptions[ind] + emoji?.native; - newOptions[ind] = value; setFieldValue('options', newOptions); }; - const handleRemoveClick = (index: any) => { - const newOptions = [...values.options]; - setFieldValue( - 'options', - newOptions.filter((_, ind: any) => ind !== index) - ); + const handleRemoveClick = (id: any) => { + const newOptions = values.options.filter((option: any) => option.id !== id); + setFieldValue('options', newOptions); }; return ( @@ -54,8 +50,7 @@ export const WaPollOptions = ({ form: { values, setFieldValue, errors, touched }
{values.options.map((option: any, ind: number) => ( ))} - {values.options.length < 10 && ( + + {errors['options'] && typeof errors['options'] === 'string' && errors['options']} + + + {values.options.length < 10 && !isEditing && ( @@ -76,41 +76,42 @@ export const WaPollOptions = ({ form: { values, setFieldValue, errors, touched } }; interface PollOptionProps { - option: string; - ind: number; + option: any; options: any; errors: any; touched: any; handleInput: any; handleRemoveClick: any; handleEmojiAdd: any; + isEditing: boolean; } const PollOption = ({ option, - ind, options, errors, touched, handleInput, handleRemoveClick, handleEmojiAdd, + isEditing, }: PollOptionProps) => { const [showEmojiPicker, setShowEmojiPicker] = useState(false); - const hasError = errors && touched && errors[ind] && touched[ind]; + const hasError = errors && typeof errors !== 'string' && touched && errors[option.id] && touched[option.id]; return ( - +
handleInput(event.target.value, ind)} + placeholder={`Option ${option.id + 1}`} + value={option?.name} + onChange={(event) => handleInput(event.target.value, option?.id)} + disabled={isEditing} slotProps={{ input: { - endAdornment: ( + endAdornment: !isEditing && ( setShowEmojiPicker(false)}> handleRemoveClick(ind)} + onClick={() => handleRemoveClick(option.id)} /> )} {showEmojiPicker && ( - handleEmojiAdd(emoji, ind)} displayStyle={emojiStyles} /> + handleEmojiAdd(emoji, option.id)} displayStyle={emojiStyles} /> )}
- {hasError ? {errors[ind]} : null} + {hasError ? {errors[option.id]} : null}
); }; diff --git a/src/containers/WaGroups/WaPolls/WaPolls.tsx b/src/containers/WaGroups/WaPolls/WaPolls.tsx index 7678a44ed1..5809ab5946 100644 --- a/src/containers/WaGroups/WaPolls/WaPolls.tsx +++ b/src/containers/WaGroups/WaPolls/WaPolls.tsx @@ -1,8 +1,6 @@ import { Typography } from '@mui/material'; import { Input } from 'components/UI/Form/Input/Input'; import { FormLayout } from 'containers/Form/FormLayout'; -import { CREATE_COLLECTION, DELETE_COLLECTION, UPDATE_COLLECTION } from 'graphql/mutations/Collection'; -import { GET_COLLECTION } from 'graphql/queries/Collection'; import { useState } from 'react'; import { useTranslation } from 'react-i18next'; import * as Yup from 'yup'; @@ -10,38 +8,92 @@ import PollsIcon from 'assets/images/Polls.svg?react'; import { Checkbox } from 'components/UI/Form/Checkbox/Checkbox'; import styles from './WaPolls.module.css'; import { WaPollOptions } from './WaPollOptions/WaPollOptions'; +import { COPY_POLL, CREATE_POLL, DELETE_POLL } from 'graphql/mutations/WaPolls'; +import { GET_POLL } from 'graphql/queries/WaPolls'; +import { useLocation, useParams } from 'react-router'; + const queries = { - getItemQuery: GET_COLLECTION, - createItemQuery: CREATE_COLLECTION, - updateItemQuery: UPDATE_COLLECTION, - deleteItemQuery: DELETE_COLLECTION, + getItemQuery: GET_POLL, + createItemQuery: CREATE_POLL, + deleteItemQuery: DELETE_POLL, + updateItemQuery: COPY_POLL, }; const pollsIcon = ; +let idType = 'waPollId'; export const WaPolls = () => { - const [title, setTitle] = useState(''); + const [label, setLabel] = useState(''); const [content, setContent] = useState(''); - const [options, setOptions] = useState(['', '']); + const [options, setOptions] = useState([ + { id: 0, name: '' }, + { id: 1, name: '' }, + ]); const [allowMultiple, setAllowMultiple] = useState(false); - const { t } = useTranslation(); + const params = useParams(); + const location = useLocation(); + + let isEditing = false; + let isCopyState = false; + if (params.id) { + isEditing = true; + } + if (location.state === 'copy') { + console.log('copy state'); + isCopyState = true; + isEditing = false; + } + const states = { - title, + label, content, options, allowMultiple, }; const setPayload = (payload: any) => { - console.log(payload); - return payload; + let payloadCopy = { ...payload }; + const poll_content = JSON.stringify({ + options: payload.options, + text: payload.content, + }); + payloadCopy = { + ...payloadCopy, + poll_content, + allow_multiple_answer: payload.allowMultiple, + }; + delete payloadCopy.options; + delete payloadCopy.content; + delete payloadCopy.allowMultiple; + + if (isCopyState) { + idType = 'copyWaPollId'; + } + return payloadCopy; + }; + const setStates = (states: any) => { + const { label, pollContent, allowMultipleAnswer } = states; + const { text, options } = JSON.parse(pollContent); + let labelValue = label; + if (isCopyState) { + labelValue = `Copy of ${label}`; + } + + setLabel(labelValue); + setAllowMultiple(allowMultipleAnswer); + setContent(text); + setOptions(options); }; - const setStates = (payload: any) => {}; const FormSchema = Yup.object().shape({ - title: Yup.string().required(t('Title is required.')).max(50, t('Title is too long.')), + label: Yup.string().required(t('Title is required.')).max(50, t('Title is too long.')), content: Yup.string().required('Content is required.').max(150, 'Content is too long.'), - options: Yup.array().of(Yup.string().required('Required')).min(2, 'At least two options are required'), + options: Yup.array() + .of(Yup.object().shape({ name: Yup.string().required('Option is required.') })) + .test('unique-values', 'Values must be unique', (array: any) => { + const values = array.map((item: any) => item.name); + return new Set(values).size === values.length; + }), }); const dialogMessage = "You won't be able to use this poll again."; @@ -49,9 +101,10 @@ export const WaPolls = () => { const formFields = [ { component: Input, - name: 'title', + name: 'label', type: 'text', label: t('Title'), + disabled: isEditing, }, { @@ -61,10 +114,12 @@ export const WaPolls = () => { label: 'Content', textArea: true, rows: 6, + disabled: isEditing, }, { component: WaPollOptions, name: 'options', + isEditing, }, { component: Checkbox, @@ -75,6 +130,7 @@ export const WaPolls = () => { ), darkCheckbox: true, + disabled: isEditing, }, ]; @@ -86,13 +142,15 @@ export const WaPolls = () => { languageSupport={false} setStates={setStates} validationSchema={FormSchema} - listItemName="collection" + listItemName="waPoll" dialogMessage={dialogMessage} formFields={formFields} redirectionLink={'group/polls'} - listItem="polls" + listItem="waPoll" icon={pollsIcon} backLinkButton={`/group/polls`} + entityId={params.id} + idType={idType} {...queries} /> ); diff --git a/src/containers/WaGroups/WaPolls/WaPollsList/WaPollsList.tsx b/src/containers/WaGroups/WaPolls/WaPollsList/WaPollsList.tsx index 5f09091f70..33a0c821d7 100644 --- a/src/containers/WaGroups/WaPolls/WaPollsList/WaPollsList.tsx +++ b/src/containers/WaGroups/WaPolls/WaPollsList/WaPollsList.tsx @@ -2,20 +2,22 @@ import { useTranslation } from 'react-i18next'; import CollectionIcon from 'assets/images/icons/Collection/Dark.svg?react'; import DeleteIcon from 'assets/images/icons/Delete/Red.svg?react'; import DuplicateIcon from 'assets/images/icons/Duplicate.svg?react'; -import { FILTER_COLLECTIONS, GET_COLLECTIONS_COUNT } from 'graphql/queries/Collection'; -import { DELETE_COLLECTION } from 'graphql/mutations/Collection'; -const queries = { - countQuery: GET_COLLECTIONS_COUNT, - filterItemsQuery: FILTER_COLLECTIONS, - deleteItemQuery: DELETE_COLLECTION, -}; - import styles from './WaPollsList.module.css'; import { List } from 'containers/List/List'; import { useState } from 'react'; import { useNavigate } from 'react-router'; import { pollsInfo } from 'common/HelpData'; import { DialogBox } from 'components/UI/DialogBox/DialogBox'; +import { GET_POLLS, GET_POLLS_COUNT } from 'graphql/queries/WaPolls'; +import { DELETE_POLL } from 'graphql/mutations/WaPolls'; +import { useMutation } from '@apollo/client'; +import { setErrorMessage, setNotification } from 'common/notification'; + +const queries = { + countQuery: GET_POLLS_COUNT, + filterItemsQuery: GET_POLLS, + deleteItemQuery: DELETE_POLL, +}; const getLabel = (label: string) =>
{label}
; @@ -31,11 +33,13 @@ const getContent = (content: string, id: number) => { return
{content.length < 100 ? content : `${content.slice(0, 100)}...`}
; }; export const WaPollsList = () => { - const [deleteItemId, setDeleteItemId] = useState(null); + const [deleteWaPollId, setDeleteWaPollId] = useState(null); const { t } = useTranslation(); const navigate = useNavigate(); + const [deletePoll, { loading }] = useMutation(DELETE_POLL); + const columnNames = [{ name: 'label', label: 'Title' }, { label: 'Content' }, { label: t('Actions') }]; const title = t('Group polls'); const collectionIcon = ; @@ -59,7 +63,14 @@ export const WaPollsList = () => { }; const handleDelete = () => { - console.log('deleteItemId', deleteItemId); + deletePoll({ + variables: { deleteWaPollId }, + onCompleted: () => { + setNotification('Poll deleted successfully', 'success'); + setDeleteWaPollId(null); + }, + onError: (error) => setErrorMessage(error), + }); }; const getRestrictedAction = () => { @@ -79,7 +90,7 @@ export const WaPollsList = () => { label: t('Delete'), icon: , parameter: 'label', - dialog: (id: any) => setDeleteItemId(id), + dialog: (id: any) => setDeleteWaPollId(id), insideMore: false, }, ]; @@ -88,10 +99,12 @@ export const WaPollsList = () => { setDeleteItemId(null)} + handleCancel={() => setDeleteWaPollId(null)} alignButtons="center" colorOk={'warning'} buttonOk={'Delete'} + buttonOkLoading={loading} + disableOk={loading} >

This action is permanent and cannot be undone. Deleting this poll will remove all associated responses and data @@ -104,9 +117,9 @@ export const WaPollsList = () => { <> { {...queries} {...columnAttributes} /> - {deleteItemId && deletedialog} + {deleteWaPollId && deletedialog} ); }; diff --git a/src/graphql/mutations/WaPolls.ts b/src/graphql/mutations/WaPolls.ts new file mode 100644 index 0000000000..af0b390d4e --- /dev/null +++ b/src/graphql/mutations/WaPolls.ts @@ -0,0 +1,39 @@ +import { gql } from '@apollo/client'; + +export const CREATE_POLL = gql` + mutation CreateWaPoll($input: WaPollInput!) { + createWaPoll(input: $input) { + errors { + message + } + waPoll { + id + } + } + } +`; + +export const COPY_POLL = gql` + mutation CopyWaPoll($input: WaPollInput, $copyWaPollId: ID!) { + copyWaPoll(input: $input, id: $copyWaPollId) { + waPoll { + id + label + } + } + } +`; + +export const DELETE_POLL = gql` + mutation DeleteWaPoll($deleteWaPollId: ID!) { + deleteWaPoll(id: $deleteWaPollId) { + errors { + message + } + waPoll { + id + label + } + } + } +`; diff --git a/src/graphql/queries/WaPolls.ts b/src/graphql/queries/WaPolls.ts new file mode 100644 index 0000000000..e26d43011a --- /dev/null +++ b/src/graphql/queries/WaPolls.ts @@ -0,0 +1,34 @@ +import { gql } from '@apollo/client'; + +export const GET_POLLS = gql` + query WaPolls($filter: WaPollFilter, $opts: Opts) { + poll: waPolls(filter: $filter, opts: $opts) { + allowMultipleAnswer + id + label + pollContent + } + } +`; + +export const GET_POLL = gql` + query WaPoll($waPollId: ID!) { + waPoll(id: $waPollId) { + waPoll { + id + label + pollContent + allowMultipleAnswer + } + errors { + message + } + } + } +`; + +export const GET_POLLS_COUNT = gql` + query RootQueryType($filter: WaPollFilter) { + countWaPolls(filter: $filter) + } +`; From 5b41396a9d982d71481f8978724f0c697a987516 Mon Sep 17 00:00:00 2001 From: Akansha Sakhre Date: Tue, 14 Jan 2025 16:41:12 +0530 Subject: [PATCH 03/38] added poll message --- src/assets/images/icons/Poll.svg | 3 + .../MessageType/MessageType.tsx | 3 + .../ChatMessages/ChatMessage/ChatMessage.tsx | 35 ++++++----- .../PollMessage/PollMessage.module.css | 63 +++++++++++++++++++ .../ChatMessage/PollMessage/PollMessage.tsx | 46 ++++++++++++++ src/graphql/queries/WaGroups.ts | 1 + 6 files changed, 136 insertions(+), 15 deletions(-) create mode 100644 src/assets/images/icons/Poll.svg create mode 100644 src/containers/Chat/ChatMessages/ChatMessage/PollMessage/PollMessage.module.css create mode 100644 src/containers/Chat/ChatMessages/ChatMessage/PollMessage/PollMessage.tsx diff --git a/src/assets/images/icons/Poll.svg b/src/assets/images/icons/Poll.svg new file mode 100644 index 0000000000..7fc91dbbc7 --- /dev/null +++ b/src/assets/images/icons/Poll.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/containers/Chat/ChatConversations/MessageType/MessageType.tsx b/src/containers/Chat/ChatConversations/MessageType/MessageType.tsx index 517216ecd4..a2469f8baf 100644 --- a/src/containers/Chat/ChatConversations/MessageType/MessageType.tsx +++ b/src/containers/Chat/ChatConversations/MessageType/MessageType.tsx @@ -10,6 +10,7 @@ import AudioIconDark from 'assets/images/icons/Audio/Dark.svg?react'; import DocumentIconDark from 'assets/images/icons/Document/Dark.svg?react'; import StickerIconDark from 'assets/images/icons/Sticker/Dark.svg?react'; import LocationIconDark from 'assets/images/icons/Location/Dark.svg?react'; +import PollIcon from 'assets/images/icons/Poll.svg?react'; import styles from './MessageType.module.css'; @@ -26,6 +27,7 @@ const lightIcons: any = { DOCUMENT: , STICKER: , LOCATION: , + POLL: , }; const darkIcons: any = { @@ -51,6 +53,7 @@ export const MessageType = ({ type, body = '', color = 'light' }: MessageTypePro QUICK_REPLY: 'Quick Reply', LIST: 'List', LOCATION_REQUEST_MESSAGE: 'Location Request', + POLL: body, }; const option = ( diff --git a/src/containers/Chat/ChatMessages/ChatMessage/ChatMessage.tsx b/src/containers/Chat/ChatMessages/ChatMessage/ChatMessage.tsx index d563222d66..2ce180492e 100644 --- a/src/containers/Chat/ChatMessages/ChatMessage/ChatMessage.tsx +++ b/src/containers/Chat/ChatMessages/ChatMessage/ChatMessage.tsx @@ -25,6 +25,7 @@ import { QuickReplyTemplate } from '../QuickReplyTemplate/QuickReplyTemplate'; import styles from './ChatMessage.module.css'; import { setNotification } from 'common/notification'; import { LocationRequestTemplate } from './LocationRequestTemplate/LocationRequestTemplate'; +import { PollMessage } from './PollMessage/PollMessage'; export interface ChatMessageProps { id: number; @@ -56,6 +57,7 @@ export interface ChatMessageProps { groups?: boolean; status?: string; contact?: any; + pollContent?: any; } export const ChatMessage = ({ @@ -81,6 +83,7 @@ export const ChatMessage = ({ groups, status, contact, + pollContent, }: ChatMessageProps) => { const [showSaveMessageDialog, setShowSaveMessageDialog] = useState(false); const Ref = useRef(null); @@ -259,6 +262,8 @@ export const ChatMessage = ({ const content: any = interactiveContent ? JSON.parse(interactiveContent) : null; const isInteractiveContentPresent: Boolean = content ? !!Object.entries(content).length : false; + const isPollMessage = type === 'POLL'; + const pollContentJson = pollContent ? JSON.parse(pollContent) : {}; const errorClasses = messageErrorStatus ? styles.ErrorContent : ''; const stickerClasses = type === 'STICKER' ? styles.StickerBackground : ''; @@ -303,6 +308,20 @@ export const ChatMessage = ({ contactName =

{contact?.name}
; } + let messageBody: any; + if (isInteractiveContentPresent && !isSender) { + messageBody = template; + } else if (isPollMessage) { + messageBody = ; + } else { + messageBody = ( + <> + {contactName} + + {dateAndSendBy} + + ); + } return (
{daySeparatorContent} @@ -342,21 +361,7 @@ export const ChatMessage = ({
- {isInteractiveContentPresent && !isSender ? ( - template - ) : ( - <> - {contactName} - - {dateAndSendBy} - - )} + {messageBody}
diff --git a/src/containers/Chat/ChatMessages/ChatMessage/PollMessage/PollMessage.module.css b/src/containers/Chat/ChatMessages/ChatMessage/PollMessage/PollMessage.module.css new file mode 100644 index 0000000000..32eba13828 --- /dev/null +++ b/src/containers/Chat/ChatMessages/ChatMessage/PollMessage/PollMessage.module.css @@ -0,0 +1,63 @@ +.PollsContainer { + min-width: 250px; + color: #4a4a4a !important; +} + +.Sender { + color: #fff !important; +} + +.Text { + font-size: 14px; + font-weight: 500; + line-height: 19.6px; +} + +.SelectText { + font-size: 10px; + font-weight: 400; + line-height: 15px; + color: #6a6d6b; + margin-bottom: 1rem !important; +} + +.Options { + display: flex; + flex-direction: column; + gap: 1rem; + padding-bottom: 1rem; +} + +.Option { + font-size: 14px; + font-weight: 500; + line-height: 20px; + letter-spacing: -0.25px; + display: flex; + gap: 0.5rem; + flex-direction: column; +} + +.Option span { + display: flex; + align-items: center; + justify-content: space-between; +} + +.OptionName { + display: flex; + gap: 0.2rem; +} + +.Vote { + font-size: 14px; + font-weight: 500; + line-height: 20px; + letter-spacing: -0.25px; + text-align: left; +} + +.LinearProgress { + height: 10px; + border-radius: 5px; +} diff --git a/src/containers/Chat/ChatMessages/ChatMessage/PollMessage/PollMessage.tsx b/src/containers/Chat/ChatMessages/ChatMessage/PollMessage/PollMessage.tsx new file mode 100644 index 0000000000..85357f20f6 --- /dev/null +++ b/src/containers/Chat/ChatMessages/ChatMessage/PollMessage/PollMessage.tsx @@ -0,0 +1,46 @@ +import { LinearProgress } from '@mui/material'; +import styles from './PollMessage.module.css'; +import RadioButtonUncheckedIcon from '@mui/icons-material/RadioButtonUnchecked'; + +interface PollMessageProps { + pollContentJson: any; + isSender: boolean; +} + +const getTotalVotes = (options: any) => { + return options.reduce((acc: number, option: any) => acc + option.votes, 0); +}; + +export const PollMessage = ({ pollContentJson, isSender }: PollMessageProps) => { + const { text, options } = pollContentJson; + const totalVotes = getTotalVotes(options); + + return ( +
+
{text}
+

Select one or more

+
+ {options.map((option: any, index: number) => { + return ( +
+ + + + {option.name} + + {option.votes} + + +
+ ); + })} +
+
+ ); +}; diff --git a/src/graphql/queries/WaGroups.ts b/src/graphql/queries/WaGroups.ts index 11727ffcab..5ca75b6111 100644 --- a/src/graphql/queries/WaGroups.ts +++ b/src/graphql/queries/WaGroups.ts @@ -49,6 +49,7 @@ export const GROUP_SEARCH_QUERY = gql` type insertedAt } + pollContent } } } From 4e78ba761ef92d691be0f1eaff421afe39b3f0d2 Mon Sep 17 00:00:00 2001 From: Akansha Sakhre Date: Tue, 14 Jan 2025 21:51:09 +0530 Subject: [PATCH 04/38] fixed copies --- src/containers/Form/FormLayout.tsx | 4 ++-- src/containers/WaGroups/WaPolls/WaPolls.tsx | 1 - src/graphql/mutations/WaPolls.ts | 4 ++-- src/graphql/queries/WaPolls.ts | 4 ++-- 4 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/containers/Form/FormLayout.tsx b/src/containers/Form/FormLayout.tsx index 9762b490dc..96b828c0a4 100644 --- a/src/containers/Form/FormLayout.tsx +++ b/src/containers/Form/FormLayout.tsx @@ -216,10 +216,10 @@ export const FormLayout = ({ // Clearning unnecessary fields delete payloadBody.billingId; } - // TODO: Change this back + updateItem({ variables: { - copyWaPollId: idVal, + [idType]: idVal, input: payloadBody, }, }); diff --git a/src/containers/WaGroups/WaPolls/WaPolls.tsx b/src/containers/WaGroups/WaPolls/WaPolls.tsx index 5809ab5946..17262a7c06 100644 --- a/src/containers/WaGroups/WaPolls/WaPolls.tsx +++ b/src/containers/WaGroups/WaPolls/WaPolls.tsx @@ -150,7 +150,6 @@ export const WaPolls = () => { icon={pollsIcon} backLinkButton={`/group/polls`} entityId={params.id} - idType={idType} {...queries} /> ); diff --git a/src/graphql/mutations/WaPolls.ts b/src/graphql/mutations/WaPolls.ts index af0b390d4e..2d7dd7c66b 100644 --- a/src/graphql/mutations/WaPolls.ts +++ b/src/graphql/mutations/WaPolls.ts @@ -14,8 +14,8 @@ export const CREATE_POLL = gql` `; export const COPY_POLL = gql` - mutation CopyWaPoll($input: WaPollInput, $copyWaPollId: ID!) { - copyWaPoll(input: $input, id: $copyWaPollId) { + mutation CopyWaPoll($input: WaPollInput, $id: ID!) { + copyWaPoll(input: $input, id: $id) { waPoll { id label diff --git a/src/graphql/queries/WaPolls.ts b/src/graphql/queries/WaPolls.ts index e26d43011a..b6b2f00d34 100644 --- a/src/graphql/queries/WaPolls.ts +++ b/src/graphql/queries/WaPolls.ts @@ -12,8 +12,8 @@ export const GET_POLLS = gql` `; export const GET_POLL = gql` - query WaPoll($waPollId: ID!) { - waPoll(id: $waPollId) { + query WaPoll($id: ID!) { + waPoll(id: $id) { waPoll { id label From e9b2fb6a723f80c7b911c06510d2d3487a3dd4ea Mon Sep 17 00:00:00 2001 From: Akansha Sakhre Date: Wed, 15 Jan 2025 11:04:25 +0530 Subject: [PATCH 05/38] added simulator support --- src/components/simulator/Simulator.tsx | 56 +++++++++++----- .../PollMessage/PollMessage.module.css | 34 ++++++++-- .../ChatMessage/PollMessage/PollMessage.tsx | 45 +++++++------ .../WaPolls/WaPollOptions/WaPollOptions.tsx | 14 +++- src/containers/WaGroups/WaPolls/WaPolls.tsx | 67 +++++++++++++------ 5 files changed, 152 insertions(+), 64 deletions(-) diff --git a/src/components/simulator/Simulator.tsx b/src/components/simulator/Simulator.tsx index 3dedc41e13..0a664decbe 100644 --- a/src/components/simulator/Simulator.tsx +++ b/src/components/simulator/Simulator.tsx @@ -52,6 +52,7 @@ import styles from './Simulator.module.css'; import { LocationRequestTemplate } from 'containers/Chat/ChatMessages/ChatMessage/LocationRequestTemplate/LocationRequestTemplate'; import { BackdropLoader } from 'containers/Flow/FlowTranslation'; import { SIMULATOR_RELEASE_SUBSCRIPTION } from 'graphql/subscriptions/PeriodicInfo'; +import { PollMessage } from 'containers/Chat/ChatMessages/ChatMessage/PollMessage/PollMessage'; export interface SimulatorProps { setShowSimulator?: any; @@ -63,6 +64,7 @@ export interface SimulatorProps { interactiveMessage?: any; showHeader?: boolean; hasResetButton?: boolean; + pollContent?: any; } interface Sender { @@ -124,6 +126,7 @@ const Simulator = ({ interactiveMessage, showHeader = true, hasResetButton = false, + pollContent, }: SimulatorProps) => { const [inputMessage, setInputMessage] = useState(''); const [simulatedMessages, setSimulatedMessage] = useState(); @@ -268,7 +271,13 @@ const Simulator = ({ }); }; - const renderMessage = (messageObject: any, direction: string, index: number, isInteractive: boolean = false) => { + const renderMessage = ( + messageObject: any, + direction: string, + index: number, + isInteractive: boolean, + isPollContent: boolean = false + ) => { const { insertedAt, type, media, location, interactiveContent, bspMessageId, templateType } = messageObject; const messageType = isInteractive ? templateType : type; @@ -320,26 +329,31 @@ const Simulator = ({ } } + let messageBody: any = ( + <> + + + + ); + if (isInteractiveContentPresent && direction !== 'send') { + messageBody = template; + } else if (isPollContent) { + messageBody = ; + } + return (
- {isInteractiveContentPresent && direction !== 'send' ? ( - template - ) : ( - <> - - - - )} + {messageBody}
{ if (simulatorMessage.receiver.id === simulatorId) { - return renderMessage(simulatorMessage, 'received', index); + return renderMessage(simulatorMessage, 'received', index, false); } - return renderMessage(simulatorMessage, 'send', index); + return renderMessage(simulatorMessage, 'send', index, false); }) .reverse(); setSimulatedMessage(chatMessage); @@ -366,7 +380,7 @@ const Simulator = ({ const getPreviewMessage = () => { if (message && message.type) { - const previewMessage = renderMessage(message, 'received', 0); + const previewMessage = renderMessage(message, 'received', 0, false); if (['STICKER', 'AUDIO'].includes(message.type)) { setSimulatedMessage(previewMessage); } else if (message.body || message.media?.caption) { @@ -380,6 +394,7 @@ const Simulator = ({ if (interactiveMessage) { const { templateType, interactiveContent } = interactiveMessage; const previewMessage = renderMessage(interactiveMessage, 'received', 0, true); + setSimulatedMessage(previewMessage); if (templateType === LIST) { const { items } = JSON.parse(interactiveContent); @@ -388,6 +403,11 @@ const Simulator = ({ setIsDrawerOpen(false); } } + + if (pollContent) { + const previewMessage = renderMessage(pollContent, 'received', 0, false, true); + setSimulatedMessage(previewMessage); + } }; useEffect(() => { diff --git a/src/containers/Chat/ChatMessages/ChatMessage/PollMessage/PollMessage.module.css b/src/containers/Chat/ChatMessages/ChatMessage/PollMessage/PollMessage.module.css index 32eba13828..584c04fd57 100644 --- a/src/containers/Chat/ChatMessages/ChatMessage/PollMessage/PollMessage.module.css +++ b/src/containers/Chat/ChatMessages/ChatMessage/PollMessage/PollMessage.module.css @@ -1,6 +1,12 @@ -.PollsContainer { +.ChatMessage { min-width: 250px; color: #4a4a4a !important; + font-size: 14px; +} + +.SimpulatorMessage { + min-width: 180px; + font-size: 12px; } .Sender { @@ -8,19 +14,26 @@ } .Text { - font-size: 14px; font-weight: 500; line-height: 19.6px; } .SelectText { - font-size: 10px; font-weight: 400; line-height: 15px; color: #6a6d6b; +} + +.ChatMessage p { + font-size: 10px !important; margin-bottom: 1rem !important; } +.SimpulatorMessage p { + font-size: 8px; + margin: 0.3rem 0 +} + .Options { display: flex; flex-direction: column; @@ -29,7 +42,6 @@ } .Option { - font-size: 14px; font-weight: 500; line-height: 20px; letter-spacing: -0.25px; @@ -61,3 +73,17 @@ height: 10px; border-radius: 5px; } + +.LinearProgressSimulator { + height: 6px; + border-radius: 5px; +} + +.PlaceHolder { + width: 100%; + border-radius: 4px; + background-color: #dfece2c3; + color: #0c1f144b; + padding: 0.3rem; + font-size: 12px; +} \ No newline at end of file diff --git a/src/containers/Chat/ChatMessages/ChatMessage/PollMessage/PollMessage.tsx b/src/containers/Chat/ChatMessages/ChatMessage/PollMessage/PollMessage.tsx index 85357f20f6..2016adc1a2 100644 --- a/src/containers/Chat/ChatMessages/ChatMessage/PollMessage/PollMessage.tsx +++ b/src/containers/Chat/ChatMessages/ChatMessage/PollMessage/PollMessage.tsx @@ -4,40 +4,47 @@ import RadioButtonUncheckedIcon from '@mui/icons-material/RadioButtonUnchecked'; interface PollMessageProps { pollContentJson: any; - isSender: boolean; + isSender?: boolean; + isSimulator?: boolean; } const getTotalVotes = (options: any) => { return options.reduce((acc: number, option: any) => acc + option.votes, 0); }; -export const PollMessage = ({ pollContentJson, isSender }: PollMessageProps) => { +export const PollMessage = ({ pollContentJson, isSender = false, isSimulator = false }: PollMessageProps) => { const { text, options } = pollContentJson; const totalVotes = getTotalVotes(options); return ( -
+
{text}

Select one or more

{options.map((option: any, index: number) => { return ( -
- - - - {option.name} - - {option.votes} - - -
+ <> + {option.name ? ( +
+ + + + {option.name} + + {option.votes} + + +
+ ) : ( + isSimulator &&
Option {option.id + 1}
+ )} + ); })}
diff --git a/src/containers/WaGroups/WaPolls/WaPollOptions/WaPollOptions.tsx b/src/containers/WaGroups/WaPolls/WaPollOptions/WaPollOptions.tsx index cfe909cfdd..7cc4d5b4fa 100644 --- a/src/containers/WaGroups/WaPolls/WaPollOptions/WaPollOptions.tsx +++ b/src/containers/WaGroups/WaPolls/WaPollOptions/WaPollOptions.tsx @@ -10,6 +10,7 @@ interface WaPollOptionsProps { form: { field: any; errors: any; touched: any; values: any; setFieldValue: any }; options: string[]; isEditing: boolean; + setPreviewData: any; } const emojiStyles = { @@ -19,14 +20,21 @@ const emojiStyles = { zIndex: 100, }; -export const WaPollOptions = ({ form: { values, setFieldValue, errors, touched }, isEditing }: WaPollOptionsProps) => { +export const WaPollOptions = ({ + form: { values, setFieldValue, errors, touched }, + isEditing, + setPreviewData, +}: WaPollOptionsProps) => { const handleAddOption = () => { - setFieldValue('options', [...values.options, { name: '', id: values.options.length }]); + const newOptions = [...values.options, { name: '', id: values.options.length }]; + setFieldValue('options', newOptions); + setPreviewData((prev: any) => ({ ...prev, options: newOptions })); }; const handleInput = (value: any, id: any) => { const newOptions = values.options.map((option: any) => (option.id === id ? { ...option, name: value } : option)); setFieldValue('options', newOptions); + setPreviewData((prev: any) => ({ ...prev, options: newOptions })); }; const handleEmojiAdd = (emoji: any, id: number) => { @@ -35,11 +43,13 @@ export const WaPollOptions = ({ form: { values, setFieldValue, errors, touched } ); setFieldValue('options', newOptions); + setPreviewData((prev: any) => ({ ...prev, options: newOptions })); }; const handleRemoveClick = (id: any) => { const newOptions = values.options.filter((option: any) => option.id !== id); setFieldValue('options', newOptions); + setPreviewData((prev: any) => ({ ...prev, options: newOptions })); }; return ( diff --git a/src/containers/WaGroups/WaPolls/WaPolls.tsx b/src/containers/WaGroups/WaPolls/WaPolls.tsx index 5809ab5946..bea68b2aad 100644 --- a/src/containers/WaGroups/WaPolls/WaPolls.tsx +++ b/src/containers/WaGroups/WaPolls/WaPolls.tsx @@ -11,6 +11,7 @@ import { WaPollOptions } from './WaPollOptions/WaPollOptions'; import { COPY_POLL, CREATE_POLL, DELETE_POLL } from 'graphql/mutations/WaPolls'; import { GET_POLL } from 'graphql/queries/WaPolls'; import { useLocation, useParams } from 'react-router'; +import Simulator from 'components/simulator/Simulator'; const queries = { getItemQuery: GET_POLL, @@ -29,17 +30,23 @@ export const WaPolls = () => { { id: 1, name: '' }, ]); const [allowMultiple, setAllowMultiple] = useState(false); + const [previewData, setPreviewData] = useState({ + text: '', + options: [ + { id: 0, name: '' }, + { id: 1, name: '' }, + ], + }); const { t } = useTranslation(); const params = useParams(); const location = useLocation(); - + const mode = location.state; let isEditing = false; let isCopyState = false; if (params.id) { isEditing = true; } - if (location.state === 'copy') { - console.log('copy state'); + if (mode === 'copy') { isCopyState = true; isEditing = false; } @@ -83,6 +90,11 @@ export const WaPolls = () => { setAllowMultiple(allowMultipleAnswer); setContent(text); setOptions(options); + + setPreviewData({ + text, + options, + }); }; const FormSchema = Yup.object().shape({ @@ -115,11 +127,18 @@ export const WaPolls = () => { textArea: true, rows: 6, disabled: isEditing, + onChange: (value: any) => { + setPreviewData({ + ...previewData, + text: value, + }); + }, }, { component: WaPollOptions, name: 'options', isEditing, + setPreviewData, }, { component: Checkbox, @@ -135,24 +154,30 @@ export const WaPolls = () => { ]; return ( - + <> + +
+ +
+ ); }; From 453a490c2570771b9cf086df0e60f3883628521e Mon Sep 17 00:00:00 2001 From: Akansha Sakhre Date: Wed, 15 Jan 2025 11:06:36 +0530 Subject: [PATCH 06/38] fixed validation --- src/containers/WaGroups/WaPolls/WaPollOptions/WaPollOptions.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/containers/WaGroups/WaPolls/WaPollOptions/WaPollOptions.tsx b/src/containers/WaGroups/WaPolls/WaPollOptions/WaPollOptions.tsx index cfe909cfdd..25727e8c08 100644 --- a/src/containers/WaGroups/WaPolls/WaPollOptions/WaPollOptions.tsx +++ b/src/containers/WaGroups/WaPolls/WaPollOptions/WaPollOptions.tsx @@ -141,7 +141,7 @@ const PollOption = ({ handleEmojiAdd(emoji, option.id)} displayStyle={emojiStyles} /> )}
- {hasError ? {errors[option.id]} : null} + {hasError ? {errors[option.id]?.name} : null} ); }; From b24ae5f309c09b5231c5a4889387414f4b5f5e1c Mon Sep 17 00:00:00 2001 From: Akansha Sakhre Date: Wed, 15 Jan 2025 11:50:57 +0530 Subject: [PATCH 07/38] fixed voting logic and colors --- src/components/simulator/Simulator.module.css | 1 + .../ChatMessage/PollMessage/PollMessage.module.css | 12 +++++++++--- .../ChatMessage/PollMessage/PollMessage.tsx | 10 ++++++---- src/graphql/subscriptions/Groups.ts | 3 ++- 4 files changed, 18 insertions(+), 8 deletions(-) diff --git a/src/components/simulator/Simulator.module.css b/src/components/simulator/Simulator.module.css index 39908c1e32..6e6193ae51 100644 --- a/src/components/simulator/Simulator.module.css +++ b/src/components/simulator/Simulator.module.css @@ -29,6 +29,7 @@ background: white; width: 200px; margin-top: 4px; + overflow-x: hidden; } .StickerReceivedMessage { diff --git a/src/containers/Chat/ChatMessages/ChatMessage/PollMessage/PollMessage.module.css b/src/containers/Chat/ChatMessages/ChatMessage/PollMessage/PollMessage.module.css index 584c04fd57..a1825febde 100644 --- a/src/containers/Chat/ChatMessages/ChatMessage/PollMessage/PollMessage.module.css +++ b/src/containers/Chat/ChatMessages/ChatMessage/PollMessage/PollMessage.module.css @@ -18,12 +18,18 @@ line-height: 19.6px; } -.SelectText { +.SelectTextDark { font-weight: 400; line-height: 15px; color: #6a6d6b; } +.SelectTextLight { + font-weight: 400; + line-height: 15px; + color: #b3b6b4; +} + .ChatMessage p { font-size: 10px !important; margin-bottom: 1rem !important; @@ -69,8 +75,8 @@ text-align: left; } -.LinearProgress { - height: 10px; +.LinearProgressChat { + height: 8px; border-radius: 5px; } diff --git a/src/containers/Chat/ChatMessages/ChatMessage/PollMessage/PollMessage.tsx b/src/containers/Chat/ChatMessages/ChatMessage/PollMessage/PollMessage.tsx index 2016adc1a2..e86078b415 100644 --- a/src/containers/Chat/ChatMessages/ChatMessage/PollMessage/PollMessage.tsx +++ b/src/containers/Chat/ChatMessages/ChatMessage/PollMessage/PollMessage.tsx @@ -14,14 +14,15 @@ const getTotalVotes = (options: any) => { export const PollMessage = ({ pollContentJson, isSender = false, isSimulator = false }: PollMessageProps) => { const { text, options } = pollContentJson; - const totalVotes = getTotalVotes(options); + const maxVotes = Math.max(...pollContentJson.options.map((option: any) => option.votes)); return (
{text}
-

Select one or more

+

Select one or more

{options.map((option: any, index: number) => { + const percentage = maxVotes > 0 ? (option.votes / maxVotes) * 100 : 0; return ( <> {option.name ? ( @@ -35,10 +36,11 @@ export const PollMessage = ({ pollContentJson, isSender = false, isSimulator = f
) : ( diff --git a/src/graphql/subscriptions/Groups.ts b/src/graphql/subscriptions/Groups.ts index 9ced03d8dd..9e52f6fa79 100644 --- a/src/graphql/subscriptions/Groups.ts +++ b/src/graphql/subscriptions/Groups.ts @@ -34,7 +34,7 @@ export const WA_MESSAGE_RECEIVED_SUBSCRIPTION = gql` type insertedAt } - + pollContent errors } } @@ -124,6 +124,7 @@ export const UPDATE_WA_MESSAGE_STATUS = gql` updateWaMessageStatus(organizationId: $organizationId) { id messageNumber + pollContent errors waGroup { id From b9d1da71be3faa94c6debadc88dd3cf9bc899f3b Mon Sep 17 00:00:00 2001 From: Akansha Sakhre Date: Wed, 15 Jan 2025 11:56:54 +0530 Subject: [PATCH 08/38] merge changes --- src/containers/WaGroups/WaPolls/WaPolls.tsx | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/containers/WaGroups/WaPolls/WaPolls.tsx b/src/containers/WaGroups/WaPolls/WaPolls.tsx index bea68b2aad..6beda6d332 100644 --- a/src/containers/WaGroups/WaPolls/WaPolls.tsx +++ b/src/containers/WaGroups/WaPolls/WaPolls.tsx @@ -20,7 +20,6 @@ const queries = { updateItemQuery: COPY_POLL, }; const pollsIcon = ; -let idType = 'waPollId'; export const WaPolls = () => { const [label, setLabel] = useState(''); @@ -73,9 +72,6 @@ export const WaPolls = () => { delete payloadCopy.content; delete payloadCopy.allowMultiple; - if (isCopyState) { - idType = 'copyWaPollId'; - } return payloadCopy; }; const setStates = (states: any) => { @@ -170,7 +166,6 @@ export const WaPolls = () => { icon={pollsIcon} backLinkButton={`/group/polls`} entityId={params.id} - idType={idType} type={mode} {...queries} /> From 3270d0d94b9606a8d308d778f6c881d67b544332 Mon Sep 17 00:00:00 2001 From: Akansha Sakhre Date: Wed, 15 Jan 2025 12:01:49 +0530 Subject: [PATCH 09/38] added ids --- .../WaGroups/WaPolls/WaPollOptions/WaPollOptions.tsx | 11 +++++++---- src/containers/WaGroups/WaPolls/WaPolls.tsx | 4 ---- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/src/containers/WaGroups/WaPolls/WaPollOptions/WaPollOptions.tsx b/src/containers/WaGroups/WaPolls/WaPollOptions/WaPollOptions.tsx index 25727e8c08..529b7dbcec 100644 --- a/src/containers/WaGroups/WaPolls/WaPollOptions/WaPollOptions.tsx +++ b/src/containers/WaGroups/WaPolls/WaPollOptions/WaPollOptions.tsx @@ -21,7 +21,7 @@ const emojiStyles = { export const WaPollOptions = ({ form: { values, setFieldValue, errors, touched }, isEditing }: WaPollOptionsProps) => { const handleAddOption = () => { - setFieldValue('options', [...values.options, { name: '', id: values.options.length }]); + setFieldValue('options', [...values.options, { name: '', id: Math.random() }]); }; const handleInput = (value: any, id: any) => { @@ -51,6 +51,7 @@ export const WaPollOptions = ({ form: { values, setFieldValue, errors, touched } {values.options.map((option: any, ind: number) => ( { const [showEmojiPicker, setShowEmojiPicker] = useState(false); - const hasError = errors && typeof errors !== 'string' && touched && errors[option.id] && touched[option.id]; + const hasError = errors && typeof errors !== 'string' && touched && errors[ind] && touched[ind]; return ( @@ -105,7 +108,7 @@ const PollOption = ({ handleInput(event.target.value, option?.id)} disabled={isEditing} @@ -141,7 +144,7 @@ const PollOption = ({ handleEmojiAdd(emoji, option.id)} displayStyle={emojiStyles} /> )}
- {hasError ? {errors[option.id]?.name} : null} + {hasError ? {errors[ind]?.name || ''} : null} ); }; diff --git a/src/containers/WaGroups/WaPolls/WaPolls.tsx b/src/containers/WaGroups/WaPolls/WaPolls.tsx index 17262a7c06..e60fa9e6e3 100644 --- a/src/containers/WaGroups/WaPolls/WaPolls.tsx +++ b/src/containers/WaGroups/WaPolls/WaPolls.tsx @@ -19,7 +19,6 @@ const queries = { updateItemQuery: COPY_POLL, }; const pollsIcon = ; -let idType = 'waPollId'; export const WaPolls = () => { const [label, setLabel] = useState(''); @@ -66,9 +65,6 @@ export const WaPolls = () => { delete payloadCopy.content; delete payloadCopy.allowMultiple; - if (isCopyState) { - idType = 'copyWaPollId'; - } return payloadCopy; }; const setStates = (states: any) => { From bc13398cdb6fdf5096a387fa9a84224eda2adad4 Mon Sep 17 00:00:00 2001 From: Akansha Sakhre Date: Wed, 15 Jan 2025 12:21:45 +0530 Subject: [PATCH 10/38] added view action --- .../PollMessage/PollMessage.module.css | 26 ++++++++++++--- .../ChatMessage/PollMessage/PollMessage.tsx | 19 ++++++----- .../ViewPollDialog/ViewPollDialog.tsx | 32 +++++++++++++++++++ .../WaPolls/WaPollsList/WaPollsList.tsx | 13 +++++++- 4 files changed, 76 insertions(+), 14 deletions(-) create mode 100644 src/containers/WaGroups/WaPolls/WaPollsList/ViewPollDialog/ViewPollDialog.tsx diff --git a/src/containers/Chat/ChatMessages/ChatMessage/PollMessage/PollMessage.module.css b/src/containers/Chat/ChatMessages/ChatMessage/PollMessage/PollMessage.module.css index a1825febde..f30ba21ebc 100644 --- a/src/containers/Chat/ChatMessages/ChatMessage/PollMessage/PollMessage.module.css +++ b/src/containers/Chat/ChatMessages/ChatMessage/PollMessage/PollMessage.module.css @@ -18,26 +18,36 @@ line-height: 19.6px; } -.SelectTextDark { +.TextLarge { + font-size: 1rem; + margin-bottom: 1rem; +} + +.SelectText { font-weight: 400; line-height: 15px; + margin: 0 !important; +} + +.SelectTextDark { + composes: SelectText; color: #6a6d6b; } .SelectTextLight { - font-weight: 400; - line-height: 15px; + composes: SelectText; color: #b3b6b4; } .ChatMessage p { font-size: 10px !important; - margin-bottom: 1rem !important; + margin-top: 0.5rem !important; + margin-bottom: 0.8rem !important; } .SimpulatorMessage p { font-size: 8px; - margin: 0.3rem 0 + margin: 0.3rem 0 !important; } .Options { @@ -67,6 +77,12 @@ gap: 0.2rem; } +.OptionNameLarge { + composes: OptionName; + gap: 0.5rem; + font-size: 1rem; +} + .Vote { font-size: 14px; font-weight: 500; diff --git a/src/containers/Chat/ChatMessages/ChatMessage/PollMessage/PollMessage.tsx b/src/containers/Chat/ChatMessages/ChatMessage/PollMessage/PollMessage.tsx index e86078b415..68bd8859cf 100644 --- a/src/containers/Chat/ChatMessages/ChatMessage/PollMessage/PollMessage.tsx +++ b/src/containers/Chat/ChatMessages/ChatMessage/PollMessage/PollMessage.tsx @@ -6,20 +6,22 @@ interface PollMessageProps { pollContentJson: any; isSender?: boolean; isSimulator?: boolean; + view?: boolean; } -const getTotalVotes = (options: any) => { - return options.reduce((acc: number, option: any) => acc + option.votes, 0); -}; - -export const PollMessage = ({ pollContentJson, isSender = false, isSimulator = false }: PollMessageProps) => { +export const PollMessage = ({ + pollContentJson, + isSender = false, + isSimulator = false, + view = false, +}: PollMessageProps) => { const { text, options } = pollContentJson; const maxVotes = Math.max(...pollContentJson.options.map((option: any) => option.votes)); return (
-
{text}
-

Select one or more

+
{text}
+ {!view &&

Select one or more

}
{options.map((option: any, index: number) => { const percentage = maxVotes > 0 ? (option.votes / maxVotes) * 100 : 0; @@ -28,12 +30,13 @@ export const PollMessage = ({ pollContentJson, isSender = false, isSimulator = f {option.name ? (
- + {option.name} {option.votes} + { + const { data, loading } = useQuery(GET_POLL, { + variables: { + id: id, + }, + }); + + const poll = data?.waPoll?.waPoll; + const pollContent = poll?.pollContent ? JSON.parse(poll?.pollContent) : {}; + console.log(poll); + + if (loading) { + return ; + } + + return ( + + + + ); +}; diff --git a/src/containers/WaGroups/WaPolls/WaPollsList/WaPollsList.tsx b/src/containers/WaGroups/WaPolls/WaPollsList/WaPollsList.tsx index 33a0c821d7..9c9ae71f1c 100644 --- a/src/containers/WaGroups/WaPolls/WaPollsList/WaPollsList.tsx +++ b/src/containers/WaGroups/WaPolls/WaPollsList/WaPollsList.tsx @@ -2,6 +2,7 @@ import { useTranslation } from 'react-i18next'; import CollectionIcon from 'assets/images/icons/Collection/Dark.svg?react'; import DeleteIcon from 'assets/images/icons/Delete/Red.svg?react'; import DuplicateIcon from 'assets/images/icons/Duplicate.svg?react'; +import ViewIcon from 'assets/images/icons/ViewLight.svg?react'; import styles from './WaPollsList.module.css'; import { List } from 'containers/List/List'; import { useState } from 'react'; @@ -12,6 +13,7 @@ import { GET_POLLS, GET_POLLS_COUNT } from 'graphql/queries/WaPolls'; import { DELETE_POLL } from 'graphql/mutations/WaPolls'; import { useMutation } from '@apollo/client'; import { setErrorMessage, setNotification } from 'common/notification'; +import { ViewPoll } from './ViewPollDialog/ViewPollDialog'; const queries = { countQuery: GET_POLLS_COUNT, @@ -34,6 +36,7 @@ const getContent = (content: string, id: number) => { }; export const WaPollsList = () => { const [deleteWaPollId, setDeleteWaPollId] = useState(null); + const [viewWaPollId, setViewWaPollId] = useState(null); const { t } = useTranslation(); const navigate = useNavigate(); @@ -79,6 +82,13 @@ export const WaPollsList = () => { }; const additionalAction = () => [ + { + label: t('View'), + icon: , + parameter: 'id', + dialog: (id: any) => setViewWaPollId(id), + insideMore: false, + }, { label: t('Copy'), icon: , @@ -89,7 +99,7 @@ export const WaPollsList = () => { { label: t('Delete'), icon: , - parameter: 'label', + parameter: 'id', dialog: (id: any) => setDeleteWaPollId(id), insideMore: false, }, @@ -134,6 +144,7 @@ export const WaPollsList = () => { {...columnAttributes} /> {deleteWaPollId && deletedialog} + {viewWaPollId && setViewWaPollId(null)} />} ); }; From 5bf2a6a00b057f4659e777c17df94dc1a8cdb4b6 Mon Sep 17 00:00:00 2001 From: Akansha Sakhre Date: Wed, 15 Jan 2025 12:24:50 +0530 Subject: [PATCH 11/38] deepscan fixes --- .../ChatMessages/ChatMessage/PollMessage/PollMessage.tsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/containers/Chat/ChatMessages/ChatMessage/PollMessage/PollMessage.tsx b/src/containers/Chat/ChatMessages/ChatMessage/PollMessage/PollMessage.tsx index 68bd8859cf..a223b5442f 100644 --- a/src/containers/Chat/ChatMessages/ChatMessage/PollMessage/PollMessage.tsx +++ b/src/containers/Chat/ChatMessages/ChatMessage/PollMessage/PollMessage.tsx @@ -1,6 +1,7 @@ import { LinearProgress } from '@mui/material'; import styles from './PollMessage.module.css'; import RadioButtonUncheckedIcon from '@mui/icons-material/RadioButtonUnchecked'; +import { Fragment } from 'react/jsx-runtime'; interface PollMessageProps { pollContentJson: any; @@ -26,7 +27,7 @@ export const PollMessage = ({ {options.map((option: any, index: number) => { const percentage = maxVotes > 0 ? (option.votes / maxVotes) * 100 : 0; return ( - <> + {option.name ? (
@@ -49,7 +50,7 @@ export const PollMessage = ({ ) : ( isSimulator &&
Option {option.id + 1}
)} - + ); })}
From 7b901e0b25c8edc80c6d21b148ab08c06686a06f Mon Sep 17 00:00:00 2001 From: Akansha Sakhre Date: Wed, 15 Jan 2025 12:27:49 +0530 Subject: [PATCH 12/38] deepscan fixes --- src/containers/Form/FormLayout.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/containers/Form/FormLayout.tsx b/src/containers/Form/FormLayout.tsx index 96b828c0a4..ee7ce54b7a 100644 --- a/src/containers/Form/FormLayout.tsx +++ b/src/containers/Form/FormLayout.tsx @@ -219,7 +219,7 @@ export const FormLayout = ({ updateItem({ variables: { - [idType]: idVal, + [idKey]: idVal, input: payloadBody, }, }); From 95c5d8ea1f4b21d13a2b93a35bd7e5b107a3f2b9 Mon Sep 17 00:00:00 2001 From: Akansha Sakhre Date: Wed, 15 Jan 2025 12:36:22 +0530 Subject: [PATCH 13/38] fixed content --- .../WaGroups/WaPolls/WaPollsList/WaPollsList.tsx | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/src/containers/WaGroups/WaPolls/WaPollsList/WaPollsList.tsx b/src/containers/WaGroups/WaPolls/WaPollsList/WaPollsList.tsx index 33a0c821d7..6e23648a85 100644 --- a/src/containers/WaGroups/WaPolls/WaPollsList/WaPollsList.tsx +++ b/src/containers/WaGroups/WaPolls/WaPollsList/WaPollsList.tsx @@ -21,15 +21,7 @@ const queries = { const getLabel = (label: string) =>
{label}
; -const getContent = (content: string, id: number) => { - const content1 = - 'Which of our communication channels do you find most effective for staying updated on our activities?'; - const content2 = - 'How frequently do you participate in our activities or events, and what influences your level of involvement? Which day works best for our upcoming community workshops?'; - if (!content) { - content = id % 2 === 0 ? content1 : content2; - } - +const getContent = (content: string) => { return
{content.length < 100 ? content : `${content.slice(0, 100)}...`}
; }; export const WaPollsList = () => { @@ -46,10 +38,11 @@ export const WaPollsList = () => { const dialogMessage = t("You won't be able to use this collection again."); const columnStyles = [styles.Label, styles.Content, styles.Actions]; - const getColumns = ({ label, content, id }: any) => { + const getColumns = ({ label, pollContent, id }: any) => { + const content = pollContent ? JSON.parse(pollContent) : {}; return { label: getLabel(label), - content: getContent(content, id), + content: getContent(content?.text), }; }; From 6da10a1420c1933aaa1b119fe6e02ae440bc6617 Mon Sep 17 00:00:00 2001 From: Akansha Sakhre Date: Wed, 15 Jan 2025 12:38:19 +0530 Subject: [PATCH 14/38] fixed content --- .../WaGroups/WaPolls/WaPollsList/WaPollsList.tsx | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/src/containers/WaGroups/WaPolls/WaPollsList/WaPollsList.tsx b/src/containers/WaGroups/WaPolls/WaPollsList/WaPollsList.tsx index 9c9ae71f1c..a301e2cc72 100644 --- a/src/containers/WaGroups/WaPolls/WaPollsList/WaPollsList.tsx +++ b/src/containers/WaGroups/WaPolls/WaPollsList/WaPollsList.tsx @@ -23,15 +23,7 @@ const queries = { const getLabel = (label: string) =>
{label}
; -const getContent = (content: string, id: number) => { - const content1 = - 'Which of our communication channels do you find most effective for staying updated on our activities?'; - const content2 = - 'How frequently do you participate in our activities or events, and what influences your level of involvement? Which day works best for our upcoming community workshops?'; - if (!content) { - content = id % 2 === 0 ? content1 : content2; - } - +const getContent = (content: string) => { return
{content.length < 100 ? content : `${content.slice(0, 100)}...`}
; }; export const WaPollsList = () => { @@ -49,10 +41,11 @@ export const WaPollsList = () => { const dialogMessage = t("You won't be able to use this collection again."); const columnStyles = [styles.Label, styles.Content, styles.Actions]; - const getColumns = ({ label, content, id }: any) => { + const getColumns = ({ label, pollContent, id }: any) => { + const content = pollContent ? JSON.parse(pollContent) : {}; return { label: getLabel(label), - content: getContent(content, id), + content: getContent(content?.text), }; }; From 46eb607b56d0b19a84967feae29c2bc5970c9c98 Mon Sep 17 00:00:00 2001 From: Akansha Sakhre Date: Wed, 15 Jan 2025 12:39:56 +0530 Subject: [PATCH 15/38] fixed content --- .../Chat/ChatMessages/ChatMessage/PollMessage/PollMessage.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/containers/Chat/ChatMessages/ChatMessage/PollMessage/PollMessage.tsx b/src/containers/Chat/ChatMessages/ChatMessage/PollMessage/PollMessage.tsx index a223b5442f..b4b5376bc8 100644 --- a/src/containers/Chat/ChatMessages/ChatMessage/PollMessage/PollMessage.tsx +++ b/src/containers/Chat/ChatMessages/ChatMessage/PollMessage/PollMessage.tsx @@ -48,7 +48,7 @@ export const PollMessage = ({ />
) : ( - isSimulator &&
Option {option.id + 1}
+ isSimulator &&
Option {index + 1}
)} ); From f52d6b1b0ba000be94b8946a517ef8c78fa3fe94 Mon Sep 17 00:00:00 2001 From: Akansha Sakhre Date: Wed, 15 Jan 2025 15:48:51 +0530 Subject: [PATCH 16/38] reorganised imports --- .../WaPolls/WaPollOptions/WaPollOptions.tsx | 8 ++++---- src/containers/WaGroups/WaPolls/WaPolls.tsx | 12 +++++++----- .../WaGroups/WaPolls/WaPollsList/WaPollsList.tsx | 16 +++++++++------- src/graphql/queries/WaPolls.ts | 2 +- 4 files changed, 21 insertions(+), 17 deletions(-) diff --git a/src/containers/WaGroups/WaPolls/WaPollOptions/WaPollOptions.tsx b/src/containers/WaGroups/WaPolls/WaPollOptions/WaPollOptions.tsx index 529b7dbcec..6ed1965e1f 100644 --- a/src/containers/WaGroups/WaPolls/WaPollOptions/WaPollOptions.tsx +++ b/src/containers/WaGroups/WaPolls/WaPollOptions/WaPollOptions.tsx @@ -1,10 +1,10 @@ +import EmojiEmotionsOutlinedIcon from '@mui/icons-material/EmojiEmotionsOutlined'; import { ClickAwayListener, FormControl, FormHelperText, IconButton, TextField, Typography } from '@mui/material'; -import styles from './WaPollOptions.module.css'; -import { Button } from 'components/UI/Form/Button/Button'; +import { useState } from 'react'; import CrossIcon from 'assets/images/icons/Cross.svg?react'; import EmojiPicker from 'components/UI/EmojiPicker/EmojiPicker'; -import { useState } from 'react'; -import EmojiEmotionsOutlinedIcon from '@mui/icons-material/EmojiEmotionsOutlined'; +import { Button } from 'components/UI/Form/Button/Button'; +import styles from './WaPollOptions.module.css'; interface WaPollOptionsProps { form: { field: any; errors: any; touched: any; values: any; setFieldValue: any }; diff --git a/src/containers/WaGroups/WaPolls/WaPolls.tsx b/src/containers/WaGroups/WaPolls/WaPolls.tsx index e60fa9e6e3..e996e1ae8a 100644 --- a/src/containers/WaGroups/WaPolls/WaPolls.tsx +++ b/src/containers/WaGroups/WaPolls/WaPolls.tsx @@ -1,16 +1,18 @@ import { Typography } from '@mui/material'; -import { Input } from 'components/UI/Form/Input/Input'; -import { FormLayout } from 'containers/Form/FormLayout'; import { useState } from 'react'; import { useTranslation } from 'react-i18next'; +import { useLocation, useParams } from 'react-router'; import * as Yup from 'yup'; + import PollsIcon from 'assets/images/Polls.svg?react'; import { Checkbox } from 'components/UI/Form/Checkbox/Checkbox'; -import styles from './WaPolls.module.css'; -import { WaPollOptions } from './WaPollOptions/WaPollOptions'; +import { Input } from 'components/UI/Form/Input/Input'; +import { FormLayout } from 'containers/Form/FormLayout'; import { COPY_POLL, CREATE_POLL, DELETE_POLL } from 'graphql/mutations/WaPolls'; import { GET_POLL } from 'graphql/queries/WaPolls'; -import { useLocation, useParams } from 'react-router'; + +import { WaPollOptions } from './WaPollOptions/WaPollOptions'; +import styles from './WaPolls.module.css'; const queries = { getItemQuery: GET_POLL, diff --git a/src/containers/WaGroups/WaPolls/WaPollsList/WaPollsList.tsx b/src/containers/WaGroups/WaPolls/WaPollsList/WaPollsList.tsx index 6e23648a85..96e8383a82 100644 --- a/src/containers/WaGroups/WaPolls/WaPollsList/WaPollsList.tsx +++ b/src/containers/WaGroups/WaPolls/WaPollsList/WaPollsList.tsx @@ -1,17 +1,19 @@ +import { useMutation } from '@apollo/client'; +import { useState } from 'react'; import { useTranslation } from 'react-i18next'; +import { useNavigate } from 'react-router'; + import CollectionIcon from 'assets/images/icons/Collection/Dark.svg?react'; import DeleteIcon from 'assets/images/icons/Delete/Red.svg?react'; import DuplicateIcon from 'assets/images/icons/Duplicate.svg?react'; -import styles from './WaPollsList.module.css'; -import { List } from 'containers/List/List'; -import { useState } from 'react'; -import { useNavigate } from 'react-router'; import { pollsInfo } from 'common/HelpData'; +import { setErrorMessage, setNotification } from 'common/notification'; import { DialogBox } from 'components/UI/DialogBox/DialogBox'; -import { GET_POLLS, GET_POLLS_COUNT } from 'graphql/queries/WaPolls'; +import { List } from 'containers/List/List'; import { DELETE_POLL } from 'graphql/mutations/WaPolls'; -import { useMutation } from '@apollo/client'; -import { setErrorMessage, setNotification } from 'common/notification'; +import { GET_POLLS, GET_POLLS_COUNT } from 'graphql/queries/WaPolls'; + +import styles from './WaPollsList.module.css'; const queries = { countQuery: GET_POLLS_COUNT, diff --git a/src/graphql/queries/WaPolls.ts b/src/graphql/queries/WaPolls.ts index b6b2f00d34..115698edfe 100644 --- a/src/graphql/queries/WaPolls.ts +++ b/src/graphql/queries/WaPolls.ts @@ -29,6 +29,6 @@ export const GET_POLL = gql` export const GET_POLLS_COUNT = gql` query RootQueryType($filter: WaPollFilter) { - countWaPolls(filter: $filter) + countPoll: countWaPolls(filter: $filter) } `; From a4b7eebb4a91ccf4711e0cbde28ec18395a6b5ec Mon Sep 17 00:00:00 2001 From: Akansha Sakhre Date: Fri, 17 Jan 2025 10:33:10 +0530 Subject: [PATCH 17/38] deepscan fixes --- .../WaGroups/WaPolls/WaPollsList/WaPollsList.tsx | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/containers/WaGroups/WaPolls/WaPollsList/WaPollsList.tsx b/src/containers/WaGroups/WaPolls/WaPollsList/WaPollsList.tsx index 96e8383a82..846f8e11e9 100644 --- a/src/containers/WaGroups/WaPolls/WaPollsList/WaPollsList.tsx +++ b/src/containers/WaGroups/WaPolls/WaPollsList/WaPollsList.tsx @@ -24,7 +24,11 @@ const queries = { const getLabel = (label: string) =>
{label}
; const getContent = (content: string) => { - return
{content.length < 100 ? content : `${content.slice(0, 100)}...`}
; + return ( +
+ {content ? (content.length < 100 ? content : `${content.slice(0, 100)}...`) : ''} +
+ ); }; export const WaPollsList = () => { const [deleteWaPollId, setDeleteWaPollId] = useState(null); @@ -44,7 +48,7 @@ export const WaPollsList = () => { const content = pollContent ? JSON.parse(pollContent) : {}; return { label: getLabel(label), - content: getContent(content?.text), + content: getContent(content.text), }; }; From 71d2aa7e89ac67024460205ebf85f6e1012fdb02 Mon Sep 17 00:00:00 2001 From: Akansha Sakhre Date: Fri, 17 Jan 2025 11:04:23 +0530 Subject: [PATCH 18/38] fixed delete functionality --- .../WaGroups/WaPolls/WaPollsList/WaPollsList.tsx | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/containers/WaGroups/WaPolls/WaPollsList/WaPollsList.tsx b/src/containers/WaGroups/WaPolls/WaPollsList/WaPollsList.tsx index 846f8e11e9..913cdc9e99 100644 --- a/src/containers/WaGroups/WaPolls/WaPollsList/WaPollsList.tsx +++ b/src/containers/WaGroups/WaPolls/WaPollsList/WaPollsList.tsx @@ -32,6 +32,7 @@ const getContent = (content: string) => { }; export const WaPollsList = () => { const [deleteWaPollId, setDeleteWaPollId] = useState(null); + const [refreshList, setRefreshList] = useState(false); const { t } = useTranslation(); const navigate = useNavigate(); @@ -67,6 +68,7 @@ export const WaPollsList = () => { onCompleted: () => { setNotification('Poll deleted successfully', 'success'); setDeleteWaPollId(null); + setRefreshList(!refreshList); }, onError: (error) => setErrorMessage(error), }); @@ -88,7 +90,7 @@ export const WaPollsList = () => { { label: t('Delete'), icon: , - parameter: 'label', + parameter: 'id', dialog: (id: any) => setDeleteWaPollId(id), insideMore: false, }, @@ -119,16 +121,17 @@ export const WaPollsList = () => { listItem="poll" columnNames={columnNames} listItemName="poll" - button={{ - show: true, - label: t('Create'), - }} pageLink={`group/polls`} listIcon={collectionIcon} dialogMessage={dialogMessage} additionalAction={additionalAction} restrictedAction={getRestrictedAction} helpData={pollsInfo} + refreshList={refreshList} + button={{ + show: true, + label: t('Create'), + }} {...queries} {...columnAttributes} /> From 759e27bb4c9a7bcf50c8e908d59280ba096a08b0 Mon Sep 17 00:00:00 2001 From: Akansha Sakhre Date: Mon, 20 Jan 2025 11:04:12 +0530 Subject: [PATCH 19/38] added test cases --- src/containers/List/List.tsx | 2 +- .../WaPolls/WaPollOptions/WaPollOptions.tsx | 2 +- .../WaGroups/WaPolls/WaPolls.test.tsx | 101 ++++++++++++ src/containers/WaGroups/WaPolls/WaPolls.tsx | 2 +- .../ViewPollDialog/ViewPollDialog.tsx | 1 - .../WaPolls/WaPollsList/WaPollsList.test.tsx | 89 ++++++++++ .../WaPolls/WaPollsList/WaPollsList.tsx | 7 +- src/i18n/en/en.json | 2 +- src/mocks/WaPolls.tsx | 152 ++++++++++++++++++ 9 files changed, 348 insertions(+), 10 deletions(-) create mode 100644 src/containers/WaGroups/WaPolls/WaPolls.test.tsx create mode 100644 src/containers/WaGroups/WaPolls/WaPollsList/WaPollsList.test.tsx create mode 100644 src/mocks/WaPolls.tsx diff --git a/src/containers/List/List.tsx b/src/containers/List/List.tsx index 54742b58ea..f04e42c7f1 100644 --- a/src/containers/List/List.tsx +++ b/src/containers/List/List.tsx @@ -107,7 +107,7 @@ export interface ListProps { dialogMessage?: string | any; pageLink: string; columns: Function; - listIcon: React.ReactNode; + listIcon?: React.ReactNode; helpData?: HelpDataProps; columnStyles: Array; secondaryButton?: any; diff --git a/src/containers/WaGroups/WaPolls/WaPollOptions/WaPollOptions.tsx b/src/containers/WaGroups/WaPolls/WaPollOptions/WaPollOptions.tsx index 0d1d8a6e1b..4a420562fa 100644 --- a/src/containers/WaGroups/WaPolls/WaPollOptions/WaPollOptions.tsx +++ b/src/containers/WaGroups/WaPolls/WaPollOptions/WaPollOptions.tsx @@ -77,7 +77,7 @@ export const WaPollOptions = ({ {values.options.length < 10 && !isEditing && ( - )} diff --git a/src/containers/WaGroups/WaPolls/WaPolls.test.tsx b/src/containers/WaGroups/WaPolls/WaPolls.test.tsx new file mode 100644 index 0000000000..d9235de31b --- /dev/null +++ b/src/containers/WaGroups/WaPolls/WaPolls.test.tsx @@ -0,0 +1,101 @@ +import { MockedProvider } from '@apollo/client/testing'; +import { MemoryRouter, Route, Routes } from 'react-router'; +import { cleanup, fireEvent, render, screen, waitFor } from '@testing-library/react'; +import * as Notification from 'common/notification'; +import { WaPollMocks } from 'mocks/WaPolls'; +import WaPolls from './WaPolls'; +import WaPollsList from './WaPollsList/WaPollsList'; + +const notificationSpy = vi.spyOn(Notification, 'setNotification'); +const mockUseLocationValue: any = { + pathname: '/', + search: '', + hash: '', + state: null, +}; + +vi.mock('react-router-dom', async () => ({ + ...((await vi.importActual('react-router-dom')) as {}), + useLocation: () => { + return mockUseLocationValue; + }, + Navigate: ({ to }: any) =>
Navigated to {to}
, +})); + +beforeEach(() => { + cleanup(); +}); + +describe('Create', () => { + test('it should create a whatsapp poll', async () => { + render( + + + + } /> + } /> + } /> + + + + ); + + await waitFor(() => { + expect(screen.getByText('Add a new waPoll')).toBeInTheDocument(); + }); + + const inputs = screen.getAllByRole('textbox'); + + fireEvent.change(inputs[0], { target: { value: 'Poll Title' } }); + fireEvent.change(inputs[1], { target: { value: 'Poll Content' } }); + + fireEvent.change(screen.getByPlaceholderText('Option 1'), { target: { value: 'Option 1' } }); + fireEvent.change(screen.getByPlaceholderText('Option 2'), { target: { value: 'Option 2' } }); + + fireEvent.click(screen.getByTestId('add-btn')); + + fireEvent.change(screen.getByPlaceholderText('Option 3'), { target: { value: 'Option 3' } }); + + fireEvent.click(screen.getAllByTestId('cross-icon')[1]); + + fireEvent.click(screen.getByText('Allow multiple options')); + + fireEvent.click(screen.getByTestId('submitActionButton')); + + await waitFor(() => { + expect(notificationSpy).toHaveBeenCalled(); + }); + }); +}); + +describe('Copy', () => { + test('it should copy a whatsapp poll', async () => { + mockUseLocationValue.state = 'copy'; + + const copyFlow = ( + + + + } /> + + + + ); + + render(copyFlow); + + await waitFor(() => { + expect(screen.getByText('Copy waPoll')).toBeInTheDocument(); + }); + + await waitFor(() => { + expect(screen.getAllByRole('textbox')[0]).toHaveValue('Copy of Poll Title'); + }); + + fireEvent.click(screen.getByTestId('submitActionButton')); + + await waitFor(() => { + expect(notificationSpy).toHaveBeenCalled(); + }); + }); +}); diff --git a/src/containers/WaGroups/WaPolls/WaPolls.tsx b/src/containers/WaGroups/WaPolls/WaPolls.tsx index b39b0e2cfa..03976b0ddb 100644 --- a/src/containers/WaGroups/WaPolls/WaPolls.tsx +++ b/src/containers/WaGroups/WaPolls/WaPolls.tsx @@ -1,7 +1,7 @@ import { Typography } from '@mui/material'; import { useState } from 'react'; import { useTranslation } from 'react-i18next'; -import { useLocation, useParams } from 'react-router'; +import { useLocation, useParams } from 'react-router-dom'; import * as Yup from 'yup'; import PollsIcon from 'assets/images/Polls.svg?react'; diff --git a/src/containers/WaGroups/WaPolls/WaPollsList/ViewPollDialog/ViewPollDialog.tsx b/src/containers/WaGroups/WaPolls/WaPollsList/ViewPollDialog/ViewPollDialog.tsx index 0ef95f477c..17abc895a0 100644 --- a/src/containers/WaGroups/WaPolls/WaPollsList/ViewPollDialog/ViewPollDialog.tsx +++ b/src/containers/WaGroups/WaPolls/WaPollsList/ViewPollDialog/ViewPollDialog.tsx @@ -18,7 +18,6 @@ export const ViewPoll = ({ id, onClose }: ViewPollProps) => { const poll = data?.waPoll?.waPoll; const pollContent = poll?.pollContent ? JSON.parse(poll?.pollContent) : {}; - console.log(poll); if (loading) { return ; diff --git a/src/containers/WaGroups/WaPolls/WaPollsList/WaPollsList.test.tsx b/src/containers/WaGroups/WaPolls/WaPollsList/WaPollsList.test.tsx new file mode 100644 index 0000000000..8787120ee3 --- /dev/null +++ b/src/containers/WaGroups/WaPolls/WaPollsList/WaPollsList.test.tsx @@ -0,0 +1,89 @@ +import { MockedProvider } from '@apollo/client/testing'; +import { MemoryRouter, Route, Routes } from 'react-router'; +import { fireEvent, render, screen, waitFor } from '@testing-library/react'; +import * as Notification from 'common/notification'; +import { WaPollListMocks } from 'mocks/WaPolls'; +import WaPolls from '../WaPolls'; +import WaPollsList from './WaPollsList'; + +const wrapper = ( + + + + } /> + } /> + + + +); + +const notificationSpy = vi.spyOn(Notification, 'setNotification'); +const mockedUsedNavigate = vi.fn(); +vi.mock('react-router-dom', async () => ({ + ...(await vi.importActual('react-router-dom')), + useNavigate: () => mockedUsedNavigate, +})); + +test('it should render the WaPollsList component', async () => { + render(wrapper); + + await waitFor(() => { + expect(screen.getByText('WhatsApp Polls')).toBeInTheDocument(); + }); + + await waitFor(() => { + expect(screen.getByText('poll 1')).toBeInTheDocument(); + }); +}); + +test('it should open the view dialog box', async () => { + render(wrapper); + + await waitFor(() => { + expect(screen.getByText('WhatsApp Polls')).toBeInTheDocument(); + }); + + fireEvent.click(screen.getAllByTestId('view-icon')[0]); + + await waitFor(() => { + expect(screen.getByTestId('dialogBox')).toBeInTheDocument(); + }); + + fireEvent.click(screen.getByTestId('CloseIcon')); +}); + +test('it navigates to create a copy', async () => { + render(wrapper); + + await waitFor(() => { + expect(screen.getByText('WhatsApp Polls')).toBeInTheDocument(); + }); + + fireEvent.click(screen.getAllByTestId('copy-icon')[0]); + + await waitFor(() => { + expect(screen.getByText('Copy waPoll')).toBeInTheDocument(); + }); +}); + +test('it should delete the poll', async () => { + render(wrapper); + + await waitFor(() => { + expect(screen.getByText('WhatsApp Polls')).toBeInTheDocument(); + }); + + fireEvent.click(screen.getAllByTestId('delete-icon')[0]); + fireEvent.click(screen.getByTestId('CloseIcon')); + fireEvent.click(screen.getAllByTestId('delete-icon')[0]); + + await waitFor(() => { + expect(screen.getByTestId('dialogBox')).toBeInTheDocument(); + }); + + fireEvent.click(screen.getByTestId('ok-button')); + + await waitFor(() => { + expect(notificationSpy).toHaveBeenCalled(); + }); +}); diff --git a/src/containers/WaGroups/WaPolls/WaPollsList/WaPollsList.tsx b/src/containers/WaGroups/WaPolls/WaPollsList/WaPollsList.tsx index 0de97d154b..e357de2cf5 100644 --- a/src/containers/WaGroups/WaPolls/WaPollsList/WaPollsList.tsx +++ b/src/containers/WaGroups/WaPolls/WaPollsList/WaPollsList.tsx @@ -3,7 +3,6 @@ import { useState } from 'react'; import { useTranslation } from 'react-i18next'; import { useNavigate } from 'react-router'; -import CollectionIcon from 'assets/images/icons/Collection/Dark.svg?react'; import DeleteIcon from 'assets/images/icons/Delete/Red.svg?react'; import DuplicateIcon from 'assets/images/icons/Duplicate.svg?react'; import ViewIcon from 'assets/images/icons/ViewLight.svg?react'; @@ -43,8 +42,7 @@ export const WaPollsList = () => { const [deletePoll, { loading }] = useMutation(DELETE_POLL); const columnNames = [{ name: 'label', label: 'Title' }, { label: 'Content' }, { label: t('Actions') }]; - const title = t('Group polls'); - const collectionIcon = ; + const title = t('WhatsApp Polls'); const dialogMessage = t("You won't be able to use this collection again."); const columnStyles = [styles.Label, styles.Content, styles.Actions]; @@ -92,7 +90,7 @@ export const WaPollsList = () => { }, { label: t('Copy'), - icon: , + icon: , parameter: 'id', insideMore: false, dialog: handleCopy, @@ -132,7 +130,6 @@ export const WaPollsList = () => { columnNames={columnNames} listItemName="poll" pageLink={`group/polls`} - listIcon={collectionIcon} dialogMessage={dialogMessage} additionalAction={additionalAction} restrictedAction={getRestrictedAction} diff --git a/src/i18n/en/en.json b/src/i18n/en/en.json index e2fb3db4fa..a7ef152496 100644 --- a/src/i18n/en/en.json +++ b/src/i18n/en/en.json @@ -533,5 +533,5 @@ "Last name is required.": "Last name is required.", "Failed": "Failed", "Members": "Members", - "Group polls": "Group polls" + "WhatsApp Polls": "WhatsApp Polls" } diff --git a/src/mocks/WaPolls.tsx b/src/mocks/WaPolls.tsx new file mode 100644 index 0000000000..47475a4896 --- /dev/null +++ b/src/mocks/WaPolls.tsx @@ -0,0 +1,152 @@ +import { COPY_POLL, CREATE_POLL, DELETE_POLL } from 'graphql/mutations/WaPolls'; +import { filterRolesQuery } from './Role'; +import { GET_POLL, GET_POLLS, GET_POLLS_COUNT } from 'graphql/queries/WaPolls'; + +const createPoll = { + request: { + query: CREATE_POLL, + }, + result: { + data: { + createWaPoll: { + errors: null, + waPoll: { + id: '8', + }, + }, + }, + }, + variableMatcher: () => true, +}; + +const getPoll = { + request: { + query: GET_POLL, + variables: { + id: '1', + }, + }, + result: { + data: { + waPoll: { + __typename: 'WaPollResult', + errors: null, + waPoll: { + allowMultipleAnswer: true, + id: '8', + label: 'Poll Title', + pollContent: + '{"text":"Poll Content","options":[{"name":"Option 1","id":0},{"name":"Option 3","id":0.6781005888671008}]}', + }, + }, + }, + }, +}; + +const copyPoll = { + request: { + query: COPY_POLL, + variables: { + id: '1', + input: { + label: 'Copy of Poll Title', + poll_content: + '{"options":[{"name":"Option 1","id":0},{"name":"Option 3","id":0.6781005888671008}],"text":"Poll Content"}', + allow_multiple_answer: true, + }, + }, + }, + result: { + data: { + copyWaPoll: { + waPoll: { + id: '2', + label: 'Copy of Poll Title', + }, + }, + }, + }, +}; + +const listPollsQuery = { + request: { + query: GET_POLLS, + variables: { filter: {}, opts: { limit: 50, offset: 0, order: 'ASC', orderWith: 'label' } }, + }, + result: { + data: { + poll: [ + { + allowMultipleAnswer: false, + id: '1', + label: 'poll 1', + pollContent: '{"text":"text","options":[{"name":"1","id":0},{"name":"2","id":1}]}', + }, + { + allowMultipleAnswer: true, + id: '8', + label: 'Poll Title', + pollContent: + '{"text":"Poll Content","options":[{"name":"Option 1","id":0},{"name":"Option 3","id":0.6781005888671008}]}', + }, + { + allowMultipleAnswer: true, + id: '5', + label: 'polllll', + pollContent: + '{"text":"How frequently do you participate in our activities or events, and what influences your level of involvement?","options":[{"name":"Everyday","id":0},{"name":"Once a week","id":1},{"name":"Monthly","id":2},{"name":"Never","id":3}]}', + }, + { + allowMultipleAnswer: false, + id: '3', + label: 'titek 1', + pollContent: '{"text":"sdcfd","options":[{"name":"dfv","id":0},{"name":"sdf","id":1}]}', + }, + { + allowMultipleAnswer: false, + id: '4', + label: 'we', + pollContent: '{"text":"s","options":[{"name":"dds","id":0},{"name":"ss","id":1}]}', + }, + ], + }, + }, +}; + +const countPollsQuery = { + request: { + query: GET_POLLS_COUNT, + variables: { filter: {} }, + }, + result: { + data: { + countPoll: 5, + }, + }, +}; + +const deletePollQuery = { + request: { + query: DELETE_POLL, + variables: { deleteWaPollId: '1' }, + }, + result: { + data: { + deleteWaPoll: { + errors: null, + waPoll: null, + }, + }, + }, +}; + +export const WaPollListMocks = [ + filterRolesQuery, + listPollsQuery, + listPollsQuery, + countPollsQuery, + countPollsQuery, + getPoll, + deletePollQuery, +]; +export const WaPollMocks = [filterRolesQuery, createPoll, getPoll, copyPoll]; From eede1426f86495b2b71b694120cdc25dc9be2098 Mon Sep 17 00:00:00 2001 From: Akansha Sakhre Date: Mon, 20 Jan 2025 11:10:39 +0530 Subject: [PATCH 20/38] changed form name --- src/containers/WaGroups/WaPolls/WaPolls.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/containers/WaGroups/WaPolls/WaPolls.tsx b/src/containers/WaGroups/WaPolls/WaPolls.tsx index e996e1ae8a..4cedecd873 100644 --- a/src/containers/WaGroups/WaPolls/WaPolls.tsx +++ b/src/containers/WaGroups/WaPolls/WaPolls.tsx @@ -140,7 +140,7 @@ export const WaPolls = () => { languageSupport={false} setStates={setStates} validationSchema={FormSchema} - listItemName="waPoll" + listItemName="Poll" dialogMessage={dialogMessage} formFields={formFields} redirectionLink={'group/polls'} From 5393f241104d25292823f58c89da173b14a65424 Mon Sep 17 00:00:00 2001 From: Akansha Sakhre Date: Mon, 20 Jan 2025 11:30:33 +0530 Subject: [PATCH 21/38] removed download icon --- .../ChatMessage/ChatMessage.module.css | 5 ++ .../ChatMessages/ChatMessage/ChatMessage.tsx | 86 ++++++++++--------- .../Chat/ChatMessages/ChatMessages.tsx | 1 + 3 files changed, 51 insertions(+), 41 deletions(-) diff --git a/src/containers/Chat/ChatMessages/ChatMessage/ChatMessage.module.css b/src/containers/Chat/ChatMessages/ChatMessage/ChatMessage.module.css index 1c01b663da..8b62eb7ea4 100644 --- a/src/containers/Chat/ChatMessages/ChatMessage/ChatMessage.module.css +++ b/src/containers/Chat/ChatMessages/ChatMessage/ChatMessage.module.css @@ -298,3 +298,8 @@ padding-bottom: 8px; font-weight: bold; } + +.NoIcon { + margin: 0 1rem; + /* background-color: red !important; */ +} diff --git a/src/containers/Chat/ChatMessages/ChatMessage/ChatMessage.tsx b/src/containers/Chat/ChatMessages/ChatMessage/ChatMessage.tsx index d563222d66..fc41352ffb 100644 --- a/src/containers/Chat/ChatMessages/ChatMessage/ChatMessage.tsx +++ b/src/containers/Chat/ChatMessages/ChatMessage/ChatMessage.tsx @@ -56,6 +56,7 @@ export interface ChatMessageProps { groups?: boolean; status?: string; contact?: any; + showIcon?: boolean; } export const ChatMessage = ({ @@ -81,6 +82,7 @@ export const ChatMessage = ({ groups, status, contact, + showIcon = true, }: ChatMessageProps) => { const [showSaveMessageDialog, setShowSaveMessageDialog] = useState(false); const Ref = useRef(null); @@ -335,8 +337,8 @@ export const ChatMessage = ({ ) : null} -
- {iconLeft && icon} +
+ {showIcon && iconLeft && icon} {ErrorIcon}
@@ -361,47 +363,49 @@ export const ChatMessage = ({
- - {({ TransitionProps }) => ( - - - - {type !== 'TEXT' && ( - -
- -
- )} -
-
- )} -
+ ]} + anchorEl={anchorEl} + placement={placement} + transition + data-testid="popup" + > + {({ TransitionProps }) => ( + + + + {type !== 'TEXT' && ( + +
+ +
+ )} +
+
+ )} + + )}
- {iconLeft ? null : icon} + {iconLeft ? null : showIcon && icon}
{sendBy}
diff --git a/src/containers/Chat/ChatMessages/ChatMessages.tsx b/src/containers/Chat/ChatMessages/ChatMessages.tsx index ae43b3d5bc..90e7d98b4d 100644 --- a/src/containers/Chat/ChatMessages/ChatMessages.tsx +++ b/src/containers/Chat/ChatMessages/ChatMessages.tsx @@ -549,6 +549,7 @@ export const ChatMessages = ({ entityId, collectionId, phoneId }: ChatMessagesPr onClick={() => showEditDialog(message.id)} focus={index === 0} jumpToMessage={jumpToMessage} + showIcon={!groups} daySeparator={showDaySeparator( reverseConversation[index].insertedAt, reverseConversation[index + 1] ? reverseConversation[index + 1].insertedAt : null From 825338c113321b9f2c55a02df53ac96a88cb9fab Mon Sep 17 00:00:00 2001 From: Akansha Sakhre Date: Mon, 20 Jan 2025 16:01:11 +0530 Subject: [PATCH 22/38] minor fixes --- .../WaPolls/WaPollOptions/WaPollOptions.tsx | 36 +++++++++++-------- .../WaPolls/WaPollsList/WaPollsList.tsx | 18 +++++++++- src/graphql/queries/WaPolls.ts | 1 + src/i18n/en/en.json | 3 +- 4 files changed, 41 insertions(+), 17 deletions(-) diff --git a/src/containers/WaGroups/WaPolls/WaPollOptions/WaPollOptions.tsx b/src/containers/WaGroups/WaPolls/WaPollOptions/WaPollOptions.tsx index 6ed1965e1f..8c2195988a 100644 --- a/src/containers/WaGroups/WaPolls/WaPollOptions/WaPollOptions.tsx +++ b/src/containers/WaGroups/WaPolls/WaPollOptions/WaPollOptions.tsx @@ -21,7 +21,8 @@ const emojiStyles = { export const WaPollOptions = ({ form: { values, setFieldValue, errors, touched }, isEditing }: WaPollOptionsProps) => { const handleAddOption = () => { - setFieldValue('options', [...values.options, { name: '', id: Math.random() }]); + const lastId = values?.options[values?.options.length - 1]?.id; + setFieldValue('options', [...values.options, { name: '', id: lastId + 1 }]); }; const handleInput = (value: any, id: any) => { @@ -66,7 +67,7 @@ export const WaPollOptions = ({ form: { values, setFieldValue, errors, touched } {errors['options'] && typeof errors['options'] === 'string' && errors['options']} - {values.options.length < 10 && !isEditing && ( + {values.options.length < 12 && !isEditing && ( @@ -116,16 +117,24 @@ const PollOption = ({ input: { endAdornment: !isEditing && ( setShowEmojiPicker(false)}> - setShowEmojiPicker(!showEmojiPicker)} - > - - +
+ setShowEmojiPicker(!showEmojiPicker)} + > + + + {showEmojiPicker && ( + handleEmojiAdd(emoji, option.id)} + displayStyle={emojiStyles} + /> + )} +
), }, @@ -140,9 +149,6 @@ const PollOption = ({ onClick={() => handleRemoveClick(option.id)} /> )} - {showEmojiPicker && ( - handleEmojiAdd(emoji, option.id)} displayStyle={emojiStyles} /> - )}
{hasError ? {errors[ind]?.name || ''} : null} diff --git a/src/containers/WaGroups/WaPolls/WaPollsList/WaPollsList.tsx b/src/containers/WaGroups/WaPolls/WaPollsList/WaPollsList.tsx index 913cdc9e99..f2a30d1f72 100644 --- a/src/containers/WaGroups/WaPolls/WaPollsList/WaPollsList.tsx +++ b/src/containers/WaGroups/WaPolls/WaPollsList/WaPollsList.tsx @@ -4,8 +4,10 @@ import { useTranslation } from 'react-i18next'; import { useNavigate } from 'react-router'; import CollectionIcon from 'assets/images/icons/Collection/Dark.svg?react'; +import CopyAllOutlined from 'assets/images/icons/Flow/Copy.svg?react'; import DeleteIcon from 'assets/images/icons/Delete/Red.svg?react'; import DuplicateIcon from 'assets/images/icons/Duplicate.svg?react'; +import { copyToClipboardMethod } from 'common/utils'; import { pollsInfo } from 'common/HelpData'; import { setErrorMessage, setNotification } from 'common/notification'; import { DialogBox } from 'components/UI/DialogBox/DialogBox'; @@ -74,6 +76,14 @@ export const WaPollsList = () => { }); }; + const copyUuid = (_id: string, item: any) => { + if (item.uuid) { + copyToClipboardMethod(item.uuid); + } else { + setNotification('Sorry! UUID not found', 'warning'); + } + }; + const getRestrictedAction = () => { const action: any = { edit: false, delete: false }; return action; @@ -81,7 +91,13 @@ export const WaPollsList = () => { const additionalAction = () => [ { - label: t('Copy'), + label: t('Copy UUID'), + icon: , + parameter: 'id', + dialog: copyUuid, + }, + { + label: t('Copy Poll'), icon: , parameter: 'id', insideMore: false, diff --git a/src/graphql/queries/WaPolls.ts b/src/graphql/queries/WaPolls.ts index 115698edfe..fd7856701e 100644 --- a/src/graphql/queries/WaPolls.ts +++ b/src/graphql/queries/WaPolls.ts @@ -7,6 +7,7 @@ export const GET_POLLS = gql` id label pollContent + uuid } } `; diff --git a/src/i18n/en/en.json b/src/i18n/en/en.json index e2fb3db4fa..245289e583 100644 --- a/src/i18n/en/en.json +++ b/src/i18n/en/en.json @@ -533,5 +533,6 @@ "Last name is required.": "Last name is required.", "Failed": "Failed", "Members": "Members", - "Group polls": "Group polls" + "Group polls": "Group polls", + "Copy Poll": "Copy Poll" } From e344750af1111a36a236a117b804f8d832164d48 Mon Sep 17 00:00:00 2001 From: Akansha Sakhre Date: Mon, 20 Jan 2025 16:13:17 +0530 Subject: [PATCH 23/38] Added test cases --- .../WaPolls/WaPollOptions/WaPollOptions.tsx | 2 +- .../WaGroups/WaPolls/WaPolls.test.tsx | 4 ++-- .../WaPolls/WaPollsList/WaPollsList.test.tsx | 18 ++++++++++++++++-- .../WaPolls/WaPollsList/WaPollsList.tsx | 14 +++++++------- src/mocks/WaPolls.tsx | 5 +++++ 5 files changed, 31 insertions(+), 12 deletions(-) diff --git a/src/containers/WaGroups/WaPolls/WaPollOptions/WaPollOptions.tsx b/src/containers/WaGroups/WaPolls/WaPollOptions/WaPollOptions.tsx index b9ec3827b1..0251fe8ee8 100644 --- a/src/containers/WaGroups/WaPolls/WaPollOptions/WaPollOptions.tsx +++ b/src/containers/WaGroups/WaPolls/WaPollOptions/WaPollOptions.tsx @@ -78,7 +78,7 @@ export const WaPollOptions = ({ {values.options.length < 12 && !isEditing && ( - )} diff --git a/src/containers/WaGroups/WaPolls/WaPolls.test.tsx b/src/containers/WaGroups/WaPolls/WaPolls.test.tsx index d9235de31b..c57530fd60 100644 --- a/src/containers/WaGroups/WaPolls/WaPolls.test.tsx +++ b/src/containers/WaGroups/WaPolls/WaPolls.test.tsx @@ -41,7 +41,7 @@ describe('Create', () => { ); await waitFor(() => { - expect(screen.getByText('Add a new waPoll')).toBeInTheDocument(); + expect(screen.getByText('Add a new Poll')).toBeInTheDocument(); }); const inputs = screen.getAllByRole('textbox'); @@ -85,7 +85,7 @@ describe('Copy', () => { render(copyFlow); await waitFor(() => { - expect(screen.getByText('Copy waPoll')).toBeInTheDocument(); + expect(screen.getByText('Copy Poll')).toBeInTheDocument(); }); await waitFor(() => { diff --git a/src/containers/WaGroups/WaPolls/WaPollsList/WaPollsList.test.tsx b/src/containers/WaGroups/WaPolls/WaPollsList/WaPollsList.test.tsx index 8787120ee3..710215d226 100644 --- a/src/containers/WaGroups/WaPolls/WaPollsList/WaPollsList.test.tsx +++ b/src/containers/WaGroups/WaPolls/WaPollsList/WaPollsList.test.tsx @@ -36,6 +36,20 @@ test('it should render the WaPollsList component', async () => { }); }); +test('it should copy the uuid', async () => { + render(wrapper); + + await waitFor(() => { + expect(screen.getByText('WhatsApp Polls')).toBeInTheDocument(); + }); + + fireEvent.click(screen.getAllByTestId('copy-icon')[0]); + + await waitFor(() => { + expect(notificationSpy).toHaveBeenCalled(); + }); +}); + test('it should open the view dialog box', async () => { render(wrapper); @@ -59,10 +73,10 @@ test('it navigates to create a copy', async () => { expect(screen.getByText('WhatsApp Polls')).toBeInTheDocument(); }); - fireEvent.click(screen.getAllByTestId('copy-icon')[0]); + fireEvent.click(screen.getAllByTestId('duplicate-icon')[0]); await waitFor(() => { - expect(screen.getByText('Copy waPoll')).toBeInTheDocument(); + expect(screen.getByText('Copy Poll')).toBeInTheDocument(); }); }); diff --git a/src/containers/WaGroups/WaPolls/WaPollsList/WaPollsList.tsx b/src/containers/WaGroups/WaPolls/WaPollsList/WaPollsList.tsx index 297de837c0..3ffd9f9cec 100644 --- a/src/containers/WaGroups/WaPolls/WaPollsList/WaPollsList.tsx +++ b/src/containers/WaGroups/WaPolls/WaPollsList/WaPollsList.tsx @@ -91,6 +91,12 @@ export const WaPollsList = () => { }; const additionalAction = () => [ + { + label: t('Copy UUID'), + icon: , + parameter: 'id', + dialog: copyUuid, + }, { label: t('View'), icon: , @@ -98,15 +104,9 @@ export const WaPollsList = () => { dialog: (id: any) => setViewWaPollId(id), insideMore: false, }, - { - label: t('Copy UUID'), - icon: , - parameter: 'id', - dialog: copyUuid, - }, { label: t('Copy Poll'), - icon: , + icon: , parameter: 'id', insideMore: false, dialog: handleCopy, diff --git a/src/mocks/WaPolls.tsx b/src/mocks/WaPolls.tsx index 47475a4896..088b75e870 100644 --- a/src/mocks/WaPolls.tsx +++ b/src/mocks/WaPolls.tsx @@ -81,6 +81,7 @@ const listPollsQuery = { id: '1', label: 'poll 1', pollContent: '{"text":"text","options":[{"name":"1","id":0},{"name":"2","id":1}]}', + uuid: '6fa459ea-ee8a-3ca4-894e-db77e160355e', }, { allowMultipleAnswer: true, @@ -88,6 +89,7 @@ const listPollsQuery = { label: 'Poll Title', pollContent: '{"text":"Poll Content","options":[{"name":"Option 1","id":0},{"name":"Option 3","id":0.6781005888671008}]}', + uuid: '550e8400-e29b-41d4-a716-446655440000', }, { allowMultipleAnswer: true, @@ -95,18 +97,21 @@ const listPollsQuery = { label: 'polllll', pollContent: '{"text":"How frequently do you participate in our activities or events, and what influences your level of involvement?","options":[{"name":"Everyday","id":0},{"name":"Once a week","id":1},{"name":"Monthly","id":2},{"name":"Never","id":3}]}', + uuid: '123e4567-e89b-12d3-a456-426614174000', }, { allowMultipleAnswer: false, id: '3', label: 'titek 1', pollContent: '{"text":"sdcfd","options":[{"name":"dfv","id":0},{"name":"sdf","id":1}]}', + uuid: '9b2d9b1e-1c3e-4f5a-8b2d-9b1e1c3e4f5a', }, { allowMultipleAnswer: false, id: '4', label: 'we', pollContent: '{"text":"s","options":[{"name":"dds","id":0},{"name":"ss","id":1}]}', + uuid: 'f47ac10b-58cc-4372-a567-0e02b2c3d479', }, ], }, From efda0888ec9c489b0c883a03c579a77f170d91a2 Mon Sep 17 00:00:00 2001 From: Kurund Jalmi Date: Sun, 16 Feb 2025 21:45:54 +0000 Subject: [PATCH 24/38] remove menu option --- src/config/menu.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/config/menu.ts b/src/config/menu.ts index 1aaa8334ec..36f347a82a 100644 --- a/src/config/menu.ts +++ b/src/config/menu.ts @@ -52,7 +52,7 @@ const menus = (): Menu[] => [ roles: allRoles, }, { - title: 'WhatsApp Polls', + title: 'Group Polls', path: '/group/polls', icon: 'waPolls', type: 'sideDrawer', From eb3461f5857a6f242dccbb26ed215dfdbe155dc7 Mon Sep 17 00:00:00 2001 From: Kurund Jalmi Date: Sun, 16 Feb 2025 22:47:50 +0000 Subject: [PATCH 25/38] update the title and error fixes --- .../WaGroups/WaPolls/WaPollsList/WaPollsList.test.tsx | 10 +++++----- .../WaGroups/WaPolls/WaPollsList/WaPollsList.tsx | 2 +- src/i18n/en/en.json | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/containers/WaGroups/WaPolls/WaPollsList/WaPollsList.test.tsx b/src/containers/WaGroups/WaPolls/WaPollsList/WaPollsList.test.tsx index 710215d226..ab95c6e3b8 100644 --- a/src/containers/WaGroups/WaPolls/WaPollsList/WaPollsList.test.tsx +++ b/src/containers/WaGroups/WaPolls/WaPollsList/WaPollsList.test.tsx @@ -28,7 +28,7 @@ test('it should render the WaPollsList component', async () => { render(wrapper); await waitFor(() => { - expect(screen.getByText('WhatsApp Polls')).toBeInTheDocument(); + expect(screen.getByText('Group Polls')).toBeInTheDocument(); }); await waitFor(() => { @@ -40,7 +40,7 @@ test('it should copy the uuid', async () => { render(wrapper); await waitFor(() => { - expect(screen.getByText('WhatsApp Polls')).toBeInTheDocument(); + expect(screen.getByText('Group Polls')).toBeInTheDocument(); }); fireEvent.click(screen.getAllByTestId('copy-icon')[0]); @@ -54,7 +54,7 @@ test('it should open the view dialog box', async () => { render(wrapper); await waitFor(() => { - expect(screen.getByText('WhatsApp Polls')).toBeInTheDocument(); + expect(screen.getByText('Group Polls')).toBeInTheDocument(); }); fireEvent.click(screen.getAllByTestId('view-icon')[0]); @@ -70,7 +70,7 @@ test('it navigates to create a copy', async () => { render(wrapper); await waitFor(() => { - expect(screen.getByText('WhatsApp Polls')).toBeInTheDocument(); + expect(screen.getByText('Group Polls')).toBeInTheDocument(); }); fireEvent.click(screen.getAllByTestId('duplicate-icon')[0]); @@ -84,7 +84,7 @@ test('it should delete the poll', async () => { render(wrapper); await waitFor(() => { - expect(screen.getByText('WhatsApp Polls')).toBeInTheDocument(); + expect(screen.getByText('Group Polls')).toBeInTheDocument(); }); fireEvent.click(screen.getAllByTestId('delete-icon')[0]); diff --git a/src/containers/WaGroups/WaPolls/WaPollsList/WaPollsList.tsx b/src/containers/WaGroups/WaPolls/WaPollsList/WaPollsList.tsx index 3ffd9f9cec..311be38f40 100644 --- a/src/containers/WaGroups/WaPolls/WaPollsList/WaPollsList.tsx +++ b/src/containers/WaGroups/WaPolls/WaPollsList/WaPollsList.tsx @@ -44,7 +44,7 @@ export const WaPollsList = () => { const [deletePoll, { loading }] = useMutation(DELETE_POLL); const columnNames = [{ name: 'label', label: 'Title' }, { label: 'Content' }, { label: t('Actions') }]; - const title = t('WhatsApp Polls'); + const title = t('Group Polls'); const dialogMessage = t("You won't be able to use this collection again."); const columnStyles = [styles.Label, styles.Content, styles.Actions]; diff --git a/src/i18n/en/en.json b/src/i18n/en/en.json index 4fe02acac7..802d96e95f 100644 --- a/src/i18n/en/en.json +++ b/src/i18n/en/en.json @@ -533,6 +533,6 @@ "Failed": "Failed", "Members": "Members", "Copy Poll": "Copy Poll", - "Group polls": "Group polls", + "Group Polls": "Group Polls", "Name cannot be more than 250 characters.": "Name cannot be more than 250 characters." } From 4e245a08a78b222848d10494e1d4bc4ee51eee94 Mon Sep 17 00:00:00 2001 From: Akansha Sakhre Date: Mon, 17 Feb 2025 11:57:46 +0530 Subject: [PATCH 26/38] resolved comments --- .../Chat/ChatMessages/ChatMessage/ChatMessage.module.css | 4 ++-- .../WaGroups/WaPolls/WaPollOptions/WaPollOptions.tsx | 2 +- src/containers/WaGroups/WaPolls/WaPolls.tsx | 3 +-- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/containers/Chat/ChatMessages/ChatMessage/ChatMessage.module.css b/src/containers/Chat/ChatMessages/ChatMessage/ChatMessage.module.css index 8b62eb7ea4..4f9f0b9bc4 100644 --- a/src/containers/Chat/ChatMessages/ChatMessage/ChatMessage.module.css +++ b/src/containers/Chat/ChatMessages/ChatMessage/ChatMessage.module.css @@ -150,6 +150,7 @@ .Inline { display: flex; } + .SendBy { display: flex; align-items: flex-end; @@ -301,5 +302,4 @@ .NoIcon { margin: 0 1rem; - /* background-color: red !important; */ -} +} \ No newline at end of file diff --git a/src/containers/WaGroups/WaPolls/WaPollOptions/WaPollOptions.tsx b/src/containers/WaGroups/WaPolls/WaPollOptions/WaPollOptions.tsx index 8c2195988a..807a83e33d 100644 --- a/src/containers/WaGroups/WaPolls/WaPollOptions/WaPollOptions.tsx +++ b/src/containers/WaGroups/WaPolls/WaPollOptions/WaPollOptions.tsx @@ -22,7 +22,7 @@ const emojiStyles = { export const WaPollOptions = ({ form: { values, setFieldValue, errors, touched }, isEditing }: WaPollOptionsProps) => { const handleAddOption = () => { const lastId = values?.options[values?.options.length - 1]?.id; - setFieldValue('options', [...values.options, { name: '', id: lastId + 1 }]); + setFieldValue('options', [...values?.options, { name: '', id: lastId + 1 }]); }; const handleInput = (value: any, id: any) => { diff --git a/src/containers/WaGroups/WaPolls/WaPolls.tsx b/src/containers/WaGroups/WaPolls/WaPolls.tsx index 4cedecd873..6f228ce63e 100644 --- a/src/containers/WaGroups/WaPolls/WaPolls.tsx +++ b/src/containers/WaGroups/WaPolls/WaPolls.tsx @@ -40,7 +40,6 @@ export const WaPolls = () => { isEditing = true; } if (location.state === 'copy') { - console.log('copy state'); isCopyState = true; isEditing = false; } @@ -140,7 +139,7 @@ export const WaPolls = () => { languageSupport={false} setStates={setStates} validationSchema={FormSchema} - listItemName="Poll" + listItemName="Group Poll" dialogMessage={dialogMessage} formFields={formFields} redirectionLink={'group/polls'} From 9647e915f1e262532f64ca55a5ee597dc3496636 Mon Sep 17 00:00:00 2001 From: Akansha Sakhre Date: Mon, 17 Feb 2025 12:01:02 +0530 Subject: [PATCH 27/38] deepscan fixes --- .../WaGroups/WaPolls/WaPollOptions/WaPollOptions.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/containers/WaGroups/WaPolls/WaPollOptions/WaPollOptions.tsx b/src/containers/WaGroups/WaPolls/WaPollOptions/WaPollOptions.tsx index 807a83e33d..b33fe310d9 100644 --- a/src/containers/WaGroups/WaPolls/WaPollOptions/WaPollOptions.tsx +++ b/src/containers/WaGroups/WaPolls/WaPollOptions/WaPollOptions.tsx @@ -21,8 +21,8 @@ const emojiStyles = { export const WaPollOptions = ({ form: { values, setFieldValue, errors, touched }, isEditing }: WaPollOptionsProps) => { const handleAddOption = () => { - const lastId = values?.options[values?.options.length - 1]?.id; - setFieldValue('options', [...values?.options, { name: '', id: lastId + 1 }]); + const lastId = values.options[values.options.length - 1]?.id; + setFieldValue('options', [...values.options, { name: '', id: lastId + 1 }]); }; const handleInput = (value: any, id: any) => { From e073c71f8ee506fa18099053511b1dcf4a5486f0 Mon Sep 17 00:00:00 2001 From: Akansha Sakhre Date: Mon, 17 Feb 2025 12:04:31 +0530 Subject: [PATCH 28/38] resolved comments --- src/containers/Chat/ChatMessages/ChatMessage/ChatMessage.tsx | 3 +-- .../Chat/ChatMessages/ChatMessage/PollMessage/PollMessage.tsx | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/containers/Chat/ChatMessages/ChatMessage/ChatMessage.tsx b/src/containers/Chat/ChatMessages/ChatMessage/ChatMessage.tsx index e106630e1a..f0b2061222 100644 --- a/src/containers/Chat/ChatMessages/ChatMessage/ChatMessage.tsx +++ b/src/containers/Chat/ChatMessages/ChatMessage/ChatMessage.tsx @@ -264,7 +264,6 @@ export const ChatMessage = ({ const content: any = interactiveContent ? JSON.parse(interactiveContent) : null; const isInteractiveContentPresent: Boolean = content ? !!Object.entries(content).length : false; - const isPollMessage = type === 'POLL'; const pollContentJson = pollContent ? JSON.parse(pollContent) : {}; const errorClasses = messageErrorStatus ? styles.ErrorContent : ''; @@ -313,7 +312,7 @@ export const ChatMessage = ({ let messageBody: any; if (isInteractiveContentPresent && !isSender) { messageBody = template; - } else if (isPollMessage) { + } else if (type === 'POLL') { messageBody = ; } else { messageBody = ( diff --git a/src/containers/Chat/ChatMessages/ChatMessage/PollMessage/PollMessage.tsx b/src/containers/Chat/ChatMessages/ChatMessage/PollMessage/PollMessage.tsx index b4b5376bc8..7e636219c1 100644 --- a/src/containers/Chat/ChatMessages/ChatMessage/PollMessage/PollMessage.tsx +++ b/src/containers/Chat/ChatMessages/ChatMessage/PollMessage/PollMessage.tsx @@ -20,7 +20,7 @@ export const PollMessage = ({ const maxVotes = Math.max(...pollContentJson.options.map((option: any) => option.votes)); return ( -
+
{text}
{!view &&

Select one or more

}
From f738d153252254a31c70cdf05f9464716f57a848 Mon Sep 17 00:00:00 2001 From: Akansha Sakhre Date: Mon, 17 Feb 2025 12:05:56 +0530 Subject: [PATCH 29/38] merge changes --- src/containers/WaGroups/WaPolls/WaPollOptions/WaPollOptions.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/containers/WaGroups/WaPolls/WaPollOptions/WaPollOptions.tsx b/src/containers/WaGroups/WaPolls/WaPollOptions/WaPollOptions.tsx index 0251fe8ee8..375c8af997 100644 --- a/src/containers/WaGroups/WaPolls/WaPollOptions/WaPollOptions.tsx +++ b/src/containers/WaGroups/WaPolls/WaPollOptions/WaPollOptions.tsx @@ -26,7 +26,7 @@ export const WaPollOptions = ({ setPreviewData, }: WaPollOptionsProps) => { const handleAddOption = () => { - const lastId = values?.options[values?.options.length - 1]?.id; + const lastId = values.options[values.options.length - 1]?.id; const newOptions = [...values.options, { name: '', id: lastId + 1 }]; setFieldValue('options', newOptions); setPreviewData((prev: any) => ({ ...prev, options: newOptions })); From 5687a6ce0b0692570c830ad0d2f1755141756c1f Mon Sep 17 00:00:00 2001 From: Akansha Sakhre Date: Mon, 17 Feb 2025 12:09:02 +0530 Subject: [PATCH 30/38] added documentation links --- src/common/HelpData.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/common/HelpData.tsx b/src/common/HelpData.tsx index a40dbe7456..3b8cdb40e9 100644 --- a/src/common/HelpData.tsx +++ b/src/common/HelpData.tsx @@ -132,5 +132,5 @@ export const templateStatusInfo: HelpDataProps = { export const pollsInfo: HelpDataProps = { heading: 'An overview of all the polls created to date', - link: 'https://glific.github.io/docs/docs/category/flows', + link: 'https://glific.github.io/docs/docs/WhatsApp%20Groups%20Automation/Sending%20Polls%20To%20WhatsApp%20Groups', }; From 95b4a8748f074c814adf500de2c384ed7bd339db Mon Sep 17 00:00:00 2001 From: Akansha Sakhre Date: Mon, 17 Feb 2025 13:21:26 +0530 Subject: [PATCH 31/38] added character limitation --- src/containers/WaGroups/WaPolls/WaPolls.tsx | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/containers/WaGroups/WaPolls/WaPolls.tsx b/src/containers/WaGroups/WaPolls/WaPolls.tsx index 6f228ce63e..67d9cd49bf 100644 --- a/src/containers/WaGroups/WaPolls/WaPolls.tsx +++ b/src/containers/WaGroups/WaPolls/WaPolls.tsx @@ -84,9 +84,13 @@ export const WaPolls = () => { const FormSchema = Yup.object().shape({ label: Yup.string().required(t('Title is required.')).max(50, t('Title is too long.')), - content: Yup.string().required('Content is required.').max(150, 'Content is too long.'), + content: Yup.string().required('Content is required.').max(255, 'Content is too long.'), options: Yup.array() - .of(Yup.object().shape({ name: Yup.string().required('Option is required.') })) + .of( + Yup.object().shape({ + name: Yup.string().required('Option is required.').max(100, 'Please enter not more than 100 characters'), + }) + ) .test('unique-values', 'Values must be unique', (array: any) => { const values = array.map((item: any) => item.name); return new Set(values).size === values.length; From 6c944d6d4c6e79163dbb7e67abc7c19d798dee5b Mon Sep 17 00:00:00 2001 From: Akansha Sakhre Date: Mon, 17 Feb 2025 18:47:13 +0530 Subject: [PATCH 32/38] refactored the code --- src/components/simulator/Simulator.tsx | 2 +- .../ChatMessages/ChatMessage/ChatMessage.tsx | 7 ++-- .../ChatMessage/PollMessage/PollMessage.tsx | 22 ++++++++----- .../WaPolls/WaPollOptions/WaPollOptions.tsx | 32 ++++++++++++++++--- src/containers/WaGroups/WaPolls/WaPolls.tsx | 28 +++++++++++----- src/graphql/queries/WaGroups.ts | 5 +++ 6 files changed, 71 insertions(+), 25 deletions(-) diff --git a/src/components/simulator/Simulator.tsx b/src/components/simulator/Simulator.tsx index 0a664decbe..9a5df1a5cf 100644 --- a/src/components/simulator/Simulator.tsx +++ b/src/components/simulator/Simulator.tsx @@ -344,7 +344,7 @@ const Simulator = ({ if (isInteractiveContentPresent && direction !== 'send') { messageBody = template; } else if (isPollContent) { - messageBody = ; + messageBody = ; } return ( diff --git a/src/containers/Chat/ChatMessages/ChatMessage/ChatMessage.tsx b/src/containers/Chat/ChatMessages/ChatMessage/ChatMessage.tsx index f0b2061222..31e3284c56 100644 --- a/src/containers/Chat/ChatMessages/ChatMessage/ChatMessage.tsx +++ b/src/containers/Chat/ChatMessages/ChatMessage/ChatMessage.tsx @@ -57,7 +57,7 @@ export interface ChatMessageProps { groups?: boolean; status?: string; contact?: any; - pollContent?: any; + poll?: any; showIcon?: boolean; } @@ -84,7 +84,7 @@ export const ChatMessage = ({ groups, status, contact, - pollContent, + poll, showIcon = true, }: ChatMessageProps) => { const [showSaveMessageDialog, setShowSaveMessageDialog] = useState(false); @@ -264,7 +264,6 @@ export const ChatMessage = ({ const content: any = interactiveContent ? JSON.parse(interactiveContent) : null; const isInteractiveContentPresent: Boolean = content ? !!Object.entries(content).length : false; - const pollContentJson = pollContent ? JSON.parse(pollContent) : {}; const errorClasses = messageErrorStatus ? styles.ErrorContent : ''; const stickerClasses = type === 'STICKER' ? styles.StickerBackground : ''; @@ -313,7 +312,7 @@ export const ChatMessage = ({ if (isInteractiveContentPresent && !isSender) { messageBody = template; } else if (type === 'POLL') { - messageBody = ; + messageBody = ; } else { messageBody = ( <> diff --git a/src/containers/Chat/ChatMessages/ChatMessage/PollMessage/PollMessage.tsx b/src/containers/Chat/ChatMessages/ChatMessage/PollMessage/PollMessage.tsx index 7e636219c1..1cb3f0f772 100644 --- a/src/containers/Chat/ChatMessages/ChatMessage/PollMessage/PollMessage.tsx +++ b/src/containers/Chat/ChatMessages/ChatMessage/PollMessage/PollMessage.tsx @@ -4,25 +4,31 @@ import RadioButtonUncheckedIcon from '@mui/icons-material/RadioButtonUnchecked'; import { Fragment } from 'react/jsx-runtime'; interface PollMessageProps { - pollContentJson: any; + pollContentJson?: any; isSender?: boolean; isSimulator?: boolean; view?: boolean; + poll?: any; } -export const PollMessage = ({ - pollContentJson, - isSender = false, - isSimulator = false, - view = false, -}: PollMessageProps) => { +export const PollMessage = ({ isSender = false, isSimulator = false, view = false, poll }: PollMessageProps) => { + const pollContentJson = poll.pollContent + ? typeof poll.pollContent === 'string' + ? JSON.parse(poll.pollContent) + : poll.pollContent + : {}; + const { text, options } = pollContentJson; const maxVotes = Math.max(...pollContentJson.options.map((option: any) => option.votes)); return (
{text}
- {!view &&

Select one or more

} + {!view && ( +

+ {poll?.allowMultipleAnswer ? 'Select one or more' : 'Select one'} +

+ )}
{options.map((option: any, index: number) => { const percentage = maxVotes > 0 ? (option.votes / maxVotes) * 100 : 0; diff --git a/src/containers/WaGroups/WaPolls/WaPollOptions/WaPollOptions.tsx b/src/containers/WaGroups/WaPolls/WaPollOptions/WaPollOptions.tsx index 375c8af997..3da155c4f5 100644 --- a/src/containers/WaGroups/WaPolls/WaPollOptions/WaPollOptions.tsx +++ b/src/containers/WaGroups/WaPolls/WaPollOptions/WaPollOptions.tsx @@ -29,13 +29,25 @@ export const WaPollOptions = ({ const lastId = values.options[values.options.length - 1]?.id; const newOptions = [...values.options, { name: '', id: lastId + 1 }]; setFieldValue('options', newOptions); - setPreviewData((prev: any) => ({ ...prev, options: newOptions })); + setPreviewData((prev: any) => ({ + ...prev, + pollContent: { + ...prev.pollContent, + options: newOptions, + }, + })); }; const handleInput = (value: any, id: any) => { const newOptions = values.options.map((option: any) => (option.id === id ? { ...option, name: value } : option)); setFieldValue('options', newOptions); - setPreviewData((prev: any) => ({ ...prev, options: newOptions })); + setPreviewData((prev: any) => ({ + ...prev, + pollContent: { + ...prev.pollContent, + options: newOptions, + }, + })); }; const handleEmojiAdd = (emoji: any, id: number) => { @@ -44,13 +56,25 @@ export const WaPollOptions = ({ ); setFieldValue('options', newOptions); - setPreviewData((prev: any) => ({ ...prev, options: newOptions })); + setPreviewData((prev: any) => ({ + ...prev, + pollContent: { + ...prev.pollContent, + options: newOptions, + }, + })); }; const handleRemoveClick = (id: any) => { const newOptions = values.options.filter((option: any) => option.id !== id); setFieldValue('options', newOptions); - setPreviewData((prev: any) => ({ ...prev, options: newOptions })); + setPreviewData((prev: any) => ({ + ...prev, + pollContent: { + ...prev.pollContent, + options: newOptions, + }, + })); }; return ( diff --git a/src/containers/WaGroups/WaPolls/WaPolls.tsx b/src/containers/WaGroups/WaPolls/WaPolls.tsx index dd6e6e5c3c..142b7f301c 100644 --- a/src/containers/WaGroups/WaPolls/WaPolls.tsx +++ b/src/containers/WaGroups/WaPolls/WaPolls.tsx @@ -32,11 +32,14 @@ export const WaPolls = () => { ]); const [allowMultiple, setAllowMultiple] = useState(false); const [previewData, setPreviewData] = useState({ - text: '', - options: [ - { id: 0, name: '' }, - { id: 1, name: '' }, - ], + allowMultipleAnswer: false, + pollContent: { + text: '', + options: [ + { id: 0, name: '' }, + { id: 1, name: '' }, + ], + }, }); const { t } = useTranslation(); const params = useParams(); @@ -90,8 +93,8 @@ export const WaPolls = () => { setOptions(options); setPreviewData({ - text, - options, + allowMultipleAnswer, + pollContent: { text, options }, }); }; @@ -128,7 +131,10 @@ export const WaPolls = () => { onChange: (value: any) => { setPreviewData({ ...previewData, - text: value, + pollContent: { + ...previewData.pollContent, + text: value, + }, }); }, }, @@ -148,6 +154,12 @@ export const WaPolls = () => { ), darkCheckbox: true, disabled: isEditing, + handleChange: (value: boolean) => { + setPreviewData({ + ...previewData, + allowMultipleAnswer: value, + }); + }, }, ]; diff --git a/src/graphql/queries/WaGroups.ts b/src/graphql/queries/WaGroups.ts index 5ca75b6111..44b662a741 100644 --- a/src/graphql/queries/WaGroups.ts +++ b/src/graphql/queries/WaGroups.ts @@ -50,6 +50,11 @@ export const GROUP_SEARCH_QUERY = gql` insertedAt } pollContent + poll { + id + pollContent + allowMultipleAnswer + } } } } From 0b1f0218a07584d0b898795429e60aa5c2ee8bc8 Mon Sep 17 00:00:00 2001 From: Akansha Sakhre Date: Mon, 17 Feb 2025 18:56:33 +0530 Subject: [PATCH 33/38] fixed view poll --- .../Chat/ChatMessages/ChatMessage/PollMessage/PollMessage.tsx | 3 +-- .../WaPolls/WaPollsList/ViewPollDialog/ViewPollDialog.tsx | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/containers/Chat/ChatMessages/ChatMessage/PollMessage/PollMessage.tsx b/src/containers/Chat/ChatMessages/ChatMessage/PollMessage/PollMessage.tsx index 1cb3f0f772..b2e8bacc22 100644 --- a/src/containers/Chat/ChatMessages/ChatMessage/PollMessage/PollMessage.tsx +++ b/src/containers/Chat/ChatMessages/ChatMessage/PollMessage/PollMessage.tsx @@ -4,7 +4,6 @@ import RadioButtonUncheckedIcon from '@mui/icons-material/RadioButtonUnchecked'; import { Fragment } from 'react/jsx-runtime'; interface PollMessageProps { - pollContentJson?: any; isSender?: boolean; isSimulator?: boolean; view?: boolean; @@ -12,7 +11,7 @@ interface PollMessageProps { } export const PollMessage = ({ isSender = false, isSimulator = false, view = false, poll }: PollMessageProps) => { - const pollContentJson = poll.pollContent + const pollContentJson = poll?.pollContent ? typeof poll.pollContent === 'string' ? JSON.parse(poll.pollContent) : poll.pollContent diff --git a/src/containers/WaGroups/WaPolls/WaPollsList/ViewPollDialog/ViewPollDialog.tsx b/src/containers/WaGroups/WaPolls/WaPollsList/ViewPollDialog/ViewPollDialog.tsx index 17abc895a0..98e44bb0b5 100644 --- a/src/containers/WaGroups/WaPolls/WaPollsList/ViewPollDialog/ViewPollDialog.tsx +++ b/src/containers/WaGroups/WaPolls/WaPollsList/ViewPollDialog/ViewPollDialog.tsx @@ -25,7 +25,7 @@ export const ViewPoll = ({ id, onClose }: ViewPollProps) => { return ( - + ); }; From 009407f4c758ff0de31324451bf4fa63edeb0785 Mon Sep 17 00:00:00 2001 From: Akansha Sakhre Date: Mon, 17 Feb 2025 18:59:07 +0530 Subject: [PATCH 34/38] deepscan fixes --- .../WaPolls/WaPollsList/ViewPollDialog/ViewPollDialog.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/containers/WaGroups/WaPolls/WaPollsList/ViewPollDialog/ViewPollDialog.tsx b/src/containers/WaGroups/WaPolls/WaPollsList/ViewPollDialog/ViewPollDialog.tsx index 98e44bb0b5..1edb90565d 100644 --- a/src/containers/WaGroups/WaPolls/WaPollsList/ViewPollDialog/ViewPollDialog.tsx +++ b/src/containers/WaGroups/WaPolls/WaPollsList/ViewPollDialog/ViewPollDialog.tsx @@ -17,7 +17,6 @@ export const ViewPoll = ({ id, onClose }: ViewPollProps) => { }); const poll = data?.waPoll?.waPoll; - const pollContent = poll?.pollContent ? JSON.parse(poll?.pollContent) : {}; if (loading) { return ; From 7997c1ddc4cf704b0b7d9c914c8234fe35dab94a Mon Sep 17 00:00:00 2001 From: Akansha Sakhre Date: Wed, 19 Feb 2025 11:16:05 +0530 Subject: [PATCH 35/38] minor fixes --- src/components/simulator/Simulator.tsx | 2 +- .../ChatMessages/ChatMessage/ChatMessage.tsx | 17 +++++++++++- .../ChatMessage/PollMessage/PollMessage.tsx | 14 +++++----- .../WaPolls/WaPollOptions/WaPollOptions.tsx | 16 ++++++------ src/containers/WaGroups/WaPolls/WaPolls.tsx | 26 +++++++++++++------ .../ViewPollDialog/ViewPollDialog.tsx | 9 ++++++- src/graphql/subscriptions/Groups.ts | 16 ++++++++++++ 7 files changed, 73 insertions(+), 27 deletions(-) diff --git a/src/components/simulator/Simulator.tsx b/src/components/simulator/Simulator.tsx index 9a5df1a5cf..faa811ee55 100644 --- a/src/components/simulator/Simulator.tsx +++ b/src/components/simulator/Simulator.tsx @@ -344,7 +344,7 @@ const Simulator = ({ if (isInteractiveContentPresent && direction !== 'send') { messageBody = template; } else if (isPollContent) { - messageBody = ; + messageBody = ; } return ( diff --git a/src/containers/Chat/ChatMessages/ChatMessage/ChatMessage.tsx b/src/containers/Chat/ChatMessages/ChatMessage/ChatMessage.tsx index 31e3284c56..7341efbfc6 100644 --- a/src/containers/Chat/ChatMessages/ChatMessage/ChatMessage.tsx +++ b/src/containers/Chat/ChatMessages/ChatMessage/ChatMessage.tsx @@ -58,6 +58,7 @@ export interface ChatMessageProps { status?: string; contact?: any; poll?: any; + pollContent?: any; showIcon?: boolean; } @@ -85,6 +86,7 @@ export const ChatMessage = ({ status, contact, poll, + pollContent, showIcon = true, }: ChatMessageProps) => { const [showSaveMessageDialog, setShowSaveMessageDialog] = useState(false); @@ -312,7 +314,20 @@ export const ChatMessage = ({ if (isInteractiveContentPresent && !isSender) { messageBody = template; } else if (type === 'POLL') { - messageBody = ; + const pollContentJson = pollContent ? JSON.parse(pollContent) : {}; + + messageBody = ( + <> + {contactName} + + + ); } else { messageBody = ( <> diff --git a/src/containers/Chat/ChatMessages/ChatMessage/PollMessage/PollMessage.tsx b/src/containers/Chat/ChatMessages/ChatMessage/PollMessage/PollMessage.tsx index b2e8bacc22..f279eac61c 100644 --- a/src/containers/Chat/ChatMessages/ChatMessage/PollMessage/PollMessage.tsx +++ b/src/containers/Chat/ChatMessages/ChatMessage/PollMessage/PollMessage.tsx @@ -7,16 +7,14 @@ interface PollMessageProps { isSender?: boolean; isSimulator?: boolean; view?: boolean; - poll?: any; + pollContent: { + poll: any; + pollContentJson: any; + }; } -export const PollMessage = ({ isSender = false, isSimulator = false, view = false, poll }: PollMessageProps) => { - const pollContentJson = poll?.pollContent - ? typeof poll.pollContent === 'string' - ? JSON.parse(poll.pollContent) - : poll.pollContent - : {}; - +export const PollMessage = ({ isSender = false, isSimulator = false, view = false, pollContent }: PollMessageProps) => { + const { poll, pollContentJson } = pollContent; const { text, options } = pollContentJson; const maxVotes = Math.max(...pollContentJson.options.map((option: any) => option.votes)); diff --git a/src/containers/WaGroups/WaPolls/WaPollOptions/WaPollOptions.tsx b/src/containers/WaGroups/WaPolls/WaPollOptions/WaPollOptions.tsx index 3da155c4f5..b5fe9cd279 100644 --- a/src/containers/WaGroups/WaPolls/WaPollOptions/WaPollOptions.tsx +++ b/src/containers/WaGroups/WaPolls/WaPollOptions/WaPollOptions.tsx @@ -31,8 +31,8 @@ export const WaPollOptions = ({ setFieldValue('options', newOptions); setPreviewData((prev: any) => ({ ...prev, - pollContent: { - ...prev.pollContent, + pollContentJson: { + ...prev.pollContentJson, options: newOptions, }, })); @@ -43,8 +43,8 @@ export const WaPollOptions = ({ setFieldValue('options', newOptions); setPreviewData((prev: any) => ({ ...prev, - pollContent: { - ...prev.pollContent, + pollContentJson: { + ...prev.pollContentJson, options: newOptions, }, })); @@ -58,8 +58,8 @@ export const WaPollOptions = ({ setFieldValue('options', newOptions); setPreviewData((prev: any) => ({ ...prev, - pollContent: { - ...prev.pollContent, + pollContentJson: { + ...prev.pollContentJson, options: newOptions, }, })); @@ -70,8 +70,8 @@ export const WaPollOptions = ({ setFieldValue('options', newOptions); setPreviewData((prev: any) => ({ ...prev, - pollContent: { - ...prev.pollContent, + pollContentJson: { + ...prev.pollContentJson, options: newOptions, }, })); diff --git a/src/containers/WaGroups/WaPolls/WaPolls.tsx b/src/containers/WaGroups/WaPolls/WaPolls.tsx index a06f9d0548..539375fe23 100644 --- a/src/containers/WaGroups/WaPolls/WaPolls.tsx +++ b/src/containers/WaGroups/WaPolls/WaPolls.tsx @@ -32,8 +32,8 @@ export const WaPolls = () => { ]); const [allowMultiple, setAllowMultiple] = useState(false); const [previewData, setPreviewData] = useState({ - allowMultipleAnswer: false, - pollContent: { + poll: { allowMultipleAnswer: false }, + pollContentJson: { text: '', options: [ { id: 0, name: '' }, @@ -81,7 +81,15 @@ export const WaPolls = () => { }; const setStates = (states: any) => { const { label, pollContent, allowMultipleAnswer } = states; - const { text, options } = JSON.parse(pollContent); + let text; + let options; + + if (pollContent) { + const pollContentJson = JSON.parse(pollContent); + text = pollContentJson?.text; + options = pollContentJson?.options; + } + let labelValue = label; if (isCopyState) { labelValue = `Copy of ${label}`; @@ -93,8 +101,8 @@ export const WaPolls = () => { setOptions(options); setPreviewData({ - allowMultipleAnswer, - pollContent: { text, options }, + poll: { allowMultipleAnswer }, + pollContentJson: { text, options }, }); }; @@ -135,8 +143,8 @@ export const WaPolls = () => { onChange: (value: any) => { setPreviewData({ ...previewData, - pollContent: { - ...previewData.pollContent, + pollContentJson: { + ...previewData.pollContentJson, text: value, }, }); @@ -161,7 +169,9 @@ export const WaPolls = () => { handleChange: (value: boolean) => { setPreviewData({ ...previewData, - allowMultipleAnswer: value, + poll: { + allowMultipleAnswer: value, + }, }); }, }, diff --git a/src/containers/WaGroups/WaPolls/WaPollsList/ViewPollDialog/ViewPollDialog.tsx b/src/containers/WaGroups/WaPolls/WaPollsList/ViewPollDialog/ViewPollDialog.tsx index 1edb90565d..1ea8b3e1f4 100644 --- a/src/containers/WaGroups/WaPolls/WaPollsList/ViewPollDialog/ViewPollDialog.tsx +++ b/src/containers/WaGroups/WaPolls/WaPollsList/ViewPollDialog/ViewPollDialog.tsx @@ -17,6 +17,7 @@ export const ViewPoll = ({ id, onClose }: ViewPollProps) => { }); const poll = data?.waPoll?.waPoll; + const pollContentJson = poll?.pollContent ? JSON.parse(poll?.pollContent) : {}; if (loading) { return ; @@ -24,7 +25,13 @@ export const ViewPoll = ({ id, onClose }: ViewPollProps) => { return ( - + ); }; diff --git a/src/graphql/subscriptions/Groups.ts b/src/graphql/subscriptions/Groups.ts index 9e52f6fa79..af19cfc956 100644 --- a/src/graphql/subscriptions/Groups.ts +++ b/src/graphql/subscriptions/Groups.ts @@ -35,6 +35,11 @@ export const WA_MESSAGE_RECEIVED_SUBSCRIPTION = gql` insertedAt } pollContent + poll { + id + pollContent + allowMultipleAnswer + } errors } } @@ -75,6 +80,12 @@ export const WA_MESSAGE_SENT_SUBSCRIPTION = gql` insertedAt } status + pollContent + poll { + id + pollContent + allowMultipleAnswer + } } } `; @@ -125,6 +136,11 @@ export const UPDATE_WA_MESSAGE_STATUS = gql` id messageNumber pollContent + poll { + id + pollContent + allowMultipleAnswer + } errors waGroup { id From c247dd1ecfc7a5418722f69c5e616eddec4440b9 Mon Sep 17 00:00:00 2001 From: Akansha Sakhre Date: Wed, 19 Feb 2025 11:56:34 +0530 Subject: [PATCH 36/38] added test cases --- .../WaGroups/WaPolls/WaPolls.test.tsx | 22 ++++++++++++++++ .../WaPolls/WaPollsList/WaPollsList.tsx | 6 +---- src/mocks/Groups.tsx | 26 ++++++++++++++----- src/mocks/WaPolls.tsx | 8 +++++- 4 files changed, 50 insertions(+), 12 deletions(-) diff --git a/src/containers/WaGroups/WaPolls/WaPolls.test.tsx b/src/containers/WaGroups/WaPolls/WaPolls.test.tsx index c57530fd60..61bce8e5c9 100644 --- a/src/containers/WaGroups/WaPolls/WaPolls.test.tsx +++ b/src/containers/WaGroups/WaPolls/WaPolls.test.tsx @@ -14,6 +14,23 @@ const mockUseLocationValue: any = { state: null, }; +vi.mock('../../../components/UI/EmojiPicker/EmojiPicker', () => ({ + default: ({ onEmojiSelect }: { onEmojiSelect: (emoji: any) => void }) => ( +
+ +
+ ), +})); + vi.mock('react-router-dom', async () => ({ ...((await vi.importActual('react-router-dom')) as {}), useLocation: () => { @@ -52,6 +69,11 @@ describe('Create', () => { fireEvent.change(screen.getByPlaceholderText('Option 1'), { target: { value: 'Option 1' } }); fireEvent.change(screen.getByPlaceholderText('Option 2'), { target: { value: 'Option 2' } }); + fireEvent.click(screen.getAllByTestId('emoji-picker')[0]); + + expect(screen.getByTestId('emoji-container')).toBeInTheDocument(); + fireEvent.click(screen.getByTestId('mock-emoji-picker')); + fireEvent.click(screen.getByTestId('add-btn')); fireEvent.change(screen.getByPlaceholderText('Option 3'), { target: { value: 'Option 3' } }); diff --git a/src/containers/WaGroups/WaPolls/WaPollsList/WaPollsList.tsx b/src/containers/WaGroups/WaPolls/WaPollsList/WaPollsList.tsx index 311be38f40..b140963a3f 100644 --- a/src/containers/WaGroups/WaPolls/WaPollsList/WaPollsList.tsx +++ b/src/containers/WaGroups/WaPolls/WaPollsList/WaPollsList.tsx @@ -27,11 +27,7 @@ const queries = { const getLabel = (label: string) =>
{label}
; const getContent = (content: string) => { - return ( -
- {content ? (content.length < 100 ? content : `${content.slice(0, 100)}...`) : ''} -
- ); + return
{content.length < 100 ? content : `${content.slice(0, 100)}...`}
; }; export const WaPollsList = () => { const [deleteWaPollId, setDeleteWaPollId] = useState(null); diff --git a/src/mocks/Groups.tsx b/src/mocks/Groups.tsx index 945210a315..2cd98e7398 100644 --- a/src/mocks/Groups.tsx +++ b/src/mocks/Groups.tsx @@ -69,9 +69,16 @@ export const waGroup = { media: null, messageNumber: 4, status: 'sent', - type: 'TEXT', - poll: null, - pollContent: '{}', + type: 'POLL', + poll: { + __typename: 'WaPoll', + allowMultipleAnswer: false, + id: '4', + pollContent: + '{"text": "this is a poll", "options": [{ "votes": 1, "name": "option 1", "id": 0 },{ "votes": 1, "name": "option 2", "id": 1 },{ "votes": 0, "name": "okay option 4", "id": 2 }]}', + }, + pollContent: + '{"text": "this is a poll", "options": [{ "votes": 1, "name": "option 1", "id": 0 },{ "votes": 1, "name": "option 2", "id": 1 },{ "votes": 0, "name": "okay option 4", "id": 2 }]}', }, { __typename: 'WaMessage', @@ -130,9 +137,16 @@ const sampleMessage = { media: null, messageNumber: 1, status: 'received', - type: 'TEXT', - poll: null, - pollContent: '{}', + type: 'POLL', + poll: { + __typename: 'WaPoll', + allowMultipleAnswer: false, + id: '4', + pollContent: + '{"text": "this is a poll", "options": [{ "votes": 1, "name": "option 1", "id": 0 },{ "votes": 1, "name": "option 2", "id": 1 },{ "votes": 0, "name": "okay option 4", "id": 2 }]}', + }, + pollContent: + '{"text": "this is a poll", "options": [{ "votes": 1, "name": "option 1", "id": 0 },{ "votes": 1, "name": "option 2", "id": 1 },{ "votes": 0, "name": "okay option 4", "id": 2 }]}', }; const sampleSearchQueryResult = [ diff --git a/src/mocks/WaPolls.tsx b/src/mocks/WaPolls.tsx index 088b75e870..b34ef6ec26 100644 --- a/src/mocks/WaPolls.tsx +++ b/src/mocks/WaPolls.tsx @@ -5,6 +5,13 @@ import { GET_POLL, GET_POLLS, GET_POLLS_COUNT } from 'graphql/queries/WaPolls'; const createPoll = { request: { query: CREATE_POLL, + variables: { + input: { + label: 'Poll Title', + poll_content: '{"options":[{"id":0,"name":"Option 1😃"},{"name":"Option 3","id":2}],"text":"Poll Content"}', + allow_multiple_answer: true, + }, + }, }, result: { data: { @@ -16,7 +23,6 @@ const createPoll = { }, }, }, - variableMatcher: () => true, }; const getPoll = { From aa0fb4478ccd5b982cb7d7bcc35cd2d1edbb170c Mon Sep 17 00:00:00 2001 From: Akansha Sakhre Date: Wed, 19 Feb 2025 23:07:03 +0530 Subject: [PATCH 37/38] removed new tag from assistants --- src/config/menu.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/config/menu.ts b/src/config/menu.ts index 791c81c6fe..9f757f1074 100644 --- a/src/config/menu.ts +++ b/src/config/menu.ts @@ -171,7 +171,6 @@ const menus = (): Menu[] => [ icon: 'assistant', type: 'sideDrawer', roles: allRoles, - new: true, }, { title: 'Manage', From 0eb9fc25b3d235fcbe773a6353afca616a16303f Mon Sep 17 00:00:00 2001 From: Akansha Sakhre Date: Thu, 20 Feb 2025 08:10:31 +0530 Subject: [PATCH 38/38] updated the version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index bf8205f0be..16a471bbb9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "glific-frontend", - "version": "6.2.6", + "version": "6.3.0", "private": true, "type": "module", "dependencies": {