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 && (
+
+ Add Option
+
+ )}
+
+
+ );
+};
+
+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 = (
} />
} />
+ } />
+ } />
+ } />
+
} />
);