@@ -287,10 +291,7 @@ export default function DateTimePicker({
isMenuOpen={false}
>
{/*
setOpen(true)} placeholder={selectedDate} disabled/> */}
-
+
)}
diff --git a/packages/twenty-front/src/modules/users/graphql/queries/saveSmsResponse.ts b/packages/twenty-front/src/modules/users/graphql/queries/saveSmsResponse.ts
new file mode 100644
index 000000000000..a7c0a9f9bd31
--- /dev/null
+++ b/packages/twenty-front/src/modules/users/graphql/queries/saveSmsResponse.ts
@@ -0,0 +1,151 @@
+import { gql } from '@apollo/client';
+export const SAVE_SMS_RESPONSE = gql`
+ mutation CreateOneSms($input: SmsCreateInput!) {
+ createSms(data: $input) {
+ id
+ dateCreated
+ campaignName
+ sid
+ numSegments
+ dateupdated
+ createdAt
+ uri
+ status
+ favorites {
+ edges {
+ node {
+ __typename
+ id
+ campaignList {
+ __typename
+ id
+ }
+ specialty {
+ __typename
+ id
+ }
+ subspecialty {
+ __typename
+ id
+ }
+ subspecialtyId
+ opportunityId
+ company {
+ __typename
+ id
+ }
+ updatedAt
+ createdAt
+ messageResponseId
+ workspaceMember {
+ __typename
+ id
+ }
+ person {
+ __typename
+ id
+ }
+ sms {
+ __typename
+ id
+ }
+ workspaceMemberId
+ abcId
+ personId
+ abc {
+ __typename
+ id
+ }
+ id
+ position
+ opportunity {
+ __typename
+ id
+ }
+ companyId
+ specialtyId
+ campaignListId
+ messageResponse {
+ __typename
+ id
+ }
+ smsId
+ }
+ __typename
+ }
+ __typename
+ }
+ position
+ activityTargets {
+ edges {
+ node {
+ __typename
+ id
+ abcId
+ person {
+ __typename
+ id
+ }
+ id
+ createdAt
+ personId
+ campaignList {
+ __typename
+ id
+ }
+ subspecialty {
+ __typename
+ id
+ }
+ activity {
+ __typename
+ id
+ }
+ specialty {
+ __typename
+ id
+ }
+ messageResponse {
+ __typename
+ id
+ }
+ company {
+ __typename
+ id
+ }
+ opportunityId
+ specialtyId
+ updatedAt
+ subspecialtyId
+ abc {
+ __typename
+ id
+ }
+ activityId
+ opportunity {
+ __typename
+ id
+ }
+ smsId
+ companyId
+ messageResponseId
+ sms {
+ __typename
+ id
+ }
+ campaignListId
+ }
+ __typename
+ }
+ __typename
+ }
+ id
+ direction
+ body
+ to
+ updatedAt
+ from
+ __typename
+ }
+ }
+`;
diff --git a/packages/twenty-front/src/pages/campaigns/CampaignContext.tsx b/packages/twenty-front/src/pages/campaigns/CampaignContext.tsx
new file mode 100644
index 000000000000..20984ce1d5f7
--- /dev/null
+++ b/packages/twenty-front/src/pages/campaigns/CampaignContext.tsx
@@ -0,0 +1,36 @@
+import { createContext, useState } from 'react';
+
+import { App } from '~/App';
+export type CampaignContextProps = {
+ currentStep: number;
+ setCurrentStep: {};
+
+ campaignData: {};
+
+ setCampaignData: {};
+};
+
+export const CampaignMultiStepContext =
+ createContext
(null);
+
+const CampaignContext = () => {
+ const [currentStep, setCurrentStep] = useState(0);
+ const [campaignData, setCampaignData] = useState({});
+
+ return (
+
+ );
+};
+
+export default CampaignContext;
diff --git a/packages/twenty-front/src/pages/campaigns/CampaignDate.tsx b/packages/twenty-front/src/pages/campaigns/CampaignDate.tsx
new file mode 100644
index 000000000000..260ba68b6030
--- /dev/null
+++ b/packages/twenty-front/src/pages/campaigns/CampaignDate.tsx
@@ -0,0 +1,118 @@
+/* eslint-disable no-restricted-imports */
+import { useState } from 'react';
+import styled from '@emotion/styled';
+import { Section } from '@react-email/components';
+import { IconArrowLeft } from '@tabler/icons-react';
+import { IconArrowRight } from '@tabler/icons-react';
+import { Button } from 'tsup.ui.index';
+
+import DateTimePicker from '@/ui/input/components/internal/date/components/DateTimePicker';
+import { useCampaign } from '~/pages/campaigns/CampaignUseContext';
+
+const StyledCard = styled.div`
+ border: 1px solid ${({ theme }) => theme.border.color.medium};
+ border-radius: ${({ theme }) => theme.border.radius.sm};
+ color: ${({ theme }) => theme.font.color.secondary};
+ box-shadow: ${({ theme }) => theme.boxShadow.strong};
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ background: ${({ theme }) => theme.background.primary};
+ height: 90%;
+ width: 70%;
+ margin: auto;
+ align-items: center;
+`;
+
+const StyledInputCard = styled.div`
+ color: ${({ theme }) => theme.font.color.secondary};
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ height: 70%;
+ justify-content: space-evenly;
+ width: 70%;
+ align-items: center;
+`;
+
+const StyledTitleCard = styled.div`
+ align-items: center;
+ color: ${({ theme }) => theme.font.color.secondary};
+ display: flex;
+ flex-direction: column;
+ height: 10%;
+ width: 70%;
+ justify-content: center;
+`;
+
+const StyledButton = styled.span`
+ display: flex;
+ justify-content: space-between;
+ width: 100%;
+`;
+const StyledLabel = styled.span`
+ color: ${({ theme }) => theme.font.color.light};
+ font-size: ${({ theme }) => theme.font.size.xs};
+ font-weight: ${({ theme }) => theme.font.weight.semiBold};
+ margin-bottom: ${({ theme }) => theme.spacing(1)};
+ text-transform: uppercase;
+`;
+
+const StyledTitle = styled.h3`
+ color: ${({ theme }) => theme.font.color.secondary};
+ font-weight: ${({ theme }) => theme.font.weight.medium};
+ font-size: ${({ theme }) => theme.font.size.md};
+`;
+
+export const CampaignDate = () => {
+ const { setCurrentStep, currentStep } = useCampaign();
+
+ const [startDate, setStartDate] = useState(new Date());
+ const [endDate, setEndDate] = useState(new Date());
+
+ return (
+ <>
+
+
+
+ The campaign date: where strategy meets opportunity
+
+
+
+
+ Start Date
+ setStartDate(startDate)}
+ minDate={new Date()}
+ showTimeInput
+ />
+
+
+ End Date
+ setEndDate(endDate)}
+ minDate={startDate}
+ showTimeInput
+ />
+
+
+
+
+
+
+ >
+ );
+};
diff --git a/packages/twenty-front/src/pages/campaigns/CampaignDetails.tsx b/packages/twenty-front/src/pages/campaigns/CampaignDetails.tsx
new file mode 100644
index 000000000000..e1fa35e36f23
--- /dev/null
+++ b/packages/twenty-front/src/pages/campaigns/CampaignDetails.tsx
@@ -0,0 +1,126 @@
+/* eslint-disable no-restricted-imports */
+import styled from '@emotion/styled';
+import { IconArrowLeft } from '@tabler/icons-react';
+import { IconArrowRight } from '@tabler/icons-react';
+import { Button, TextArea, TextInput } from 'tsup.ui.index';
+
+import { useCampaign } from '~/pages/campaigns/CampaignUseContext';
+
+const StyledCard = styled.div`
+ border: 1px solid ${({ theme }) => theme.border.color.medium};
+ border-radius: ${({ theme }) => theme.border.radius.sm};
+ color: ${({ theme }) => theme.font.color.secondary};
+ box-shadow: ${({ theme }) => theme.boxShadow.strong};
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ background: ${({ theme }) => theme.background.primary};
+ height: 90%;
+ width: 70%;
+ margin: auto;
+ align-items: center;
+`;
+
+const StyledInputCard = styled.div`
+ color: ${({ theme }) => theme.font.color.secondary};
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ height: 50%;
+ justify-content: space-evenly;
+ width: 70%;
+ align-items: center;
+`;
+
+const StyledTitleCard = styled.div`
+ align-items: center;
+ color: ${({ theme }) => theme.font.color.secondary};
+ display: flex;
+ flex-direction: column;
+ height: 10%;
+ width: 70%;
+ justify-content: flex-start;
+`;
+
+const StyledAreaLabel = styled.span`
+ align-content: flex-start;
+ display: flex;
+ flex-direction: column;
+ margin-bottom: 2%;
+ width: 100%;
+`;
+const StyledButton = styled.span`
+ display: flex;
+ justify-content: space-between;
+ width: 100%;
+`;
+const StyledLabel = styled.span`
+ color: ${({ theme }) => theme.font.color.light};
+ font-size: ${({ theme }) => theme.font.size.xs};
+ font-weight: ${({ theme }) => theme.font.weight.semiBold};
+ margin-bottom: ${({ theme }) => theme.spacing(1)};
+ text-transform: uppercase;
+`;
+
+const StyledTitle = styled.h3`
+ color: ${({ theme }) => theme.font.color.secondary};
+ font-weight: ${({ theme }) => theme.font.weight.medium};
+ font-size: ${({ theme }) => theme.font.size.md};
+`;
+
+export const CampaignDetails = () => {
+ const { setCurrentStep, currentStep } = useCampaign();
+ const handleCampaignChange = (_event: Event | undefined): void => {
+ throw new Error('Function not implemented.');
+ };
+
+ return (
+ <>
+
+
+
+ Get started on your campaign journey with our comprehensive
+ solution. Create, launch, and optimize campaigns with ease
+
+
+
+ handleCampaignChange(event)}
+ name="campaignName"
+ required
+ fullWidth
+ />
+
+ Description
+
+
+
+ setCurrentStep(currentStep + 1)}
+ />
+
+
+
+ >
+ );
+};
diff --git a/packages/twenty-front/src/pages/campaigns/CampaignUseContext.tsx b/packages/twenty-front/src/pages/campaigns/CampaignUseContext.tsx
new file mode 100644
index 000000000000..931f9830aabf
--- /dev/null
+++ b/packages/twenty-front/src/pages/campaigns/CampaignUseContext.tsx
@@ -0,0 +1,14 @@
+import { useContext } from 'react';
+
+import {
+ CampaignContextProps,
+ CampaignMultiStepContext,
+} from '~/pages/campaigns/CampaignContext';
+
+export const useCampaign = (): CampaignContextProps => {
+ const context = useContext(CampaignMultiStepContext);
+ if (!context) {
+ throw new Error('useCampaign must be used within a CampaignProvider');
+ }
+ return context;
+};
diff --git a/packages/twenty-front/src/pages/campaigns/Campaigns.tsx b/packages/twenty-front/src/pages/campaigns/Campaigns.tsx
index 4bb0c940f853..0787ac9f9bfc 100644
--- a/packages/twenty-front/src/pages/campaigns/Campaigns.tsx
+++ b/packages/twenty-front/src/pages/campaigns/Campaigns.tsx
@@ -1,361 +1,92 @@
-/* eslint-disable no-restricted-globals */
-/* eslint-disable @nx/workspace-styled-components-prefixed-with-styled */
-import { useState } from 'react';
-import { useMutation, useQuery } from '@apollo/client';
import styled from '@emotion/styled';
-import { v4 as uuidv4 } from 'uuid';
-import {
- Checkbox,
- CheckboxVariant,
- CheckboxSize,
- CheckboxShape,
- Select,
- TextInput,
-} from 'tsup.ui.index';
-import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer';
-import { IconMail } from '@/ui/display/icon';
-import { H1Title } from '@/ui/display/typography/components/H1Title';
-import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
-import { Button } from '@/ui/input/button/components/Button';
-import DateTimePicker from '@/ui/input/components/internal/date/components/DateTimePicker';
-import { Radio } from '@/ui/input/components/Radio';
-import { SubMenuTopBarContainer } from '@/ui/layout/page/SubMenuTopBarContainer';
-import { Section } from '@/ui/layout/section/components/Section';
-import { ADD_CAMPAIGN } from '@/users/graphql/queries/addCampaign';
-import { GET_SPECIALTY } from '@/users/graphql/queries/getSpecialtyDetails';
-const StyledH1Title = styled(H1Title)`
- margin-bottom: 0;
-`;
-
-const StyledSection = styled(Section)`
- align-items: center;
- display: flex;
- justify-content: space-around;
- margin-bottom: 16px;
- margin-left: 0;
-`;
-
-const SaveButtonContainer = styled.div`
+import { IconTargetArrow } from '@/ui/display/icon';
+import { Modal } from '@/ui/layout/modal/components/Modal';
+import { PageBody } from '@/ui/layout/page/PageBody';
+import { PageContainer } from '@/ui/layout/page/PageContainer';
+import { PageHeader } from '@/ui/layout/page/PageHeader';
+import { StepBar } from '@/ui/navigation/step-bar/components/StepBar';
+import { MOBILE_VIEWPORT } from '@/ui/theme/constants/theme';
+import { CampaignDate } from '~/pages/campaigns/CampaignDate';
+import { CampaignDetails } from '~/pages/campaigns/CampaignDetails';
+import { useCampaign } from '~/pages/campaigns/CampaignUseContext';
+import { Lead } from '~/pages/campaigns/Lead';
+import { MessagingChannel } from '~/pages/campaigns/MessagingChannel';
+import { PreviewPage } from '~/pages/campaigns/PreviewPage';
+import { Specialty } from '~/pages/campaigns/Specialty';
+
+const StyledBoardContainer = styled.div`
display: flex;
- justify-content: flex-end;
- width: auto;
+ height: 100%;
+ width: 100%;
+ flex-direction: column;
+ justify-self: center;
`;
-const StyledLabel = styled.span`
- color: ${({ theme }) => theme.font.color.light};
- font-size: ${({ theme }) => theme.font.size.xs};
- font-weight: ${({ theme }) => theme.font.weight.semiBold};
- margin-bottom: ${({ theme }) => theme.spacing(1)};
- text-transform: uppercase;
+const StyledHeader = styled(Modal.Header)`
+ background-color: ${({ theme }) => theme.background.secondary};
+ border-bottom: 1px solid ${({ theme }) => theme.border.color.medium};
+ height: 60px;
+ padding: 0px;
+ padding-left: ${({ theme }) => theme.spacing(30)};
+ padding-right: ${({ theme }) => theme.spacing(30)};
+ @media (max-width: ${MOBILE_VIEWPORT}px) {
+ padding-left: ${({ theme }) => theme.spacing(4)};
+ padding-right: ${({ theme }) => theme.spacing(4)};
+ }
`;
-const StyledCheckboxLabel = styled.label`
+const StyledCard = styled.div`
+ border: 1px solid ${({ theme }) => theme.border.color.medium};
+ border-radius: ${({ theme }) => theme.border.radius.sm};
+ color: ${({ theme }) => theme.font.color.secondary};
+ box-shadow: ${({ theme }) => theme.boxShadow.strong};
display: flex;
- align-items: center;
+ justify-content: center;
+ background: ${({ theme }) => theme.background.noisy};
+ height: 100%;
`;
-
export const Campaigns = () => {
- let Specialty: any = [];
-
- const SpecialtyTypes: any = {};
-
- const [campaignName, setCampaignName] = useState('');
- const [description, setDescription] = useState('');
- const [specialty, setSpecialty] = useState('');
- const [subSpecialty, setSubSpecialty] = useState('');
- const [startDate, setStartDate] = useState(new Date());
- const [endDate, setEndDate] = useState(new Date());
- const [selectedMessaging, setSelectedMessaging] = useState(new Set());
- const { loading: queryLoading, data: queryData } = useQuery(GET_SPECIALTY);
-
- const [showSmsInput, setShowSmsInput] = useState(false);
- const [smsMessage, setSmsMessage] = useState('');
-
- if (!queryLoading) {
- const specialtyTypes = queryData?.subspecialties.edges.map(
- (edge: { node: { specialtyType: { name: any } } }) =>
- edge?.node?.specialtyType?.name,
- );
- const uniqueSpecialtyTypes = Array.from(new Set(specialtyTypes));
- Specialty = uniqueSpecialtyTypes.map((specialtyType) => ({
- value: specialtyType,
- label: specialtyType,
- }));
-
- queryData?.subspecialties.edges.forEach(
- (edge: { node: { specialtyType: { name: any }; name: any } }) => {
- const specialtyType = edge.node.specialtyType.name;
- const subSpecialty = edge.node.name;
-
- // If the specialty type is already a key in the dictionary, push the sub-specialty to its array
- if (SpecialtyTypes[specialtyType]) {
- SpecialtyTypes[specialtyType].push({
- value: subSpecialty,
- label: subSpecialty,
- });
- } else {
- // If the specialty type is not yet a key, create a new array with the sub-specialty as its first element
- SpecialtyTypes[specialtyType] = [];
- SpecialtyTypes[specialtyType].push({
- value: subSpecialty,
- label: subSpecialty,
- });
- }
- },
- );
- }
-
- const [addCampaigns, { loading, error }] = useMutation(ADD_CAMPAIGN);
- const { enqueueSnackBar } = useSnackBar();
-
- const handleCampaignChange = (e: any) => {
- setCampaignName(e.target.value);
- };
-
- const handleDescriptionChange = (e: any) => {
- setDescription(e.target.value);
- };
-
- const handleSpecialtySelectChange = (selectedValue: any) => {
- setSpecialty(selectedValue);
- };
-
- const handleSubSpecialtySelectChange = (selectedValue: any) => {
- setSubSpecialty(selectedValue);
- };
-
- const onSelectCheckBoxChange = (event: any, checkedOption: string) => {
- const { checked } = event.target;
- if (checked) {
- setSelectedMessaging(selectedMessaging.add(checkedOption))
- if (checkedOption === 'SMS') {
- setShowSmsInput(true);
- }
- } else {
- selectedMessaging.delete(checkedOption)
- setSelectedMessaging(selectedMessaging)
- if (checkedOption === 'SMS') {
- setShowSmsInput(false);
- }
+ const { currentStep } = useCampaign();
+
+ const showCampaignStep = (step: number) => {
+ switch (step) {
+ case 2:
+ return ;
+ case 3:
+ return ;
+ case 4:
+ return ;
+ case 5:
+ return ;
+ case 6:
+ return ;
+ default:
+ return ;
}
};
- const resetCampaignData = () => {
- setCampaignName('');
- setDescription('');
- setStartDate(new Date());
- setSelectedMessaging(new Set());
- setSpecialty('');
- setSubSpecialty('');
- };
- const handleSave = async () => {
- try {
- console.log('Start Date', startDate);
-
- console.log('End Date', endDate);
- const variables = {
- input: {
- id: uuidv4(),
- campaignName: campaignName,
- specialtyType: specialty,
- description: description,
- subSpecialtyType: subSpecialty,
- startDate: startDate,
- endDate: endDate,
- messagingMedia: Array.from(selectedMessaging).join(' '),
- },
- };
- console.log('Variables', variables);
-
- const { data } = await addCampaigns({
- variables: variables,
- });
- enqueueSnackBar('Campaign added successfully', {
- variant: 'success',
- });
-
- const myHeaders = new Headers();
- myHeaders.append("Content-Type", "application/x-www-form-urlencoded");
- myHeaders.append("Authorization", "Basic QUM1ZGQxNjZiMDhjN2M3MGQ0YzZjNDM1N2I2OTFkODMwZjo0NDdmZmU0OWU1N2VhZmM4ZmIxNjAxZDNiOGEwMDVjYg==");
-
- const urlencoded = new URLSearchParams();
- urlencoded.append("To", " 919108223419");
- urlencoded.append("From", " 16506035403");
- urlencoded.append("Body", smsMessage)
-
- const requestOptions : Object = {
- method: "POST",
- headers: myHeaders,
- body: urlencoded,
- redirect: "follow"
- };
- const response: any = await fetch("https://api.twilio.com/2010-04-01/Accounts/AC5dd166b08c7c70d4c6c4357b691d830f/Messages.json", requestOptions)
- .catch((error) => console.error(error));
- const respData=await response.json()
-
- if(respData.body)
- {
- enqueueSnackBar('SMS sent successfully', {
- variant: 'success',
- });
- }
-
-
- resetCampaignData();
- } catch (errors: any) {
- console.error('Error updating user:', error);
- enqueueSnackBar(errors.message + 'Error while Submitting Campaign', {
- variant: 'error',
- });
- }
- };
return (
-
-
-
-
- handleCampaignChange(event)}
- placeholder="Campaign Name"
- name="campaignName"
- required
- fullWidth
- />
-
-
- handleDescriptionChange(event)}
- placeholder="Description about campaign"
- name="description"
- required
- fullWidth
- />
-
-
- {specialty && (
-
- )}
-
- Start Date
- setStartDate(startDate)}
- minDate={new Date()}
- />
-
-
- End Date
- setEndDate(endDate)}
- minDate={startDate}
- />
-
-
- Messaging
-
-
- onSelectCheckBoxChange(event, 'SMS')}
- variant={CheckboxVariant.Primary}
- size={CheckboxSize.Small}
- shape={CheckboxShape.Squared}
- />
- SMS
-
-
-
- onSelectCheckBoxChange(event, 'Whatsapp')}
- variant={CheckboxVariant.Primary}
- size={CheckboxSize.Small}
- shape={CheckboxShape.Squared}
- />
- WhastApp
-
-
-
- onSelectCheckBoxChange(event, 'GBM')}
- variant={CheckboxVariant.Primary}
- size={CheckboxSize.Small}
- shape={CheckboxShape.Squared}
- />
- GBM
-
-
-
- onSelectCheckBoxChange(event, 'Call')}
- variant={CheckboxVariant.Primary}
- size={CheckboxSize.Small}
- shape={CheckboxShape.Squared}
- />
- Call
-
-
-
-
- {showSmsInput && (
-
- SMS Message Body
- setSmsMessage(value)}
- placeholder="Enter SMS message body"
- fullWidth
- />
-
- )}
-
-
-
-
- handleSave()}
- />
-
-
-
+ <>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {showCampaignStep(currentStep + 1)}
+
+
+
+ >
);
};
diff --git a/packages/twenty-front/src/pages/campaigns/Lead.tsx b/packages/twenty-front/src/pages/campaigns/Lead.tsx
new file mode 100644
index 000000000000..6e7386bb8964
--- /dev/null
+++ b/packages/twenty-front/src/pages/campaigns/Lead.tsx
@@ -0,0 +1,115 @@
+/* eslint-disable prefer-arrow/prefer-arrow-functions */
+/* eslint-disable no-restricted-imports */
+import { ChangeEvent } from 'react';
+import styled from '@emotion/styled';
+import { IconArrowLeft } from '@tabler/icons-react';
+import { IconArrowRight } from '@tabler/icons-react';
+
+import { Button } from '@/ui/input/button/components/Button';
+import { Section } from '@/ui/layout/section/components/Section';
+import { useCampaign } from '~/pages/campaigns/CampaignUseContext';
+const StyledCard = styled.div`
+ border: 1px solid ${({ theme }) => theme.border.color.medium};
+ border-radius: ${({ theme }) => theme.border.radius.sm};
+ color: ${({ theme }) => theme.font.color.secondary};
+ box-shadow: ${({ theme }) => theme.boxShadow.strong};
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ background: ${({ theme }) => theme.background.primary};
+ height: 90%;
+ width: 70%;
+ margin: auto;
+ align-items: center;
+`;
+
+const StyledInputCard = styled.div`
+ align-items: center;
+ color: ${({ theme }) => theme.font.color.secondary};
+ display: flex;
+ flex-direction: column;
+ height: 50%;
+ justify-content: space-evenly;
+ width: 70%;
+`;
+
+const StyledTitleCard = styled.div`
+ align-items: center;
+ color: ${({ theme }) => theme.font.color.secondary};
+ display: flex;
+ flex-direction: column;
+ height: 10%;
+ width: 70%;
+ justify-content: flex-start;
+`;
+
+const StyledButton = styled.span`
+ display: flex;
+ justify-content: space-between;
+ width: 100%;
+`;
+const StyledLabel = styled.span`
+ color: ${({ theme }) => theme.font.color.light};
+ font-size: ${({ theme }) => theme.font.size.xs};
+ font-weight: ${({ theme }) => theme.font.weight.semiBold};
+ margin-bottom: ${({ theme }) => theme.spacing(1)};
+ text-transform: uppercase;
+ display: flex;
+`;
+
+const StyledCheckboxLabel = styled.span`
+ margin-left: ${({ theme }) => theme.spacing(2)};
+`;
+
+const StyledTitle = styled.h3`
+ color: ${({ theme }) => theme.font.color.secondary};
+ font-weight: ${({ theme }) => theme.font.weight.medium};
+ font-size: ${({ theme }) => theme.font.size.md};
+`;
+
+const StyledSection = styled(Section)`
+ align-items: flex-start;
+ display: flex;
+ justify-content: space-between;
+ margin-bottom: 16px;
+ margin-left: 0;
+`;
+export const Lead = () => {
+ const { setCurrentStep, currentStep } = useCampaign();
+
+ const onSelectCheckBoxChange = (
+ _event: ChangeEvent,
+ arg1: string,
+ ): void => {
+ throw new Error('Function not implemented.');
+ };
+
+ return (
+ <>
+
+
+
+
+
+ Lead Extraction
+
+ setCurrentStep(currentStep - 1)}
+ />
+ setCurrentStep(currentStep + 1)}
+ />
+
+
+
+ >
+ );
+};
diff --git a/packages/twenty-front/src/pages/campaigns/MessagingChannel.tsx b/packages/twenty-front/src/pages/campaigns/MessagingChannel.tsx
new file mode 100644
index 000000000000..e36555ec5f73
--- /dev/null
+++ b/packages/twenty-front/src/pages/campaigns/MessagingChannel.tsx
@@ -0,0 +1,175 @@
+/* eslint-disable prefer-arrow/prefer-arrow-functions */
+/* eslint-disable no-restricted-imports */
+import { ChangeEvent } from 'react';
+import styled from '@emotion/styled';
+import { IconArrowLeft } from '@tabler/icons-react';
+import { IconArrowRight } from '@tabler/icons-react';
+import {
+ Checkbox,
+ CheckboxShape,
+ CheckboxSize,
+ CheckboxVariant,
+} from 'tsup.ui.index';
+
+import { Button } from '@/ui/input/button/components/Button';
+import { Section } from '@/ui/layout/section/components/Section';
+import { useCampaign } from '~/pages/campaigns/CampaignUseContext';
+const StyledCard = styled.div`
+ border: 1px solid ${({ theme }) => theme.border.color.medium};
+ border-radius: ${({ theme }) => theme.border.radius.sm};
+ color: ${({ theme }) => theme.font.color.secondary};
+ box-shadow: ${({ theme }) => theme.boxShadow.strong};
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ background: ${({ theme }) => theme.background.primary};
+ height: 90%;
+ width: 70%;
+ margin: auto;
+ align-items: center;
+`;
+
+const StyledInputCard = styled.div`
+ align-items: center;
+ color: ${({ theme }) => theme.font.color.secondary};
+ display: flex;
+ flex-direction: column;
+ height: 50%;
+ justify-content: space-evenly;
+ width: 70%;
+`;
+
+const StyledTitleCard = styled.div`
+ align-items: center;
+ color: ${({ theme }) => theme.font.color.secondary};
+ display: flex;
+ flex-direction: column;
+ height: 10%;
+ width: 70%;
+ justify-content: flex-start;
+`;
+
+const StyledButton = styled.span`
+ display: flex;
+ justify-content: space-between;
+ width: 100%;
+`;
+const StyledLabel = styled.span`
+ color: ${({ theme }) => theme.font.color.light};
+ font-size: ${({ theme }) => theme.font.size.xs};
+ font-weight: ${({ theme }) => theme.font.weight.semiBold};
+ margin-bottom: ${({ theme }) => theme.spacing(1)};
+ text-transform: uppercase;
+ display: flex;
+`;
+
+const StyledCheckboxLabel = styled.span`
+ margin-left: ${({ theme }) => theme.spacing(2)};
+`;
+
+const StyledTitle = styled.h3`
+ color: ${({ theme }) => theme.font.color.secondary};
+ font-weight: ${({ theme }) => theme.font.weight.medium};
+ font-size: ${({ theme }) => theme.font.size.md};
+`;
+
+const StyledSection = styled(Section)`
+ align-items: flex-start;
+ display: flex;
+ justify-content: space-between;
+ margin-bottom: 16px;
+ margin-left: 0;
+`;
+export const MessagingChannel = () => {
+ const { setCurrentStep, currentStep } = useCampaign();
+
+ const onSelectCheckBoxChange = (
+ _event: ChangeEvent,
+ arg1: string,
+ ): void => {
+ throw new Error('Function not implemented.');
+ };
+
+ return (
+ <>
+
+
+
+ Deliver your campaign seamlessly across multiple channels with our
+ flexible options. Choose the message channels that align with your
+ audience's behaviors and preferences.
+
+
+
+ Messaging
+
+
+ onSelectCheckBoxChange(event, 'SMS')}
+ variant={CheckboxVariant.Primary}
+ size={CheckboxSize.Small}
+ shape={CheckboxShape.Squared}
+ />{' '}
+ SMS
+
+
+
+ onSelectCheckBoxChange(event, 'Whatsapp')}
+ variant={CheckboxVariant.Primary}
+ size={CheckboxSize.Small}
+ shape={CheckboxShape.Squared}
+ />
+ WhatsApp
+
+
+
+ onSelectCheckBoxChange(event, 'GBM')}
+ variant={CheckboxVariant.Primary}
+ size={CheckboxSize.Small}
+ shape={CheckboxShape.Squared}
+ />
+ GBM
+
+
+
+ onSelectCheckBoxChange(event, 'Call')}
+ variant={CheckboxVariant.Primary}
+ size={CheckboxSize.Small}
+ shape={CheckboxShape.Squared}
+ />
+ CALL
+
+
+
+ setCurrentStep(currentStep - 1)}
+ />
+ setCurrentStep(currentStep + 1)}
+ />
+
+
+
+ >
+ );
+};
diff --git a/packages/twenty-front/src/pages/campaigns/Preview.tsx b/packages/twenty-front/src/pages/campaigns/Preview.tsx
new file mode 100644
index 000000000000..366b0cd7e515
--- /dev/null
+++ b/packages/twenty-front/src/pages/campaigns/Preview.tsx
@@ -0,0 +1,394 @@
+/* eslint-disable no-restricted-globals */
+/* eslint-disable @nx/workspace-styled-components-prefixed-with-styled */
+import { useState } from 'react';
+import { useMutation, useQuery } from '@apollo/client';
+import styled from '@emotion/styled';
+import {
+ Checkbox,
+ CheckboxShape,
+ CheckboxSize,
+ CheckboxVariant,
+ Select,
+ TextInput,
+} from 'tsup.ui.index';
+import { v4 as uuidv4 } from 'uuid';
+
+import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer';
+import { IconMail } from '@/ui/display/icon';
+import { H1Title } from '@/ui/display/typography/components/H1Title';
+import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
+import { Button } from '@/ui/input/button/components/Button';
+import DateTimePicker from '@/ui/input/components/internal/date/components/DateTimePicker';
+import { SubMenuTopBarContainer } from '@/ui/layout/page/SubMenuTopBarContainer';
+import { Section } from '@/ui/layout/section/components/Section';
+import { ADD_CAMPAIGN } from '@/users/graphql/queries/addCampaign';
+import { GET_SPECIALTY } from '@/users/graphql/queries/getSpecialtyDetails';
+import { SAVE_SMS_RESPONSE } from '@/users/graphql/queries/saveSmsResponse';
+
+const StyledH1Title = styled(H1Title)`
+ margin-bottom: 0;
+`;
+
+const StyledSection = styled(Section)`
+ align-items: center;
+ display: flex;
+ justify-content: space-around;
+ margin-bottom: 16px;
+ margin-left: 0;
+`;
+
+const SaveButtonContainer = styled.div`
+ display: flex;
+ justify-content: flex-end;
+ width: auto;
+`;
+
+const StyledLabel = styled.span`
+ color: ${({ theme }) => theme.font.color.light};
+ font-size: ${({ theme }) => theme.font.size.xs};
+ font-weight: ${({ theme }) => theme.font.weight.semiBold};
+ margin-bottom: ${({ theme }) => theme.spacing(1)};
+ text-transform: uppercase;
+`;
+
+const StyledCheckboxLabel = styled.label`
+ align-items: center;
+ display: flex;
+`;
+
+export const Preview = () => {
+ let Specialty: any = [];
+
+ const SpecialtyTypes: any = {};
+
+ const [campaignName, setCampaignName] = useState('');
+ const [description, setDescription] = useState('');
+ const [specialty, setSpecialty] = useState('');
+ const [subSpecialty, setSubSpecialty] = useState('');
+ const [startDate, setStartDate] = useState(new Date());
+ const [endDate, setEndDate] = useState(new Date());
+ const [selectedMessaging, setSelectedMessaging] = useState(new Set());
+ const { loading: queryLoading, data: queryData } = useQuery(GET_SPECIALTY);
+
+ const [showSmsInput, setShowSmsInput] = useState(false);
+ const [smsMessage, setSmsMessage] = useState('');
+
+ if (!queryLoading) {
+ const specialtyTypes = queryData?.subspecialties.edges.map(
+ (edge: { node: { specialtyType: { name: any } } }) =>
+ edge?.node?.specialtyType?.name,
+ );
+ const uniqueSpecialtyTypes = Array.from(new Set(specialtyTypes));
+ Specialty = uniqueSpecialtyTypes.map((specialtyType) => ({
+ value: specialtyType,
+ label: specialtyType,
+ }));
+
+ queryData?.subspecialties.edges.forEach(
+ (edge: { node: { specialtyType: { name: any }; name: any } }) => {
+ const specialtyType = edge.node.specialtyType.name;
+ const subSpecialty = edge.node.name;
+
+ // If the specialty type is already a key in the dictionary, push the sub-specialty to its array
+ if (SpecialtyTypes[specialtyType]) {
+ SpecialtyTypes[specialtyType].push({
+ value: subSpecialty,
+ label: subSpecialty,
+ });
+ } else {
+ // If the specialty type is not yet a key, create a new array with the sub-specialty as its first element
+ SpecialtyTypes[specialtyType] = [];
+ SpecialtyTypes[specialtyType].push({
+ value: subSpecialty,
+ label: subSpecialty,
+ });
+ }
+ },
+ );
+ }
+
+ const [addCampaigns, { loading, error }] = useMutation(ADD_CAMPAIGN);
+
+ const [saveSmsResponse] = useMutation(SAVE_SMS_RESPONSE);
+
+ const { enqueueSnackBar } = useSnackBar();
+
+ const handleCampaignChange = (e: any) => {
+ setCampaignName(e.target.value);
+ };
+
+ const handleDescriptionChange = (e: any) => {
+ setDescription(e.target.value);
+ };
+
+ const handleSpecialtySelectChange = (selectedValue: any) => {
+ setSpecialty(selectedValue);
+ };
+
+ const handleSubSpecialtySelectChange = (selectedValue: any) => {
+ setSubSpecialty(selectedValue);
+ };
+
+ const onSelectCheckBoxChange = (event: any, checkedOption: string) => {
+ const { checked } = event.target;
+ if (checked) {
+ setSelectedMessaging(selectedMessaging.add(checkedOption));
+ if (checkedOption === 'SMS') {
+ setShowSmsInput(true);
+ }
+ } else {
+ selectedMessaging.delete(checkedOption);
+ setSelectedMessaging(selectedMessaging);
+ if (checkedOption === 'SMS') {
+ setShowSmsInput(false);
+ }
+ }
+ };
+ const resetCampaignData = () => {
+ setCampaignName('');
+ setDescription('');
+ setStartDate(new Date());
+ setSelectedMessaging(new Set());
+ setSpecialty('');
+ setSubSpecialty('');
+ };
+ const saveSMSResponse = async (response: any, campaignName: string) => {
+ const variables = {
+ input: {
+ id: uuidv4(),
+ campaignName: campaignName,
+ sid: response.sid,
+ status: response.status,
+ dateCreated: response.date_created,
+ to: response.to,
+ body: response.body,
+ },
+ };
+
+ const { data } = await saveSmsResponse({
+ variables: variables,
+ });
+
+ enqueueSnackBar('SMS response Saved Successfully', {
+ variant: 'success',
+ });
+
+ console.log('ashahsuahsh', data);
+ };
+ const handleSave = async () => {
+ try {
+ console.log('Start Date', startDate);
+
+ console.log('End Date', endDate);
+ const variables = {
+ input: {
+ id: uuidv4(),
+ campaignName: campaignName,
+ specialtyType: specialty,
+ description: description,
+ subSpecialtyType: subSpecialty,
+ startDate: startDate,
+ endDate: endDate,
+ messagingMedia: Array.from(selectedMessaging).join(' '),
+ },
+ };
+ console.log('Variables', variables);
+
+ const { data } = await addCampaigns({
+ variables: variables,
+ });
+ enqueueSnackBar('Campaign added successfully', {
+ variant: 'success',
+ });
+
+ const myHeaders = new Headers();
+ myHeaders.append('Content-Type', 'application/x-www-form-urlencoded');
+ myHeaders.append(
+ 'Authorization',
+ 'Basic QUM1ZGQxNjZiMDhjN2M3MGQ0YzZjNDM1N2I2OTFkODMwZjo0NDdmZmU0OWU1N2VhZmM4ZmIxNjAxZDNiOGEwMDVjYg==',
+ );
+
+ const urlencoded = new URLSearchParams();
+ enqueueSnackBar('SMS sent successfully', {
+ variant: 'success',
+ });
+ urlencoded.append('To', ' 919108223419');
+ urlencoded.append('From', ' 16506035403');
+ urlencoded.append('Body', smsMessage);
+
+ const requestOptions: Object = {
+ method: 'POST',
+ headers: myHeaders,
+ body: urlencoded,
+ redirect: 'follow',
+ };
+
+ const response: any = await fetch(
+ 'https://api.twilio.com/2010-04-01/Accounts/AC5dd166b08c7c70d4c6c4357b691d830f/Messages.json',
+ requestOptions,
+ ).catch((error) => console.error(error));
+ const respData = await response.json();
+
+ if (respData.body) {
+ enqueueSnackBar('SMS sent successfully', {
+ variant: 'success',
+ });
+
+ await saveSMSResponse(respData, campaignName);
+ }
+
+ resetCampaignData();
+ } catch (errors: any) {
+ console.error('Error updating user:', error);
+ enqueueSnackBar(errors.message + 'Error while Submitting Campaign', {
+ variant: 'error',
+ });
+ }
+ };
+ return (
+
+
+
+
+ handleCampaignChange(event)}
+ placeholder="Campaign Name"
+ name="campaignName"
+ required
+ fullWidth
+ />
+
+
+ handleDescriptionChange(event)}
+ placeholder="Description about campaign"
+ name="description"
+ required
+ fullWidth
+ />
+
+
+ {specialty && (
+
+ )}
+
+ Start Date
+ setStartDate(startDate)}
+ minDate={new Date()}
+ />
+
+
+ End Date
+ setEndDate(endDate)}
+ minDate={startDate}
+ />
+
+
+ Messaging
+
+
+ onSelectCheckBoxChange(event, 'SMS')}
+ variant={CheckboxVariant.Primary}
+ size={CheckboxSize.Small}
+ shape={CheckboxShape.Squared}
+ />
+ SMS
+
+
+
+ onSelectCheckBoxChange(event, 'Whatsapp')}
+ variant={CheckboxVariant.Primary}
+ size={CheckboxSize.Small}
+ shape={CheckboxShape.Squared}
+ />
+ WhastApp
+
+
+
+ onSelectCheckBoxChange(event, 'GBM')}
+ variant={CheckboxVariant.Primary}
+ size={CheckboxSize.Small}
+ shape={CheckboxShape.Squared}
+ />
+ GBM
+
+
+
+ onSelectCheckBoxChange(event, 'Call')}
+ variant={CheckboxVariant.Primary}
+ size={CheckboxSize.Small}
+ shape={CheckboxShape.Squared}
+ />
+ Call
+
+
+
+ {showSmsInput && (
+
+ SMS Message Body
+ setSmsMessage(value)}
+ placeholder="Enter SMS message body"
+ fullWidth
+ />
+
+ )}
+
+
+
+ handleSave()}
+ />
+
+
+
+ );
+};
diff --git a/packages/twenty-front/src/pages/campaigns/PreviewPage.tsx b/packages/twenty-front/src/pages/campaigns/PreviewPage.tsx
new file mode 100644
index 000000000000..c93ca43e0de5
--- /dev/null
+++ b/packages/twenty-front/src/pages/campaigns/PreviewPage.tsx
@@ -0,0 +1,118 @@
+/* eslint-disable prefer-arrow/prefer-arrow-functions */
+/* eslint-disable no-restricted-imports */
+import { ChangeEvent } from 'react';
+import styled from '@emotion/styled';
+import { IconArrowLeft } from '@tabler/icons-react';
+import { IconArrowRight } from '@tabler/icons-react';
+
+import { Button } from '@/ui/input/button/components/Button';
+import { Section } from '@/ui/layout/section/components/Section';
+import { useCampaign } from '~/pages/campaigns/CampaignUseContext';
+const StyledCard = styled.div`
+ border: 1px solid ${({ theme }) => theme.border.color.medium};
+ border-radius: ${({ theme }) => theme.border.radius.sm};
+ color: ${({ theme }) => theme.font.color.secondary};
+ box-shadow: ${({ theme }) => theme.boxShadow.strong};
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ background: ${({ theme }) => theme.background.primary};
+ height: 90%;
+ width: 70%;
+ margin: auto;
+ align-items: center;
+`;
+
+const StyledInputCard = styled.div`
+ align-items: center;
+ color: ${({ theme }) => theme.font.color.secondary};
+ display: flex;
+ flex-direction: column;
+ height: 50%;
+ justify-content: space-evenly;
+ width: 70%;
+`;
+
+const StyledTitleCard = styled.div`
+ align-items: center;
+ color: ${({ theme }) => theme.font.color.secondary};
+ display: flex;
+ flex-direction: column;
+ height: 10%;
+ width: 70%;
+ justify-content: flex-start;
+`;
+
+const StyledButton = styled.span`
+ display: flex;
+ justify-content: space-between;
+ width: 100%;
+`;
+const StyledLabel = styled.span`
+ color: ${({ theme }) => theme.font.color.light};
+ font-size: ${({ theme }) => theme.font.size.xs};
+ font-weight: ${({ theme }) => theme.font.weight.semiBold};
+ margin-bottom: ${({ theme }) => theme.spacing(1)};
+ text-transform: uppercase;
+ display: flex;
+`;
+
+const StyledCheckboxLabel = styled.span`
+ margin-left: ${({ theme }) => theme.spacing(2)};
+`;
+
+const StyledTitle = styled.h3`
+ color: ${({ theme }) => theme.font.color.secondary};
+ font-weight: ${({ theme }) => theme.font.weight.medium};
+ font-size: ${({ theme }) => theme.font.size.md};
+`;
+
+const StyledSection = styled(Section)`
+ align-items: flex-start;
+ display: flex;
+ justify-content: space-between;
+ margin-bottom: 16px;
+ margin-left: 0;
+`;
+export const PreviewPage = () => {
+ const { setCurrentStep, currentStep } = useCampaign();
+
+ const onSelectCheckBoxChange = (
+ _event: ChangeEvent,
+ arg1: string,
+ ): void => {
+ throw new Error('Function not implemented.');
+ };
+
+ return (
+ <>
+
+
+
+ Deliver your campaign seamlessly across multiple channels with our
+ flexible options. Choose the message channels that align with your
+ audience's behaviors and preferences.
+
+
+
+ Preview
+
+ setCurrentStep(currentStep - 1)}
+ />
+
+
+
+
+ >
+ );
+};
diff --git a/packages/twenty-front/src/pages/campaigns/Specialty.tsx b/packages/twenty-front/src/pages/campaigns/Specialty.tsx
new file mode 100644
index 000000000000..c550a421d0b6
--- /dev/null
+++ b/packages/twenty-front/src/pages/campaigns/Specialty.tsx
@@ -0,0 +1,171 @@
+/* eslint-disable no-restricted-imports */
+import { useState } from 'react';
+import { useQuery } from '@apollo/client';
+import styled from '@emotion/styled';
+import { IconArrowLeft } from '@tabler/icons-react';
+import { IconArrowRight } from '@tabler/icons-react';
+
+import { Button } from '@/ui/input/button/components/Button';
+import { Select } from '@/ui/input/components/Select';
+import { Section } from '@/ui/layout/section/components/Section';
+import { GET_SPECIALTY } from '@/users/graphql/queries/getSpecialtyDetails';
+import { useCampaign } from '~/pages/campaigns/CampaignUseContext';
+
+const StyledCard = styled.div`
+ border: 1px solid ${({ theme }) => theme.border.color.medium};
+ border-radius: ${({ theme }) => theme.border.radius.sm};
+ color: ${({ theme }) => theme.font.color.secondary};
+ box-shadow: ${({ theme }) => theme.boxShadow.strong};
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ background: ${({ theme }) => theme.background.primary};
+ height: 90%;
+ width: 70%;
+ margin: auto;
+ align-items: center;
+`;
+
+const StyledInputCard = styled.div`
+ color: ${({ theme }) => theme.font.color.secondary};
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ height: 50%;
+ justify-content: space-evenly;
+ width: 70%;
+ align-items: center;
+`;
+
+const StyledTitleCard = styled.div`
+ align-items: center;
+ color: ${({ theme }) => theme.font.color.secondary};
+ display: flex;
+ flex-direction: column;
+ height: 10%;
+ width: 70%;
+ justify-content: flex-start;
+`;
+
+const StyledButton = styled.span`
+ display: flex;
+ justify-content: space-between;
+ width: 100%;
+`;
+const StyledLabel = styled.span`
+ color: ${({ theme }) => theme.font.color.light};
+ font-size: ${({ theme }) => theme.font.size.xs};
+ font-weight: ${({ theme }) => theme.font.weight.semiBold};
+ margin-bottom: ${({ theme }) => theme.spacing(1)};
+ text-transform: uppercase;
+`;
+
+const StyledTitle = styled.h3`
+ color: ${({ theme }) => theme.font.color.secondary};
+ font-weight: ${({ theme }) => theme.font.weight.medium};
+ font-size: ${({ theme }) => theme.font.size.md};
+`;
+export const Specialty = () => {
+ const { setCurrentStep, currentStep } = useCampaign();
+
+ let Specialty: any = [];
+ const SpecialtyTypes: any = {};
+ const [specialty, setSpecialty] = useState('');
+ const [subSpecialty, setSubSpecialty] = useState('');
+ const { loading: queryLoading, data: queryData } = useQuery(GET_SPECIALTY);
+
+ if (!queryLoading) {
+ const specialtyTypes = queryData?.subspecialties.edges.map(
+ (edge: { node: { specialtyType: { name: any } } }) =>
+ edge?.node?.specialtyType?.name,
+ );
+ const uniqueSpecialtyTypes = Array.from(new Set(specialtyTypes));
+ Specialty = uniqueSpecialtyTypes.map((specialtyType) => ({
+ value: specialtyType,
+ label: specialtyType,
+ }));
+
+ queryData?.subspecialties.edges.forEach(
+ (edge: { node: { specialtyType: { name: any }; name: any } }) => {
+ const specialtyType = edge.node.specialtyType.name;
+ const subSpecialty = edge.node.name;
+
+ // If the specialty type is already a key in the dictionary, push the sub-specialty to its array
+ if (SpecialtyTypes[specialtyType]) {
+ SpecialtyTypes[specialtyType].push({
+ value: subSpecialty,
+ label: subSpecialty,
+ });
+ } else {
+ // If the specialty type is not yet a key, create a new array with the sub-specialty as its first element
+ SpecialtyTypes[specialtyType] = [];
+ SpecialtyTypes[specialtyType].push({
+ value: subSpecialty,
+ label: subSpecialty,
+ });
+ }
+ },
+ );
+ }
+
+ const handleSpecialtySelectChange = (selectedValue: any) => {
+ setSpecialty(selectedValue);
+ };
+
+ const handleSubSpecialtySelectChange = (selectedValue: any) => {
+ setSubSpecialty(selectedValue);
+ };
+ return (
+ <>
+
+
+
+ Select from a variety of specialties and sub-specialties to
+ customize your campaign and target specific segments of your
+ audience with precision.
+
+
+
+
+ {specialty && (
+
+ )}
+
+ setCurrentStep(currentStep - 1)}
+ />
+ setCurrentStep(currentStep + 1)}
+ />
+
+
+
+ >
+ );
+};
From bc86ac7a1f5b833608ad2ce6dad49fc589e40f16 Mon Sep 17 00:00:00 2001
From: sanjana0190 <56463647+sanjana0190@users.noreply.github.com>
Date: Thu, 2 May 2024 18:05:48 +0530
Subject: [PATCH 020/122] removed Initial committed Campaign Files
---
.../components/MainNavigationDrawerItems.tsx | 25 +-
.../src/pages/Templates/AudioTemplate.tsx | 109 -----
.../src/pages/Templates/DocumentTemplate.tsx | 109 -----
.../src/pages/Templates/ImageTemplate.tsx | 126 ------
.../src/pages/Templates/TemplatesList.tsx | 71 ----
.../src/pages/Templates/TextTemplate.tsx | 92 ----
.../src/pages/Templates/VideoTemplate.tsx | 109 -----
.../src/pages/campaigns/CampaignContext.tsx | 36 --
.../src/pages/campaigns/CampaignDate.tsx | 118 ------
.../src/pages/campaigns/CampaignDetails.tsx | 126 ------
.../pages/campaigns/CampaignUseContext.tsx | 14 -
.../src/pages/campaigns/Campaigns.tsx | 92 ----
.../twenty-front/src/pages/campaigns/Lead.tsx | 115 -----
.../src/pages/campaigns/MessagingChannel.tsx | 175 --------
.../src/pages/campaigns/Preview.tsx | 394 ------------------
.../src/pages/campaigns/PreviewPage.tsx | 118 ------
.../src/pages/campaigns/Specialty.tsx | 171 --------
17 files changed, 8 insertions(+), 1992 deletions(-)
delete mode 100644 packages/twenty-front/src/pages/Templates/AudioTemplate.tsx
delete mode 100644 packages/twenty-front/src/pages/Templates/DocumentTemplate.tsx
delete mode 100644 packages/twenty-front/src/pages/Templates/ImageTemplate.tsx
delete mode 100644 packages/twenty-front/src/pages/Templates/TemplatesList.tsx
delete mode 100644 packages/twenty-front/src/pages/Templates/TextTemplate.tsx
delete mode 100644 packages/twenty-front/src/pages/Templates/VideoTemplate.tsx
delete mode 100644 packages/twenty-front/src/pages/campaigns/CampaignContext.tsx
delete mode 100644 packages/twenty-front/src/pages/campaigns/CampaignDate.tsx
delete mode 100644 packages/twenty-front/src/pages/campaigns/CampaignDetails.tsx
delete mode 100644 packages/twenty-front/src/pages/campaigns/CampaignUseContext.tsx
delete mode 100644 packages/twenty-front/src/pages/campaigns/Campaigns.tsx
delete mode 100644 packages/twenty-front/src/pages/campaigns/Lead.tsx
delete mode 100644 packages/twenty-front/src/pages/campaigns/MessagingChannel.tsx
delete mode 100644 packages/twenty-front/src/pages/campaigns/Preview.tsx
delete mode 100644 packages/twenty-front/src/pages/campaigns/PreviewPage.tsx
delete mode 100644 packages/twenty-front/src/pages/campaigns/Specialty.tsx
diff --git a/packages/twenty-front/src/modules/navigation/components/MainNavigationDrawerItems.tsx b/packages/twenty-front/src/modules/navigation/components/MainNavigationDrawerItems.tsx
index 1147a7d888a3..88553e6b22a5 100644
--- a/packages/twenty-front/src/modules/navigation/components/MainNavigationDrawerItems.tsx
+++ b/packages/twenty-front/src/modules/navigation/components/MainNavigationDrawerItems.tsx
@@ -1,11 +1,17 @@
import { useLocation, useNavigate } from 'react-router-dom';
import { useRecoilValue, useSetRecoilState } from 'recoil';
-import { IconCheckbox, IconInbox, IconSearch, IconSettings, IconMail } from 'twenty-ui';
+import {
+ IconCheckbox,
+ IconInbox,
+ IconSearch,
+ IconSettings,
+ IconMail,
+} from 'twenty-ui';
import { CurrentUserDueTaskCountEffect } from '@/activities/tasks/components/CurrentUserDueTaskCountEffect';
import { currentUserDueTaskCountState } from '@/activities/tasks/states/currentUserTaskCountState';
import { useCommandMenu } from '@/command-menu/hooks/useCommandMenu';
import { Favorites } from '@/favorites/components/Favorites';
-import { ObjectMetadataNavItems } from '@/object-metadata/components/ObjectMetadataNavItems'
+import { ObjectMetadataNavItems } from '@/object-metadata/components/ObjectMetadataNavItems';
import { NavigationDrawerItem } from '@/ui/navigation/navigation-drawer/components/NavigationDrawerItem';
import { NavigationDrawerSection } from '@/ui/navigation/navigation-drawer/components/NavigationDrawerSection';
import { NavigationDrawerSectionTitle } from '@/ui/navigation/navigation-drawer/components/NavigationDrawerSectionTitle';
@@ -65,21 +71,6 @@ export const MainNavigationDrawerItems = () => {
- {
- navigate('/templatelist');
- }}
- Icon={IconMail}
- />
-
- {
- navigate('/campaigns');
- }}
- Icon={IconMail}
- />
>
);
diff --git a/packages/twenty-front/src/pages/Templates/AudioTemplate.tsx b/packages/twenty-front/src/pages/Templates/AudioTemplate.tsx
deleted file mode 100644
index 609d634aeb28..000000000000
--- a/packages/twenty-front/src/pages/Templates/AudioTemplate.tsx
+++ /dev/null
@@ -1,109 +0,0 @@
-import { ChangeEvent, useRef, useState } from 'react';
-import styled from '@emotion/styled';
-import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer';
-import { H1Title } from '@/ui/display/typography/components/H1Title';
-import { H2Title } from '@/ui/display/typography/components/H2Title';
-import { SubMenuTopBarContainer } from '@/ui/layout/page/SubMenuTopBarContainer';
-import { Section } from '@/ui/layout/section/components/Section';
-import { TextArea, TextInput } from 'tsup.ui.index';
-import { Button } from '@/ui/input/button/components/Button';
-import { ActivityTargetableObject } from '@/activities/types/ActivityTargetableEntity';
-import { useMutation } from '@apollo/client';
-import { UPLOAD_FILE } from '../../modules/files/graphql/queries/uploadFile.ts';
-import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
-import { IconSettings } from '@/ui/display/icon';
-
-const StyledH1Title = styled(H1Title)`
- margin-bottom: 0;
-`;
-
-const StyledInputsContainer = styled.div`
- display: flex;
- gap: ${({ theme }) => theme.spacing(2)};
- margin-bottom: ${({ theme }) => theme.spacing(2)};
- width: 100%;
-`;
-
-export const AudioTemplate = ({
- targetableObject,
-}: {
- targetableObject: ActivityTargetableObject;
-}) => {
- const [bodyDescription, setBodyDescription] = useState('');
- const [footerText, setFooterText] = useState('');
- const [file, setFile] = useState(null);
- const [uploadFileMutation] = useMutation(UPLOAD_FILE);
- const { enqueueSnackBar } = useSnackBar();
-
- const handleFileChange = (event: ChangeEvent) => {
- const selectedFile = event.target.files && event.target.files[0];
- setFile(selectedFile || null);
- };
-
- const handleUpload = async () => {
- try {
- if (!file) return;
- const { data } = await uploadFileMutation({
- variables: {
- file,
- fileFolder: 'Attachment',
- },
- });
- console.log('File uploaded successfully:', data);
-
- enqueueSnackBar('Uploaded Sucessfullly!',{
- variant: 'success',
- });
- } catch (errors: any) {
- console.error('Error uploading file:', errors);
- enqueueSnackBar(errors.message + ' Error uploading file:',{
- variant: 'error',
- });
-
- }
- };
-
- return (
-
-
-
-
-
-
-
-
-
-
-
- );
-};
diff --git a/packages/twenty-front/src/pages/Templates/DocumentTemplate.tsx b/packages/twenty-front/src/pages/Templates/DocumentTemplate.tsx
deleted file mode 100644
index 31289a1dcdc0..000000000000
--- a/packages/twenty-front/src/pages/Templates/DocumentTemplate.tsx
+++ /dev/null
@@ -1,109 +0,0 @@
-import { ChangeEvent, useRef, useState } from 'react';
-import styled from '@emotion/styled';
-import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer';
-import { H1Title } from '@/ui/display/typography/components/H1Title';
-import { H2Title } from '@/ui/display/typography/components/H2Title';
-import { SubMenuTopBarContainer } from '@/ui/layout/page/SubMenuTopBarContainer';
-import { Section } from '@/ui/layout/section/components/Section';
-import { TextArea, TextInput } from 'tsup.ui.index';
-import { Button } from '@/ui/input/button/components/Button';
-import { ActivityTargetableObject } from '@/activities/types/ActivityTargetableEntity';
-import { useMutation } from '@apollo/client';
-import { UPLOAD_FILE } from '../../modules/files/graphql/queries/uploadFile.ts';
-import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
-import { IconSettings } from '@/ui/display/icon';
-
-const StyledH1Title = styled(H1Title)`
- margin-bottom: 0;
-`;
-
-const StyledInputsContainer = styled.div`
- display: flex;
- gap: ${({ theme }) => theme.spacing(2)};
- margin-bottom: ${({ theme }) => theme.spacing(2)};
- width: 100%;
-`;
-
-export const DocumentTemplate = ({
- targetableObject,
-}: {
- targetableObject: ActivityTargetableObject;
-}) => {
- const [bodyDescription, setBodyDescription] = useState('');
- const [footerText, setFooterText] = useState('');
- const [file, setFile] = useState(null);
- const [uploadFileMutation] = useMutation(UPLOAD_FILE);
- const { enqueueSnackBar } = useSnackBar();
-
- const handleFileChange = (event: ChangeEvent) => {
- const selectedFile = event.target.files && event.target.files[0];
- setFile(selectedFile || null);
- };
-
- const handleUpload = async () => {
- try {
- if (!file) return;
- const { data } = await uploadFileMutation({
- variables: {
- file,
- fileFolder: 'Attachment',
- },
- });
- console.log('File uploaded successfully:', data);
-
- enqueueSnackBar('Uploaded Sucessfullly!',{
- variant: 'success',
- });
- } catch (errors: any) {
- console.error('Error uploading file:', errors);
- enqueueSnackBar(errors.message + ' Error uploading file:',{
- variant: 'error',
- });
-
- }
- };
-
- return (
-
-
-
-
-
-
-
-
-
-
-
- );
-};
diff --git a/packages/twenty-front/src/pages/Templates/ImageTemplate.tsx b/packages/twenty-front/src/pages/Templates/ImageTemplate.tsx
deleted file mode 100644
index c71e014634de..000000000000
--- a/packages/twenty-front/src/pages/Templates/ImageTemplate.tsx
+++ /dev/null
@@ -1,126 +0,0 @@
-import { ChangeEvent, useRef, useState } from 'react';
-import styled from '@emotion/styled';
-import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer';
-import { H1Title } from '@/ui/display/typography/components/H1Title';
-import { H2Title } from '@/ui/display/typography/components/H2Title';
-import { SubMenuTopBarContainer } from '@/ui/layout/page/SubMenuTopBarContainer';
-import { Section } from '@/ui/layout/section/components/Section';
-import { TextArea, TextInput } from 'tsup.ui.index';
-import { Button } from '@/ui/input/button/components/Button';
-import { ActivityTargetableObject } from '@/activities/types/ActivityTargetableEntity';
-import { useMutation } from '@apollo/client';
-import { UPLOAD_FILE } from '../../modules/files/graphql/queries/uploadFile.ts';
-import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
-import { IconSettings } from '@/ui/display/icon';
-
-const StyledH1Title = styled(H1Title)`
- margin-bottom: 0;
-`;
-
-const StyledInputsContainer = styled.div`
- display: flex;
- gap: ${({ theme }) => theme.spacing(2)};
- margin-bottom: ${({ theme }) => theme.spacing(2)};
- width: 100%;
-`;
-
-const StyledImagePreview = styled.img`
- max-width: 100%;
- max-height: 200px;
- margin-top: ${({ theme }) => theme.spacing(2)};
-`;
-
-export const ImageTemplate = ({
- targetableObject,
-}: {
- targetableObject: ActivityTargetableObject;
-}) => {
- const [bodyDescription, setBodyDescription] = useState('');
- const [footerText, setFooterText] = useState('');
- const [file, setFile] = useState(null);
- const [imagePreviewUrl, setImagePreviewUrl] = useState(null);
- const [uploadFileMutation] = useMutation(UPLOAD_FILE);
- const { enqueueSnackBar } = useSnackBar();
-
- const handleFileChange = (event: ChangeEvent) => {
- const selectedFile = event.target.files && event.target.files[0];
- setFile(selectedFile || null);
-
- if (selectedFile && selectedFile.type.startsWith('image/')) {
- const reader = new FileReader();
- reader.onloadend = () => {
- setImagePreviewUrl(reader.result as string);
- };
- reader.readAsDataURL(selectedFile);
- } else {
- setImagePreviewUrl(null);
- }
- };
-
- const handleUpload = async () => {
- try {
- if (!file) return;
- const { data } = await uploadFileMutation({
- variables: {
- file,
- fileFolder: 'Attachment',
- },
- });
- console.log('File uploaded successfully:', data);
- enqueueSnackBar('Uploaded Sucessfullly!',{
- variant: 'success',
- });
- } catch (errors: any) {
- console.error('Error uploading file:', errors);
- enqueueSnackBar(errors.message + ' Error uploading file:',{
- variant: 'error',
- });
-
- }
- };
-
- return (
-
-
-
-
-
-
-
-
-
-
-
- );
-};
diff --git a/packages/twenty-front/src/pages/Templates/TemplatesList.tsx b/packages/twenty-front/src/pages/Templates/TemplatesList.tsx
deleted file mode 100644
index 1c028adf8806..000000000000
--- a/packages/twenty-front/src/pages/Templates/TemplatesList.tsx
+++ /dev/null
@@ -1,71 +0,0 @@
-import { useNavigate } from 'react-router-dom';
-import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer';
-import { IconSettings } from '@/ui/display/icon';
-import { H2Title } from '@/ui/display/typography/components/H2Title';
-import { SubMenuTopBarContainer } from '@/ui/layout/page/SubMenuTopBarContainer';
-import { Table } from '@/ui/layout/table/components/Table';
-import { TableHeader } from '@/ui/layout/table/components/TableHeader';
-import { TableRow } from '@/ui/layout/table/components/TableRow';
-import { TableCell } from '@/ui/layout/table/components/TableCell';
-
-export const TemplatesList = () => {
- const navigate = useNavigate();
-
- const handleRowClick = (templateName: string) => {
- navigate(`/${templateName.toLowerCase()}`);
- };
-
- return (
-
-
-
-
-
- Name
- Description
- Created At
-
-
- handleRowClick('TextTemplate')}>
- Text Template
- Template with text Header type.
- 12/12/12
-
-
- handleRowClick('ImageTemplate')}>
- Image Template
- Template with Image Header type.
- 12/12/12
-
-
- handleRowClick('VideoTemplate')}>
- Video Template
- Template with Video Header type.
- 12/12/12
-
-
- handleRowClick('AudioTemplate')}>
- Audio Template
- Template with Audio Header type.
- 12/12/12
-
-
- handleRowClick('DocumentTemplate')}>
- Document Template
- Template with Video Header type.
- 12/12/12
-
-
-
- {/* */}
-
- );
-};
diff --git a/packages/twenty-front/src/pages/Templates/TextTemplate.tsx b/packages/twenty-front/src/pages/Templates/TextTemplate.tsx
deleted file mode 100644
index f97050932e32..000000000000
--- a/packages/twenty-front/src/pages/Templates/TextTemplate.tsx
+++ /dev/null
@@ -1,92 +0,0 @@
-import { useState } from 'react';
-import styled from '@emotion/styled';
-import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer';
-import { IconSettings, IconUpload } from '@/ui/display/icon';
-import { H1Title } from '@/ui/display/typography/components/H1Title';
-import { H2Title } from '@/ui/display/typography/components/H2Title';
-import { SubMenuTopBarContainer } from '@/ui/layout/page/SubMenuTopBarContainer';
-import { Section } from '@/ui/layout/section/components/Section';
-import { TextArea, TextInput } from 'tsup.ui.index';
-import { ImageInput } from '@/ui/input/components/ImageInput';
-import { getImageAbsoluteURIOrBase64 } from '@/users/utils/getProfilePictureAbsoluteURI';
-import { useUploadProfilePictureMutation } from '~/generated/graphql';
-
-const StyledH1Title = styled(H1Title)`
- margin-bottom: 0;
-`;
-
-const StyledComboInputContainer = styled.div`
- display: flex;
- flex-direction: row;
- > * + * {
- margin-left: ${({ theme }) => theme.spacing(4)};
- }
- margin-bottom: ${({ theme }) => theme.spacing(2)};
-`;
-
-const StyledInputsContainer = styled.div`
- display: flex;
- gap: ${({ theme }) => theme.spacing(2)};
- margin-bottom: ${({ theme }) => theme.spacing(2)};
- width: 100%;
-`;
-
-export const TextTemplate = () => {
- const [uploadPicture] = useUploadProfilePictureMutation();
- const [headerText, setHeaderText] = useState('');
- const [bodyDescription, setBodyDescription] = useState('');
- const [footerText, setFooterText] = useState('');
-
- const handleUpload = async (file: File) => {
- if (!file) return;
-
- try {
- const result = await uploadPicture({ variables: { file } });
- return result;
- } catch (error) {
- console.error('An error occurred while uploading the picture:', error);
- }
- };
-
- return (
-
-
-
-
-
-
-
-
-
-
-
-
- );
-};
diff --git a/packages/twenty-front/src/pages/Templates/VideoTemplate.tsx b/packages/twenty-front/src/pages/Templates/VideoTemplate.tsx
deleted file mode 100644
index e4469a401e3f..000000000000
--- a/packages/twenty-front/src/pages/Templates/VideoTemplate.tsx
+++ /dev/null
@@ -1,109 +0,0 @@
-import { ChangeEvent, useRef, useState } from 'react';
-import styled from '@emotion/styled';
-import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer';
-import { H1Title } from '@/ui/display/typography/components/H1Title';
-import { H2Title } from '@/ui/display/typography/components/H2Title';
-import { SubMenuTopBarContainer } from '@/ui/layout/page/SubMenuTopBarContainer';
-import { Section } from '@/ui/layout/section/components/Section';
-import { TextArea, TextInput } from 'tsup.ui.index';
-import { Button } from '@/ui/input/button/components/Button';
-import { ActivityTargetableObject } from '@/activities/types/ActivityTargetableEntity';
-import { useMutation } from '@apollo/client';
-import { UPLOAD_FILE } from '../../modules/files/graphql/queries/uploadFile.ts';
-import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
-import { IconSettings } from '@/ui/display/icon';
-
-const StyledH1Title = styled(H1Title)`
- margin-bottom: 0;
-`;
-
-const StyledInputsContainer = styled.div`
- display: flex;
- gap: ${({ theme }) => theme.spacing(2)};
- margin-bottom: ${({ theme }) => theme.spacing(2)};
- width: 100%;
-`;
-
-export const VideoTemplate = ({
- targetableObject,
-}: {
- targetableObject: ActivityTargetableObject;
-}) => {
- const [bodyDescription, setBodyDescription] = useState('');
- const [footerText, setFooterText] = useState('');
- const [file, setFile] = useState(null);
- const [uploadFileMutation] = useMutation(UPLOAD_FILE);
- const { enqueueSnackBar } = useSnackBar();
-
- const handleFileChange = (event: ChangeEvent) => {
- const selectedFile = event.target.files && event.target.files[0];
- setFile(selectedFile || null);
- };
-
- const handleUpload = async () => {
- try {
- if (!file) return;
- const { data } = await uploadFileMutation({
- variables: {
- file,
- fileFolder: 'Attachment',
- },
- });
- console.log('File uploaded successfully:', data);
-
- enqueueSnackBar('Uploaded Sucessfullly!',{
- variant: 'success',
- });
- } catch (errors: any) {
- console.error('Error uploading file:', errors);
- enqueueSnackBar(errors.message + ' Error uploading file:',{
- variant: 'error',
- });
-
- }
- };
-
- return (
-
-
-
-
-
-
-
-
-
-
-
- );
-};
diff --git a/packages/twenty-front/src/pages/campaigns/CampaignContext.tsx b/packages/twenty-front/src/pages/campaigns/CampaignContext.tsx
deleted file mode 100644
index 20984ce1d5f7..000000000000
--- a/packages/twenty-front/src/pages/campaigns/CampaignContext.tsx
+++ /dev/null
@@ -1,36 +0,0 @@
-import { createContext, useState } from 'react';
-
-import { App } from '~/App';
-export type CampaignContextProps = {
- currentStep: number;
- setCurrentStep: {};
-
- campaignData: {};
-
- setCampaignData: {};
-};
-
-export const CampaignMultiStepContext =
- createContext(null);
-
-const CampaignContext = () => {
- const [currentStep, setCurrentStep] = useState(0);
- const [campaignData, setCampaignData] = useState({});
-
- return (
-
- );
-};
-
-export default CampaignContext;
diff --git a/packages/twenty-front/src/pages/campaigns/CampaignDate.tsx b/packages/twenty-front/src/pages/campaigns/CampaignDate.tsx
deleted file mode 100644
index 260ba68b6030..000000000000
--- a/packages/twenty-front/src/pages/campaigns/CampaignDate.tsx
+++ /dev/null
@@ -1,118 +0,0 @@
-/* eslint-disable no-restricted-imports */
-import { useState } from 'react';
-import styled from '@emotion/styled';
-import { Section } from '@react-email/components';
-import { IconArrowLeft } from '@tabler/icons-react';
-import { IconArrowRight } from '@tabler/icons-react';
-import { Button } from 'tsup.ui.index';
-
-import DateTimePicker from '@/ui/input/components/internal/date/components/DateTimePicker';
-import { useCampaign } from '~/pages/campaigns/CampaignUseContext';
-
-const StyledCard = styled.div`
- border: 1px solid ${({ theme }) => theme.border.color.medium};
- border-radius: ${({ theme }) => theme.border.radius.sm};
- color: ${({ theme }) => theme.font.color.secondary};
- box-shadow: ${({ theme }) => theme.boxShadow.strong};
- display: flex;
- flex-direction: column;
- justify-content: center;
- background: ${({ theme }) => theme.background.primary};
- height: 90%;
- width: 70%;
- margin: auto;
- align-items: center;
-`;
-
-const StyledInputCard = styled.div`
- color: ${({ theme }) => theme.font.color.secondary};
- display: flex;
- flex-direction: column;
- justify-content: center;
- height: 70%;
- justify-content: space-evenly;
- width: 70%;
- align-items: center;
-`;
-
-const StyledTitleCard = styled.div`
- align-items: center;
- color: ${({ theme }) => theme.font.color.secondary};
- display: flex;
- flex-direction: column;
- height: 10%;
- width: 70%;
- justify-content: center;
-`;
-
-const StyledButton = styled.span`
- display: flex;
- justify-content: space-between;
- width: 100%;
-`;
-const StyledLabel = styled.span`
- color: ${({ theme }) => theme.font.color.light};
- font-size: ${({ theme }) => theme.font.size.xs};
- font-weight: ${({ theme }) => theme.font.weight.semiBold};
- margin-bottom: ${({ theme }) => theme.spacing(1)};
- text-transform: uppercase;
-`;
-
-const StyledTitle = styled.h3`
- color: ${({ theme }) => theme.font.color.secondary};
- font-weight: ${({ theme }) => theme.font.weight.medium};
- font-size: ${({ theme }) => theme.font.size.md};
-`;
-
-export const CampaignDate = () => {
- const { setCurrentStep, currentStep } = useCampaign();
-
- const [startDate, setStartDate] = useState(new Date());
- const [endDate, setEndDate] = useState(new Date());
-
- return (
- <>
-
-
-
- The campaign date: where strategy meets opportunity
-
-
-
-
- Start Date
- setStartDate(startDate)}
- minDate={new Date()}
- showTimeInput
- />
-
-
- End Date
- setEndDate(endDate)}
- minDate={startDate}
- showTimeInput
- />
-
-
-
- setCurrentStep(currentStep - 1)}
- />
- setCurrentStep(currentStep + 1)}
- />
-
-
-
- >
- );
-};
diff --git a/packages/twenty-front/src/pages/campaigns/CampaignDetails.tsx b/packages/twenty-front/src/pages/campaigns/CampaignDetails.tsx
deleted file mode 100644
index e1fa35e36f23..000000000000
--- a/packages/twenty-front/src/pages/campaigns/CampaignDetails.tsx
+++ /dev/null
@@ -1,126 +0,0 @@
-/* eslint-disable no-restricted-imports */
-import styled from '@emotion/styled';
-import { IconArrowLeft } from '@tabler/icons-react';
-import { IconArrowRight } from '@tabler/icons-react';
-import { Button, TextArea, TextInput } from 'tsup.ui.index';
-
-import { useCampaign } from '~/pages/campaigns/CampaignUseContext';
-
-const StyledCard = styled.div`
- border: 1px solid ${({ theme }) => theme.border.color.medium};
- border-radius: ${({ theme }) => theme.border.radius.sm};
- color: ${({ theme }) => theme.font.color.secondary};
- box-shadow: ${({ theme }) => theme.boxShadow.strong};
- display: flex;
- flex-direction: column;
- justify-content: center;
- background: ${({ theme }) => theme.background.primary};
- height: 90%;
- width: 70%;
- margin: auto;
- align-items: center;
-`;
-
-const StyledInputCard = styled.div`
- color: ${({ theme }) => theme.font.color.secondary};
- display: flex;
- flex-direction: column;
- justify-content: center;
- height: 50%;
- justify-content: space-evenly;
- width: 70%;
- align-items: center;
-`;
-
-const StyledTitleCard = styled.div`
- align-items: center;
- color: ${({ theme }) => theme.font.color.secondary};
- display: flex;
- flex-direction: column;
- height: 10%;
- width: 70%;
- justify-content: flex-start;
-`;
-
-const StyledAreaLabel = styled.span`
- align-content: flex-start;
- display: flex;
- flex-direction: column;
- margin-bottom: 2%;
- width: 100%;
-`;
-const StyledButton = styled.span`
- display: flex;
- justify-content: space-between;
- width: 100%;
-`;
-const StyledLabel = styled.span`
- color: ${({ theme }) => theme.font.color.light};
- font-size: ${({ theme }) => theme.font.size.xs};
- font-weight: ${({ theme }) => theme.font.weight.semiBold};
- margin-bottom: ${({ theme }) => theme.spacing(1)};
- text-transform: uppercase;
-`;
-
-const StyledTitle = styled.h3`
- color: ${({ theme }) => theme.font.color.secondary};
- font-weight: ${({ theme }) => theme.font.weight.medium};
- font-size: ${({ theme }) => theme.font.size.md};
-`;
-
-export const CampaignDetails = () => {
- const { setCurrentStep, currentStep } = useCampaign();
- const handleCampaignChange = (_event: Event | undefined): void => {
- throw new Error('Function not implemented.');
- };
-
- return (
- <>
-
-
-
- Get started on your campaign journey with our comprehensive
- solution. Create, launch, and optimize campaigns with ease
-
-
-
- handleCampaignChange(event)}
- name="campaignName"
- required
- fullWidth
- />
-
- Description
-
-
-
- setCurrentStep(currentStep + 1)}
- />
-
-
-
- >
- );
-};
diff --git a/packages/twenty-front/src/pages/campaigns/CampaignUseContext.tsx b/packages/twenty-front/src/pages/campaigns/CampaignUseContext.tsx
deleted file mode 100644
index 931f9830aabf..000000000000
--- a/packages/twenty-front/src/pages/campaigns/CampaignUseContext.tsx
+++ /dev/null
@@ -1,14 +0,0 @@
-import { useContext } from 'react';
-
-import {
- CampaignContextProps,
- CampaignMultiStepContext,
-} from '~/pages/campaigns/CampaignContext';
-
-export const useCampaign = (): CampaignContextProps => {
- const context = useContext(CampaignMultiStepContext);
- if (!context) {
- throw new Error('useCampaign must be used within a CampaignProvider');
- }
- return context;
-};
diff --git a/packages/twenty-front/src/pages/campaigns/Campaigns.tsx b/packages/twenty-front/src/pages/campaigns/Campaigns.tsx
deleted file mode 100644
index 0787ac9f9bfc..000000000000
--- a/packages/twenty-front/src/pages/campaigns/Campaigns.tsx
+++ /dev/null
@@ -1,92 +0,0 @@
-import styled from '@emotion/styled';
-
-import { IconTargetArrow } from '@/ui/display/icon';
-import { Modal } from '@/ui/layout/modal/components/Modal';
-import { PageBody } from '@/ui/layout/page/PageBody';
-import { PageContainer } from '@/ui/layout/page/PageContainer';
-import { PageHeader } from '@/ui/layout/page/PageHeader';
-import { StepBar } from '@/ui/navigation/step-bar/components/StepBar';
-import { MOBILE_VIEWPORT } from '@/ui/theme/constants/theme';
-import { CampaignDate } from '~/pages/campaigns/CampaignDate';
-import { CampaignDetails } from '~/pages/campaigns/CampaignDetails';
-import { useCampaign } from '~/pages/campaigns/CampaignUseContext';
-import { Lead } from '~/pages/campaigns/Lead';
-import { MessagingChannel } from '~/pages/campaigns/MessagingChannel';
-import { PreviewPage } from '~/pages/campaigns/PreviewPage';
-import { Specialty } from '~/pages/campaigns/Specialty';
-
-const StyledBoardContainer = styled.div`
- display: flex;
- height: 100%;
- width: 100%;
- flex-direction: column;
- justify-self: center;
-`;
-
-const StyledHeader = styled(Modal.Header)`
- background-color: ${({ theme }) => theme.background.secondary};
- border-bottom: 1px solid ${({ theme }) => theme.border.color.medium};
- height: 60px;
- padding: 0px;
- padding-left: ${({ theme }) => theme.spacing(30)};
- padding-right: ${({ theme }) => theme.spacing(30)};
- @media (max-width: ${MOBILE_VIEWPORT}px) {
- padding-left: ${({ theme }) => theme.spacing(4)};
- padding-right: ${({ theme }) => theme.spacing(4)};
- }
-`;
-
-const StyledCard = styled.div`
- border: 1px solid ${({ theme }) => theme.border.color.medium};
- border-radius: ${({ theme }) => theme.border.radius.sm};
- color: ${({ theme }) => theme.font.color.secondary};
- box-shadow: ${({ theme }) => theme.boxShadow.strong};
- display: flex;
- justify-content: center;
- background: ${({ theme }) => theme.background.noisy};
- height: 100%;
-`;
-export const Campaigns = () => {
- const { currentStep } = useCampaign();
-
- const showCampaignStep = (step: number) => {
- switch (step) {
- case 2:
- return ;
- case 3:
- return ;
- case 4:
- return ;
- case 5:
- return ;
- case 6:
- return ;
- default:
- return ;
- }
- };
-
- return (
- <>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {showCampaignStep(currentStep + 1)}
-
-
-
- >
- );
-};
diff --git a/packages/twenty-front/src/pages/campaigns/Lead.tsx b/packages/twenty-front/src/pages/campaigns/Lead.tsx
deleted file mode 100644
index 6e7386bb8964..000000000000
--- a/packages/twenty-front/src/pages/campaigns/Lead.tsx
+++ /dev/null
@@ -1,115 +0,0 @@
-/* eslint-disable prefer-arrow/prefer-arrow-functions */
-/* eslint-disable no-restricted-imports */
-import { ChangeEvent } from 'react';
-import styled from '@emotion/styled';
-import { IconArrowLeft } from '@tabler/icons-react';
-import { IconArrowRight } from '@tabler/icons-react';
-
-import { Button } from '@/ui/input/button/components/Button';
-import { Section } from '@/ui/layout/section/components/Section';
-import { useCampaign } from '~/pages/campaigns/CampaignUseContext';
-const StyledCard = styled.div`
- border: 1px solid ${({ theme }) => theme.border.color.medium};
- border-radius: ${({ theme }) => theme.border.radius.sm};
- color: ${({ theme }) => theme.font.color.secondary};
- box-shadow: ${({ theme }) => theme.boxShadow.strong};
- display: flex;
- flex-direction: column;
- justify-content: center;
- background: ${({ theme }) => theme.background.primary};
- height: 90%;
- width: 70%;
- margin: auto;
- align-items: center;
-`;
-
-const StyledInputCard = styled.div`
- align-items: center;
- color: ${({ theme }) => theme.font.color.secondary};
- display: flex;
- flex-direction: column;
- height: 50%;
- justify-content: space-evenly;
- width: 70%;
-`;
-
-const StyledTitleCard = styled.div`
- align-items: center;
- color: ${({ theme }) => theme.font.color.secondary};
- display: flex;
- flex-direction: column;
- height: 10%;
- width: 70%;
- justify-content: flex-start;
-`;
-
-const StyledButton = styled.span`
- display: flex;
- justify-content: space-between;
- width: 100%;
-`;
-const StyledLabel = styled.span`
- color: ${({ theme }) => theme.font.color.light};
- font-size: ${({ theme }) => theme.font.size.xs};
- font-weight: ${({ theme }) => theme.font.weight.semiBold};
- margin-bottom: ${({ theme }) => theme.spacing(1)};
- text-transform: uppercase;
- display: flex;
-`;
-
-const StyledCheckboxLabel = styled.span`
- margin-left: ${({ theme }) => theme.spacing(2)};
-`;
-
-const StyledTitle = styled.h3`
- color: ${({ theme }) => theme.font.color.secondary};
- font-weight: ${({ theme }) => theme.font.weight.medium};
- font-size: ${({ theme }) => theme.font.size.md};
-`;
-
-const StyledSection = styled(Section)`
- align-items: flex-start;
- display: flex;
- justify-content: space-between;
- margin-bottom: 16px;
- margin-left: 0;
-`;
-export const Lead = () => {
- const { setCurrentStep, currentStep } = useCampaign();
-
- const onSelectCheckBoxChange = (
- _event: ChangeEvent,
- arg1: string,
- ): void => {
- throw new Error('Function not implemented.');
- };
-
- return (
- <>
-
-
-
-
-
- Lead Extraction
-
- setCurrentStep(currentStep - 1)}
- />
- setCurrentStep(currentStep + 1)}
- />
-
-
-
- >
- );
-};
diff --git a/packages/twenty-front/src/pages/campaigns/MessagingChannel.tsx b/packages/twenty-front/src/pages/campaigns/MessagingChannel.tsx
deleted file mode 100644
index e36555ec5f73..000000000000
--- a/packages/twenty-front/src/pages/campaigns/MessagingChannel.tsx
+++ /dev/null
@@ -1,175 +0,0 @@
-/* eslint-disable prefer-arrow/prefer-arrow-functions */
-/* eslint-disable no-restricted-imports */
-import { ChangeEvent } from 'react';
-import styled from '@emotion/styled';
-import { IconArrowLeft } from '@tabler/icons-react';
-import { IconArrowRight } from '@tabler/icons-react';
-import {
- Checkbox,
- CheckboxShape,
- CheckboxSize,
- CheckboxVariant,
-} from 'tsup.ui.index';
-
-import { Button } from '@/ui/input/button/components/Button';
-import { Section } from '@/ui/layout/section/components/Section';
-import { useCampaign } from '~/pages/campaigns/CampaignUseContext';
-const StyledCard = styled.div`
- border: 1px solid ${({ theme }) => theme.border.color.medium};
- border-radius: ${({ theme }) => theme.border.radius.sm};
- color: ${({ theme }) => theme.font.color.secondary};
- box-shadow: ${({ theme }) => theme.boxShadow.strong};
- display: flex;
- flex-direction: column;
- justify-content: center;
- background: ${({ theme }) => theme.background.primary};
- height: 90%;
- width: 70%;
- margin: auto;
- align-items: center;
-`;
-
-const StyledInputCard = styled.div`
- align-items: center;
- color: ${({ theme }) => theme.font.color.secondary};
- display: flex;
- flex-direction: column;
- height: 50%;
- justify-content: space-evenly;
- width: 70%;
-`;
-
-const StyledTitleCard = styled.div`
- align-items: center;
- color: ${({ theme }) => theme.font.color.secondary};
- display: flex;
- flex-direction: column;
- height: 10%;
- width: 70%;
- justify-content: flex-start;
-`;
-
-const StyledButton = styled.span`
- display: flex;
- justify-content: space-between;
- width: 100%;
-`;
-const StyledLabel = styled.span`
- color: ${({ theme }) => theme.font.color.light};
- font-size: ${({ theme }) => theme.font.size.xs};
- font-weight: ${({ theme }) => theme.font.weight.semiBold};
- margin-bottom: ${({ theme }) => theme.spacing(1)};
- text-transform: uppercase;
- display: flex;
-`;
-
-const StyledCheckboxLabel = styled.span`
- margin-left: ${({ theme }) => theme.spacing(2)};
-`;
-
-const StyledTitle = styled.h3`
- color: ${({ theme }) => theme.font.color.secondary};
- font-weight: ${({ theme }) => theme.font.weight.medium};
- font-size: ${({ theme }) => theme.font.size.md};
-`;
-
-const StyledSection = styled(Section)`
- align-items: flex-start;
- display: flex;
- justify-content: space-between;
- margin-bottom: 16px;
- margin-left: 0;
-`;
-export const MessagingChannel = () => {
- const { setCurrentStep, currentStep } = useCampaign();
-
- const onSelectCheckBoxChange = (
- _event: ChangeEvent,
- arg1: string,
- ): void => {
- throw new Error('Function not implemented.');
- };
-
- return (
- <>
-
-
-
- Deliver your campaign seamlessly across multiple channels with our
- flexible options. Choose the message channels that align with your
- audience's behaviors and preferences.
-
-
-
- Messaging
-
-
- onSelectCheckBoxChange(event, 'SMS')}
- variant={CheckboxVariant.Primary}
- size={CheckboxSize.Small}
- shape={CheckboxShape.Squared}
- />{' '}
- SMS
-
-
-
- onSelectCheckBoxChange(event, 'Whatsapp')}
- variant={CheckboxVariant.Primary}
- size={CheckboxSize.Small}
- shape={CheckboxShape.Squared}
- />
- WhatsApp
-
-
-
- onSelectCheckBoxChange(event, 'GBM')}
- variant={CheckboxVariant.Primary}
- size={CheckboxSize.Small}
- shape={CheckboxShape.Squared}
- />
- GBM
-
-
-
- onSelectCheckBoxChange(event, 'Call')}
- variant={CheckboxVariant.Primary}
- size={CheckboxSize.Small}
- shape={CheckboxShape.Squared}
- />
- CALL
-
-
-
- setCurrentStep(currentStep - 1)}
- />
- setCurrentStep(currentStep + 1)}
- />
-
-
-
- >
- );
-};
diff --git a/packages/twenty-front/src/pages/campaigns/Preview.tsx b/packages/twenty-front/src/pages/campaigns/Preview.tsx
deleted file mode 100644
index 366b0cd7e515..000000000000
--- a/packages/twenty-front/src/pages/campaigns/Preview.tsx
+++ /dev/null
@@ -1,394 +0,0 @@
-/* eslint-disable no-restricted-globals */
-/* eslint-disable @nx/workspace-styled-components-prefixed-with-styled */
-import { useState } from 'react';
-import { useMutation, useQuery } from '@apollo/client';
-import styled from '@emotion/styled';
-import {
- Checkbox,
- CheckboxShape,
- CheckboxSize,
- CheckboxVariant,
- Select,
- TextInput,
-} from 'tsup.ui.index';
-import { v4 as uuidv4 } from 'uuid';
-
-import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer';
-import { IconMail } from '@/ui/display/icon';
-import { H1Title } from '@/ui/display/typography/components/H1Title';
-import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
-import { Button } from '@/ui/input/button/components/Button';
-import DateTimePicker from '@/ui/input/components/internal/date/components/DateTimePicker';
-import { SubMenuTopBarContainer } from '@/ui/layout/page/SubMenuTopBarContainer';
-import { Section } from '@/ui/layout/section/components/Section';
-import { ADD_CAMPAIGN } from '@/users/graphql/queries/addCampaign';
-import { GET_SPECIALTY } from '@/users/graphql/queries/getSpecialtyDetails';
-import { SAVE_SMS_RESPONSE } from '@/users/graphql/queries/saveSmsResponse';
-
-const StyledH1Title = styled(H1Title)`
- margin-bottom: 0;
-`;
-
-const StyledSection = styled(Section)`
- align-items: center;
- display: flex;
- justify-content: space-around;
- margin-bottom: 16px;
- margin-left: 0;
-`;
-
-const SaveButtonContainer = styled.div`
- display: flex;
- justify-content: flex-end;
- width: auto;
-`;
-
-const StyledLabel = styled.span`
- color: ${({ theme }) => theme.font.color.light};
- font-size: ${({ theme }) => theme.font.size.xs};
- font-weight: ${({ theme }) => theme.font.weight.semiBold};
- margin-bottom: ${({ theme }) => theme.spacing(1)};
- text-transform: uppercase;
-`;
-
-const StyledCheckboxLabel = styled.label`
- align-items: center;
- display: flex;
-`;
-
-export const Preview = () => {
- let Specialty: any = [];
-
- const SpecialtyTypes: any = {};
-
- const [campaignName, setCampaignName] = useState('');
- const [description, setDescription] = useState('');
- const [specialty, setSpecialty] = useState('');
- const [subSpecialty, setSubSpecialty] = useState('');
- const [startDate, setStartDate] = useState(new Date());
- const [endDate, setEndDate] = useState(new Date());
- const [selectedMessaging, setSelectedMessaging] = useState(new Set());
- const { loading: queryLoading, data: queryData } = useQuery(GET_SPECIALTY);
-
- const [showSmsInput, setShowSmsInput] = useState(false);
- const [smsMessage, setSmsMessage] = useState('');
-
- if (!queryLoading) {
- const specialtyTypes = queryData?.subspecialties.edges.map(
- (edge: { node: { specialtyType: { name: any } } }) =>
- edge?.node?.specialtyType?.name,
- );
- const uniqueSpecialtyTypes = Array.from(new Set(specialtyTypes));
- Specialty = uniqueSpecialtyTypes.map((specialtyType) => ({
- value: specialtyType,
- label: specialtyType,
- }));
-
- queryData?.subspecialties.edges.forEach(
- (edge: { node: { specialtyType: { name: any }; name: any } }) => {
- const specialtyType = edge.node.specialtyType.name;
- const subSpecialty = edge.node.name;
-
- // If the specialty type is already a key in the dictionary, push the sub-specialty to its array
- if (SpecialtyTypes[specialtyType]) {
- SpecialtyTypes[specialtyType].push({
- value: subSpecialty,
- label: subSpecialty,
- });
- } else {
- // If the specialty type is not yet a key, create a new array with the sub-specialty as its first element
- SpecialtyTypes[specialtyType] = [];
- SpecialtyTypes[specialtyType].push({
- value: subSpecialty,
- label: subSpecialty,
- });
- }
- },
- );
- }
-
- const [addCampaigns, { loading, error }] = useMutation(ADD_CAMPAIGN);
-
- const [saveSmsResponse] = useMutation(SAVE_SMS_RESPONSE);
-
- const { enqueueSnackBar } = useSnackBar();
-
- const handleCampaignChange = (e: any) => {
- setCampaignName(e.target.value);
- };
-
- const handleDescriptionChange = (e: any) => {
- setDescription(e.target.value);
- };
-
- const handleSpecialtySelectChange = (selectedValue: any) => {
- setSpecialty(selectedValue);
- };
-
- const handleSubSpecialtySelectChange = (selectedValue: any) => {
- setSubSpecialty(selectedValue);
- };
-
- const onSelectCheckBoxChange = (event: any, checkedOption: string) => {
- const { checked } = event.target;
- if (checked) {
- setSelectedMessaging(selectedMessaging.add(checkedOption));
- if (checkedOption === 'SMS') {
- setShowSmsInput(true);
- }
- } else {
- selectedMessaging.delete(checkedOption);
- setSelectedMessaging(selectedMessaging);
- if (checkedOption === 'SMS') {
- setShowSmsInput(false);
- }
- }
- };
- const resetCampaignData = () => {
- setCampaignName('');
- setDescription('');
- setStartDate(new Date());
- setSelectedMessaging(new Set());
- setSpecialty('');
- setSubSpecialty('');
- };
- const saveSMSResponse = async (response: any, campaignName: string) => {
- const variables = {
- input: {
- id: uuidv4(),
- campaignName: campaignName,
- sid: response.sid,
- status: response.status,
- dateCreated: response.date_created,
- to: response.to,
- body: response.body,
- },
- };
-
- const { data } = await saveSmsResponse({
- variables: variables,
- });
-
- enqueueSnackBar('SMS response Saved Successfully', {
- variant: 'success',
- });
-
- console.log('ashahsuahsh', data);
- };
- const handleSave = async () => {
- try {
- console.log('Start Date', startDate);
-
- console.log('End Date', endDate);
- const variables = {
- input: {
- id: uuidv4(),
- campaignName: campaignName,
- specialtyType: specialty,
- description: description,
- subSpecialtyType: subSpecialty,
- startDate: startDate,
- endDate: endDate,
- messagingMedia: Array.from(selectedMessaging).join(' '),
- },
- };
- console.log('Variables', variables);
-
- const { data } = await addCampaigns({
- variables: variables,
- });
- enqueueSnackBar('Campaign added successfully', {
- variant: 'success',
- });
-
- const myHeaders = new Headers();
- myHeaders.append('Content-Type', 'application/x-www-form-urlencoded');
- myHeaders.append(
- 'Authorization',
- 'Basic QUM1ZGQxNjZiMDhjN2M3MGQ0YzZjNDM1N2I2OTFkODMwZjo0NDdmZmU0OWU1N2VhZmM4ZmIxNjAxZDNiOGEwMDVjYg==',
- );
-
- const urlencoded = new URLSearchParams();
- enqueueSnackBar('SMS sent successfully', {
- variant: 'success',
- });
- urlencoded.append('To', ' 919108223419');
- urlencoded.append('From', ' 16506035403');
- urlencoded.append('Body', smsMessage);
-
- const requestOptions: Object = {
- method: 'POST',
- headers: myHeaders,
- body: urlencoded,
- redirect: 'follow',
- };
-
- const response: any = await fetch(
- 'https://api.twilio.com/2010-04-01/Accounts/AC5dd166b08c7c70d4c6c4357b691d830f/Messages.json',
- requestOptions,
- ).catch((error) => console.error(error));
- const respData = await response.json();
-
- if (respData.body) {
- enqueueSnackBar('SMS sent successfully', {
- variant: 'success',
- });
-
- await saveSMSResponse(respData, campaignName);
- }
-
- resetCampaignData();
- } catch (errors: any) {
- console.error('Error updating user:', error);
- enqueueSnackBar(errors.message + 'Error while Submitting Campaign', {
- variant: 'error',
- });
- }
- };
- return (
-
-
-
-
- handleCampaignChange(event)}
- placeholder="Campaign Name"
- name="campaignName"
- required
- fullWidth
- />
-
-
- handleDescriptionChange(event)}
- placeholder="Description about campaign"
- name="description"
- required
- fullWidth
- />
-
-
- {specialty && (
-
- )}
-
- Start Date
- setStartDate(startDate)}
- minDate={new Date()}
- />
-
-
- End Date
- setEndDate(endDate)}
- minDate={startDate}
- />
-
-
- Messaging
-
-
- onSelectCheckBoxChange(event, 'SMS')}
- variant={CheckboxVariant.Primary}
- size={CheckboxSize.Small}
- shape={CheckboxShape.Squared}
- />
- SMS
-
-
-
- onSelectCheckBoxChange(event, 'Whatsapp')}
- variant={CheckboxVariant.Primary}
- size={CheckboxSize.Small}
- shape={CheckboxShape.Squared}
- />
- WhastApp
-
-
-
- onSelectCheckBoxChange(event, 'GBM')}
- variant={CheckboxVariant.Primary}
- size={CheckboxSize.Small}
- shape={CheckboxShape.Squared}
- />
- GBM
-
-
-
- onSelectCheckBoxChange(event, 'Call')}
- variant={CheckboxVariant.Primary}
- size={CheckboxSize.Small}
- shape={CheckboxShape.Squared}
- />
- Call
-
-
-
- {showSmsInput && (
-
- SMS Message Body
- setSmsMessage(value)}
- placeholder="Enter SMS message body"
- fullWidth
- />
-
- )}
-
-
-
- handleSave()}
- />
-
-
-
- );
-};
diff --git a/packages/twenty-front/src/pages/campaigns/PreviewPage.tsx b/packages/twenty-front/src/pages/campaigns/PreviewPage.tsx
deleted file mode 100644
index c93ca43e0de5..000000000000
--- a/packages/twenty-front/src/pages/campaigns/PreviewPage.tsx
+++ /dev/null
@@ -1,118 +0,0 @@
-/* eslint-disable prefer-arrow/prefer-arrow-functions */
-/* eslint-disable no-restricted-imports */
-import { ChangeEvent } from 'react';
-import styled from '@emotion/styled';
-import { IconArrowLeft } from '@tabler/icons-react';
-import { IconArrowRight } from '@tabler/icons-react';
-
-import { Button } from '@/ui/input/button/components/Button';
-import { Section } from '@/ui/layout/section/components/Section';
-import { useCampaign } from '~/pages/campaigns/CampaignUseContext';
-const StyledCard = styled.div`
- border: 1px solid ${({ theme }) => theme.border.color.medium};
- border-radius: ${({ theme }) => theme.border.radius.sm};
- color: ${({ theme }) => theme.font.color.secondary};
- box-shadow: ${({ theme }) => theme.boxShadow.strong};
- display: flex;
- flex-direction: column;
- justify-content: center;
- background: ${({ theme }) => theme.background.primary};
- height: 90%;
- width: 70%;
- margin: auto;
- align-items: center;
-`;
-
-const StyledInputCard = styled.div`
- align-items: center;
- color: ${({ theme }) => theme.font.color.secondary};
- display: flex;
- flex-direction: column;
- height: 50%;
- justify-content: space-evenly;
- width: 70%;
-`;
-
-const StyledTitleCard = styled.div`
- align-items: center;
- color: ${({ theme }) => theme.font.color.secondary};
- display: flex;
- flex-direction: column;
- height: 10%;
- width: 70%;
- justify-content: flex-start;
-`;
-
-const StyledButton = styled.span`
- display: flex;
- justify-content: space-between;
- width: 100%;
-`;
-const StyledLabel = styled.span`
- color: ${({ theme }) => theme.font.color.light};
- font-size: ${({ theme }) => theme.font.size.xs};
- font-weight: ${({ theme }) => theme.font.weight.semiBold};
- margin-bottom: ${({ theme }) => theme.spacing(1)};
- text-transform: uppercase;
- display: flex;
-`;
-
-const StyledCheckboxLabel = styled.span`
- margin-left: ${({ theme }) => theme.spacing(2)};
-`;
-
-const StyledTitle = styled.h3`
- color: ${({ theme }) => theme.font.color.secondary};
- font-weight: ${({ theme }) => theme.font.weight.medium};
- font-size: ${({ theme }) => theme.font.size.md};
-`;
-
-const StyledSection = styled(Section)`
- align-items: flex-start;
- display: flex;
- justify-content: space-between;
- margin-bottom: 16px;
- margin-left: 0;
-`;
-export const PreviewPage = () => {
- const { setCurrentStep, currentStep } = useCampaign();
-
- const onSelectCheckBoxChange = (
- _event: ChangeEvent,
- arg1: string,
- ): void => {
- throw new Error('Function not implemented.');
- };
-
- return (
- <>
-
-
-
- Deliver your campaign seamlessly across multiple channels with our
- flexible options. Choose the message channels that align with your
- audience's behaviors and preferences.
-
-
-
- Preview
-
- setCurrentStep(currentStep - 1)}
- />
-
-
-
-
- >
- );
-};
diff --git a/packages/twenty-front/src/pages/campaigns/Specialty.tsx b/packages/twenty-front/src/pages/campaigns/Specialty.tsx
deleted file mode 100644
index c550a421d0b6..000000000000
--- a/packages/twenty-front/src/pages/campaigns/Specialty.tsx
+++ /dev/null
@@ -1,171 +0,0 @@
-/* eslint-disable no-restricted-imports */
-import { useState } from 'react';
-import { useQuery } from '@apollo/client';
-import styled from '@emotion/styled';
-import { IconArrowLeft } from '@tabler/icons-react';
-import { IconArrowRight } from '@tabler/icons-react';
-
-import { Button } from '@/ui/input/button/components/Button';
-import { Select } from '@/ui/input/components/Select';
-import { Section } from '@/ui/layout/section/components/Section';
-import { GET_SPECIALTY } from '@/users/graphql/queries/getSpecialtyDetails';
-import { useCampaign } from '~/pages/campaigns/CampaignUseContext';
-
-const StyledCard = styled.div`
- border: 1px solid ${({ theme }) => theme.border.color.medium};
- border-radius: ${({ theme }) => theme.border.radius.sm};
- color: ${({ theme }) => theme.font.color.secondary};
- box-shadow: ${({ theme }) => theme.boxShadow.strong};
- display: flex;
- flex-direction: column;
- justify-content: center;
- background: ${({ theme }) => theme.background.primary};
- height: 90%;
- width: 70%;
- margin: auto;
- align-items: center;
-`;
-
-const StyledInputCard = styled.div`
- color: ${({ theme }) => theme.font.color.secondary};
- display: flex;
- flex-direction: column;
- justify-content: center;
- height: 50%;
- justify-content: space-evenly;
- width: 70%;
- align-items: center;
-`;
-
-const StyledTitleCard = styled.div`
- align-items: center;
- color: ${({ theme }) => theme.font.color.secondary};
- display: flex;
- flex-direction: column;
- height: 10%;
- width: 70%;
- justify-content: flex-start;
-`;
-
-const StyledButton = styled.span`
- display: flex;
- justify-content: space-between;
- width: 100%;
-`;
-const StyledLabel = styled.span`
- color: ${({ theme }) => theme.font.color.light};
- font-size: ${({ theme }) => theme.font.size.xs};
- font-weight: ${({ theme }) => theme.font.weight.semiBold};
- margin-bottom: ${({ theme }) => theme.spacing(1)};
- text-transform: uppercase;
-`;
-
-const StyledTitle = styled.h3`
- color: ${({ theme }) => theme.font.color.secondary};
- font-weight: ${({ theme }) => theme.font.weight.medium};
- font-size: ${({ theme }) => theme.font.size.md};
-`;
-export const Specialty = () => {
- const { setCurrentStep, currentStep } = useCampaign();
-
- let Specialty: any = [];
- const SpecialtyTypes: any = {};
- const [specialty, setSpecialty] = useState('');
- const [subSpecialty, setSubSpecialty] = useState('');
- const { loading: queryLoading, data: queryData } = useQuery(GET_SPECIALTY);
-
- if (!queryLoading) {
- const specialtyTypes = queryData?.subspecialties.edges.map(
- (edge: { node: { specialtyType: { name: any } } }) =>
- edge?.node?.specialtyType?.name,
- );
- const uniqueSpecialtyTypes = Array.from(new Set(specialtyTypes));
- Specialty = uniqueSpecialtyTypes.map((specialtyType) => ({
- value: specialtyType,
- label: specialtyType,
- }));
-
- queryData?.subspecialties.edges.forEach(
- (edge: { node: { specialtyType: { name: any }; name: any } }) => {
- const specialtyType = edge.node.specialtyType.name;
- const subSpecialty = edge.node.name;
-
- // If the specialty type is already a key in the dictionary, push the sub-specialty to its array
- if (SpecialtyTypes[specialtyType]) {
- SpecialtyTypes[specialtyType].push({
- value: subSpecialty,
- label: subSpecialty,
- });
- } else {
- // If the specialty type is not yet a key, create a new array with the sub-specialty as its first element
- SpecialtyTypes[specialtyType] = [];
- SpecialtyTypes[specialtyType].push({
- value: subSpecialty,
- label: subSpecialty,
- });
- }
- },
- );
- }
-
- const handleSpecialtySelectChange = (selectedValue: any) => {
- setSpecialty(selectedValue);
- };
-
- const handleSubSpecialtySelectChange = (selectedValue: any) => {
- setSubSpecialty(selectedValue);
- };
- return (
- <>
-
-
-
- Select from a variety of specialties and sub-specialties to
- customize your campaign and target specific segments of your
- audience with precision.
-
-
-
-
- {specialty && (
-
- )}
-
- setCurrentStep(currentStep - 1)}
- />
- setCurrentStep(currentStep + 1)}
- />
-
-
-
- >
- );
-};
From 22668cdee054a8ecf39810b869090d021926a065 Mon Sep 17 00:00:00 2001
From: sanjana0190 <56463647+sanjana0190@users.noreply.github.com>
Date: Thu, 2 May 2024 20:24:28 +0530
Subject: [PATCH 021/122] Synced Main Branch Changes with Feature/Template
---
packages/twenty-front/src/App.tsx | 16 +
packages/twenty-front/src/index.tsx | 3 +
.../activities/Leads/components/Leads.tsx | 401 ++++++++++++++
.../Schedule/components/schedule.tsx | 199 +++++++
.../formTemplate/components/formTemplate.tsx | 142 +++++
.../components/messageTemplate.tsx | 130 +++++
.../RecordDetailRelationRecordsListItem.tsx | 33 +-
.../src/modules/types/CustomPath.ts | 10 +
.../date/components/DateTimePicker.tsx | 7 +-
.../ui/layout/page/RunCampaignButton.tsx | 18 +
.../components/ShowPageRightContainer.tsx | 151 ++++--
.../users/graphql/queries/addCampaign.ts | 103 +---
.../users/graphql/queries/addSegment.ts | 7 +
.../queries/addTriggerCampaignRecord.ts | 9 +
.../users/graphql/queries/filterLeads.ts | 30 ++
.../users/graphql/queries/getCampaignList.ts | 51 ++
.../users/graphql/queries/getFormTemplates.ts | 27 +
.../graphql/queries/getMessageTemplates.ts | 295 +++++++++++
.../graphql/queries/getOneCampaignTrigger.ts | 360 +++++++++++++
.../users/graphql/queries/getSegments.ts | 28 +
.../graphql/queries/getSpecialtyDetails.ts | 38 +-
.../queries/updateCampaignlistStatus.ts | 9 +
.../graphql/queries/updateLastExecutionId.ts | 9 +
.../src/pages/Segment/Segment.tsx | 343 ++++++++++++
.../src/pages/campaigns/CampaignContext.tsx | 64 +++
.../src/pages/campaigns/CampaignDate.tsx | 125 +++++
.../src/pages/campaigns/CampaignDetails.tsx | 143 +++++
.../src/pages/campaigns/CampaignForm.tsx | 354 +++++++++++++
.../src/pages/campaigns/CampaignForm2.tsx | 324 ++++++++++++
.../src/pages/campaigns/CampaignForm3.tsx | 403 ++++++++++++++
.../pages/campaigns/CampaignUseContext.tsx | 14 +
.../src/pages/campaigns/Campaigns.tsx | 488 +++++++++++++++++
.../src/pages/campaigns/Form1.tsx | 221 ++++++++
.../src/pages/campaigns/Form2.tsx | 223 ++++++++
.../src/pages/campaigns/Form3.tsx | 323 ++++++++++++
.../twenty-front/src/pages/campaigns/Lead.tsx | 490 ++++++++++++++++++
.../src/pages/campaigns/LeadsPreviewPage.tsx | 81 +++
.../src/pages/campaigns/MessagingChannel.tsx | 225 ++++++++
.../src/pages/campaigns/Preview.tsx | 394 ++++++++++++++
.../pages/campaigns/PreviewCampaignDate.tsx | 38 ++
.../campaigns/PreviewCampaignDetailsTab.tsx | 60 +++
.../src/pages/campaigns/PreviewLeadsData.tsx | 111 ++++
.../campaigns/PreviewMessagingChannel.tsx | 54 ++
.../src/pages/campaigns/PreviewPage.tsx | 160 ++++++
.../src/pages/campaigns/PreviewSpecialty.tsx | 56 ++
.../src/pages/campaigns/Specialty.tsx | 178 +++++++
.../object-record/RecordIndexPageHeader.tsx | 25 +-
.../pages/object-record/RecordShowPage.tsx | 130 ++++-
48 files changed, 6933 insertions(+), 170 deletions(-)
create mode 100644 packages/twenty-front/src/modules/activities/Leads/components/Leads.tsx
create mode 100644 packages/twenty-front/src/modules/activities/Schedule/components/schedule.tsx
create mode 100644 packages/twenty-front/src/modules/activities/formTemplate/components/formTemplate.tsx
create mode 100644 packages/twenty-front/src/modules/activities/messageTemplate/components/messageTemplate.tsx
create mode 100644 packages/twenty-front/src/modules/ui/layout/page/RunCampaignButton.tsx
create mode 100644 packages/twenty-front/src/modules/users/graphql/queries/addSegment.ts
create mode 100644 packages/twenty-front/src/modules/users/graphql/queries/addTriggerCampaignRecord.ts
create mode 100644 packages/twenty-front/src/modules/users/graphql/queries/filterLeads.ts
create mode 100644 packages/twenty-front/src/modules/users/graphql/queries/getCampaignList.ts
create mode 100644 packages/twenty-front/src/modules/users/graphql/queries/getFormTemplates.ts
create mode 100644 packages/twenty-front/src/modules/users/graphql/queries/getMessageTemplates.ts
create mode 100644 packages/twenty-front/src/modules/users/graphql/queries/getOneCampaignTrigger.ts
create mode 100644 packages/twenty-front/src/modules/users/graphql/queries/getSegments.ts
create mode 100644 packages/twenty-front/src/modules/users/graphql/queries/updateCampaignlistStatus.ts
create mode 100644 packages/twenty-front/src/modules/users/graphql/queries/updateLastExecutionId.ts
create mode 100644 packages/twenty-front/src/pages/Segment/Segment.tsx
create mode 100644 packages/twenty-front/src/pages/campaigns/CampaignContext.tsx
create mode 100644 packages/twenty-front/src/pages/campaigns/CampaignDate.tsx
create mode 100644 packages/twenty-front/src/pages/campaigns/CampaignDetails.tsx
create mode 100644 packages/twenty-front/src/pages/campaigns/CampaignForm.tsx
create mode 100644 packages/twenty-front/src/pages/campaigns/CampaignForm2.tsx
create mode 100644 packages/twenty-front/src/pages/campaigns/CampaignForm3.tsx
create mode 100644 packages/twenty-front/src/pages/campaigns/CampaignUseContext.tsx
create mode 100644 packages/twenty-front/src/pages/campaigns/Campaigns.tsx
create mode 100644 packages/twenty-front/src/pages/campaigns/Form1.tsx
create mode 100644 packages/twenty-front/src/pages/campaigns/Form2.tsx
create mode 100644 packages/twenty-front/src/pages/campaigns/Form3.tsx
create mode 100644 packages/twenty-front/src/pages/campaigns/Lead.tsx
create mode 100644 packages/twenty-front/src/pages/campaigns/LeadsPreviewPage.tsx
create mode 100644 packages/twenty-front/src/pages/campaigns/MessagingChannel.tsx
create mode 100644 packages/twenty-front/src/pages/campaigns/Preview.tsx
create mode 100644 packages/twenty-front/src/pages/campaigns/PreviewCampaignDate.tsx
create mode 100644 packages/twenty-front/src/pages/campaigns/PreviewCampaignDetailsTab.tsx
create mode 100644 packages/twenty-front/src/pages/campaigns/PreviewLeadsData.tsx
create mode 100644 packages/twenty-front/src/pages/campaigns/PreviewMessagingChannel.tsx
create mode 100644 packages/twenty-front/src/pages/campaigns/PreviewPage.tsx
create mode 100644 packages/twenty-front/src/pages/campaigns/PreviewSpecialty.tsx
create mode 100644 packages/twenty-front/src/pages/campaigns/Specialty.tsx
diff --git a/packages/twenty-front/src/App.tsx b/packages/twenty-front/src/App.tsx
index 8b39526735ac..8a99fa82757a 100644
--- a/packages/twenty-front/src/App.tsx
+++ b/packages/twenty-front/src/App.tsx
@@ -52,6 +52,12 @@ import { SettingsWorkspace } from '~/pages/settings/SettingsWorkspace';
import { SettingsWorkspaceMembers } from '~/pages/settings/SettingsWorkspaceMembers';
import { Tasks } from '~/pages/tasks/Tasks';
import { getPageTitleFromPath } from '~/utils/title-utils';
+import { CustomPath } from '@/types/CustomPath';
+import { CampaignForm } from '~/pages/campaigns/CampaignForm';
+import { CampaignForm2 } from '~/pages/campaigns/CampaignForm2';
+import { CampaignForm3 } from '~/pages/campaigns/CampaignForm3';
+import { Campaigns } from '~/pages/campaigns/Campaigns';
+import { Segment } from '~/pages/Segment/Segment';
export const App = () => {
const billing = useRecoilValue(billingState);
@@ -215,6 +221,16 @@ export const App = () => {
}>
} />
+
+
+ } />
+ } />
+ } />
+ } />
+
+
+ } />
+
>
);
diff --git a/packages/twenty-front/src/index.tsx b/packages/twenty-front/src/index.tsx
index 7894a3a6a562..89af1e63ea22 100644
--- a/packages/twenty-front/src/index.tsx
+++ b/packages/twenty-front/src/index.tsx
@@ -32,6 +32,7 @@ import { App } from './App';
import './index.css';
import 'react-loading-skeleton/dist/skeleton.css';
+import CampaignContext from '~/pages/campaigns/CampaignContext';
const root = ReactDOM.createRoot(
document.getElementById('root') ?? document.body,
@@ -60,10 +61,12 @@ root.render(
+
+
diff --git a/packages/twenty-front/src/modules/activities/Leads/components/Leads.tsx b/packages/twenty-front/src/modules/activities/Leads/components/Leads.tsx
new file mode 100644
index 000000000000..2bf4dda47112
--- /dev/null
+++ b/packages/twenty-front/src/modules/activities/Leads/components/Leads.tsx
@@ -0,0 +1,401 @@
+import { useEffect, useState } from 'react';
+import styled from '@emotion/styled';
+import { ActivityTargetableObject } from '@/activities/types/ActivityTargetableEntity';
+import { GET_CAMPAIGN_LISTS } from '@/users/graphql/queries/getCampaignList';
+import { GET_CAMPAIGN_TRIGGER } from '@/users/graphql/queries/getOneCampaignTrigger';
+import { useLazyQuery } from '@apollo/client';
+import { FILTER_LEADS } from '@/users/graphql/queries/filterLeads';
+import { Checkbox } from '@/ui/input/components/Checkbox';
+import { capitalize } from '~/utils/string/capitalize';
+import { useCampaign } from '~/pages/campaigns/CampaignUseContext';
+import { formatToHumanReadableDate } from '~/utils';
+import { EllipsisDisplay } from '@/ui/field/display/components/EllipsisDisplay';
+import { DateDisplay } from '@/ui/field/display/components/DateDisplay';
+import { NumberDisplay } from '@/ui/field/display/components/NumberDisplay';
+import { TextFieldDisplay } from '@/object-record/record-field/meta-types/display/components/TextFieldDisplay';
+import { useGetIsSomeCellInEditModeState } from '@/object-record/record-table/hooks/internal/useGetIsSomeCellInEditMode';
+import { useMoveSoftFocusToCurrentCellOnHover } from '@/object-record/record-table/record-table-cell/hooks/useMoveSoftFocusToCurrentCellOnHover';
+import { isSoftFocusUsingMouseState } from '@/object-record/record-table/states/isSoftFocusUsingMouseState';
+import { useRecoilValue, useSetRecoilState } from 'recoil';
+import {
+ IconRefresh,
+ IconUser,
+ IconListNumbers,
+ IconLocation,
+ IconBrandCampaignmonitor,
+ IconDeviceTv,
+ IconSpeakerphone,
+ IconTextCaption,
+ IconCalendar,
+ IconNumbers,
+} from '@tabler/icons-react';
+import { IconButton } from '@/ui/input/button/components/IconButton';
+import { TextDisplay } from '@/ui/field/display/components/TextDisplay';
+
+const StyledInputCard = styled.div`
+ align-items: flex-start;
+ display: flex;
+ flex-direction: column;
+ height: auto%;
+ justify-content: space-evenly;
+ width: 100%;
+`;
+
+const StyledButtonContainer = styled.div`
+ display: inline-flex;
+ justify-content: flex-end;
+ margin-top: ${({ theme }) => theme.spacing(2)};
+`;
+
+const StyledCountContainer = styled.div`
+ display: flex;
+ flex-direction: row;
+ > * + * {
+ margin-left: ${({ theme }) => theme.spacing(10)};
+ }
+ margin-top: ${({ theme }) => theme.spacing(2)};
+ margin-bottom: ${({ theme }) => theme.spacing(6)};
+ height: auto;
+ justify-content: flex-start;
+ width: 100%;
+ align-items: center;
+`;
+
+const StyledTable = styled.table<{ cursorPointer: boolean }>`
+ width: 100%;
+ border-collapse: collapse;
+ height: 10px;
+ margin-bottom: ${({ theme }) => theme.spacing(6)};
+ background-color: ${({ theme }) => theme.background.primary};
+ cursor: ${({ cursorPointer }) => (cursorPointer ? 'pointer' : 'inherit')};
+ font-family: inherit;
+ font-size: inherit;
+
+ font-weight: ${({ theme }) => theme.font.weight.regular};
+ max-width: 100%;
+ overflow: hidden;
+ text-decoration: inherit;
+
+ text-overflow: ellipsis;
+ white-space: nowrap;
+`;
+
+const StyledTableRow = styled.tr`
+ &:nth-of-type(odd) {
+ background-color: ${({ theme }) => theme.background.primary};
+ }
+`;
+
+const StyledTableCell = styled.td`
+ padding: 5px;
+ height: 25px;
+ border: 1px solid ${({ theme }) => theme.border.color.light};
+ font-weight: ${({ theme }) => theme.font.weight.regular};
+ &:hover {
+ background-color: ${({ theme }) => theme.background.tertiary};
+ }
+`;
+
+const StyledTableHeaderCell = styled.td`
+ padding: 5px;
+ border: 1px solid ${({ theme }) => theme.border.color.medium};
+ height: 25px;
+`;
+
+const StyledComboInputContainer = styled.div`
+ display: flex;
+ align-items: center;
+ > * + * {
+ margin-left: ${({ theme }) => theme.spacing(2)};
+ }
+`;
+
+const StyledContainer = styled.div`
+ align-items: flex-start;
+ align-self: stretch;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+`;
+
+const StyledLabelContainer = styled.div`
+ color: ${({ theme }) => theme.font.color.tertiary};
+ width: auto;
+`;
+
+export const Leads = ({
+ targetableObject,
+}: {
+ targetableObject: ActivityTargetableObject;
+}) => {
+ const fields = [
+ { name: 'name', icon: IconUser },
+ { name: 'age', icon: IconListNumbers },
+ { name: 'location', icon: IconLocation },
+ { name: 'advertisementSource', icon: IconBrandCampaignmonitor },
+ { name: 'advertisementName', icon: IconDeviceTv },
+ { name: 'campaignName', icon: IconSpeakerphone },
+ { name: 'comments', icon: IconTextCaption },
+ { name: 'createdAt', icon: IconCalendar },
+ ];
+
+ const [leadsData, setLeadsData] = useState([]);
+ const [totalLeadsCount, setTotalLeadsCount] = useState(0);
+ const [selectedRows, setSelectedRows] = useState<{ [key: string]: boolean }>(
+ {},
+ );
+ const [pageSize, setPageSize] = useState(10);
+ const [cursor, setCursor] = useState(null);
+ const [unSelectedRows, setunSelectedRows] = useState<{
+ [key: string]: boolean;
+ }>({});
+ const [masterCheckboxChecked, setMasterCheckboxChecked] = useState(true);
+
+ const { campaignData, setCampaignData } = useCampaign();
+
+ let [selectedCampaign, { data: selectedCampaignData }] =
+ useLazyQuery(GET_CAMPAIGN_LISTS, {
+ fetchPolicy: 'network-only',
+ });
+
+ let [selectedCampaignTrigger, { data: selectedCampaignTriggerData }] =
+ useLazyQuery(GET_CAMPAIGN_TRIGGER, {
+ fetchPolicy: 'network-only',
+ });
+
+ let [filterleads, { data: filterLeadsData }] = useLazyQuery(FILTER_LEADS, {
+ fetchPolicy: 'network-only',
+ onCompleted: (data) => {
+ setLeadsData(data);
+ },
+ });
+
+ useEffect(() => {
+ if (leadsData.leads && leadsData.leads.edges) {
+ const allLeadIds = leadsData.leads.edges.map(
+ (leadEdge: any) => leadEdge.node.id,
+ );
+ const initialSelectedRows: { [key: string]: boolean } = {};
+ const initialUnSelectedRows: { [key: string]: boolean } = {};
+ allLeadIds.forEach((leadId: string) => {
+ initialSelectedRows[leadId] = true;
+ });
+ setSelectedRows(initialSelectedRows);
+ setunSelectedRows(initialUnSelectedRows);
+ }
+ }, [leadsData]);
+
+ const handleCheckboxChange = (leadId: string) => {
+ const updatedSelectedRows = { ...selectedRows };
+ updatedSelectedRows[leadId] = !updatedSelectedRows[leadId];
+
+ const updatedUnSelectedRows = { ...unSelectedRows };
+ if (!updatedSelectedRows[leadId]) {
+ updatedUnSelectedRows[leadId] = true;
+ delete updatedSelectedRows[leadId];
+ } else {
+ delete updatedUnSelectedRows[leadId];
+ }
+
+ const selectedLeadIds = Object.keys(updatedSelectedRows);
+ const unSelectedLeadIds = Object.keys(updatedUnSelectedRows);
+
+ setCampaignData({
+ ...campaignData,
+ selectedId: selectedLeadIds,
+ unSelectedId: unSelectedLeadIds,
+ });
+
+ setSelectedRows(updatedSelectedRows);
+ setunSelectedRows(updatedUnSelectedRows);
+ };
+
+ const handleMasterCheckboxChange = () => {
+ const updatedSelectedRows: { [key: string]: boolean } = {};
+ const updatedUnSelectedRows: { [key: string]: boolean } = {};
+ if (!masterCheckboxChecked) {
+ leadsData?.leads?.edges.forEach((leadEdge: any) => {
+ const lead = leadEdge?.node;
+ updatedSelectedRows[lead.id] = true;
+ });
+ } else {
+ leadsData?.leads?.edges.forEach((leadEdge: any) => {
+ const lead = leadEdge?.node;
+ updatedUnSelectedRows[lead.id] = true;
+ });
+ }
+
+ const selectedLeadIds = Object.keys(updatedSelectedRows);
+ const unSelectedLeadIds = Object.keys(updatedUnSelectedRows);
+
+ setCampaignData({
+ ...campaignData,
+ selectedId: selectedLeadIds,
+ unSelectedId: unSelectedLeadIds,
+ });
+
+ setSelectedRows(updatedSelectedRows);
+ setunSelectedRows(updatedUnSelectedRows);
+ setMasterCheckboxChecked(!masterCheckboxChecked);
+ };
+ let campaignId = "";
+
+ const fetchLeads = async () => {
+ try {
+ if(targetableObject.targetObjectNameSingular === 'campaignTrigger'){
+ const data = await selectedCampaignTrigger({
+ variables: {
+ objectRecordId: targetableObject.id ,
+ },
+ });
+
+ campaignId = data.data.campaignTrigger.campaignId;
+ console.log(campaignId, "campaignId")
+ }
+ else if(targetableObject.targetObjectNameSingular === 'campaign'){
+ campaignId = targetableObject.id
+ }
+
+ const data = await selectedCampaign({
+ variables: {
+ filter: {
+ id: { eq: campaignId },
+ },
+ },
+ });
+
+ const filter = JSON.parse(
+ data.data.campaigns.edges[0].node.segment.filters,
+ );
+
+ const result = await filterleads({ variables: filter });
+ const leadsCount = result.data?.leads?.totalCount || 0;
+ setTotalLeadsCount(leadsCount);
+ setLeadsData(result.data);
+ const currentTime = new Date().toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });
+ const currentDate = formatToHumanReadableDate(new Date());
+ const querystamp = `${currentDate} ${currentTime}`;
+ setCampaignData({
+ ...campaignData,
+ querystamp: querystamp,
+ });
+ } catch (error) {
+ console.error('Error fetching campaign segment filter:', error);
+ }
+ };
+
+ useEffect(() => {
+ fetchLeads();
+ }, [targetableObject.id, selectedCampaign]);
+
+ const handleLoadMore = () => {
+ if (
+ leadsData?.leads?.pageInfo?.hasNextPage &&
+ leadsData?.leads?.pageInfo?.endCursor
+ ) {
+ setCursor(leadsData.leads.pageInfo.endCursor);
+ }
+ };
+ return (
+ <>
+
+
+
+ {leadsData?.leads?.pageInfo?.hasNextPage && (
+
+
+
+ )}
+
+
+
+ {leadsData?.leads?.edges[0] && (
+ <>
+
+
+
+ Leads fetched at:
+
+
+
+
+
+ Total Leads:
+
+ {' '}
+
+
+
+
+ Selected Leads:
+
+
+
+
+
+
+ Unselected Leads:
+
+
+
+
+
+
+
+
+
+
+
+
+ {fields.map(({ name, icon: Icon }) => (
+
+
+ {Icon && }
+ {capitalize(name)}
+
+
+ ))}
+
+ {leadsData?.leads?.edges.map((leadEdge: any) => {
+ const lead = leadEdge?.node;
+ return (
+ handleCheckboxChange(lead.id)}
+ >
+
+ handleCheckboxChange(lead.id)}
+ />
+
+ {fields.map(({ name }) => (
+
+
+ {lead[name].toString()}
+
+
+ ))}
+
+ );
+ })}
+
+
+ >
+ )}
+
+
+ >
+ );
+};
diff --git a/packages/twenty-front/src/modules/activities/Schedule/components/schedule.tsx b/packages/twenty-front/src/modules/activities/Schedule/components/schedule.tsx
new file mode 100644
index 000000000000..286e4d45d759
--- /dev/null
+++ b/packages/twenty-front/src/modules/activities/Schedule/components/schedule.tsx
@@ -0,0 +1,199 @@
+import { useState } from 'react';
+import styled from '@emotion/styled';
+import { ActivityTargetableObject } from '@/activities/types/ActivityTargetableEntity';
+import { useCampaign } from '~/pages/campaigns/CampaignUseContext';
+import {
+ Checkbox,
+ CheckboxShape,
+ CheckboxSize,
+ CheckboxVariant,
+} from '@/ui/input/components/Checkbox';
+import DateTimePicker from '@/ui/input/components/internal/date/components/DateTimePicker';
+import { IconCalendar } from '@tabler/icons-react';
+
+const StyledContainer = styled.div`
+ align-items: flex-start;
+ align-self: stretch;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ padding: 8px 24px;
+`;
+
+const StyledTitleBar = styled.div`
+ display: flex;
+ justify-content: space-between;
+ margin-bottom: ${({ theme }) => theme.spacing(4)};
+ margin-top: ${({ theme }) => theme.spacing(4)};
+ place-items: center;
+ width: 100%;
+`;
+
+const StyledTitle = styled.h3`
+ color: ${({ theme }) => theme.font.color.primary};
+ font-weight: ${({ theme }) => theme.font.weight.medium};
+ font-size:${({ theme }) => theme.font.size.md}
+`;
+
+const StyledScheduleTitle = styled.h3`
+ color: ${({ theme }) => theme.font.color.primary};
+ font-weight: ${({ theme }) => theme.font.weight.medium};
+ font-size:${({ theme }) => theme.font.size.xs}
+`;
+
+const StyledTaskRows = styled.div`
+ background-color: ${({ theme }) => theme.background.secondary};
+ border: 1px solid ${({ theme }) => theme.border.color.light};
+ border-radius: ${({ theme }) => theme.border.radius.md};
+ width: 100%;
+`;
+
+const StyledComboInputContainer = styled.div`
+ display: flex;
+ align-items: center;
+ align-self: center;
+ justify-content: start;
+ margin: ${({ theme }) => theme.spacing(10)};
+`;
+
+const StyledLabel = styled.span`
+ color: ${({ theme }) => theme.font.color.tertiary};
+ font-size: ${({ theme }) => theme.font.size.xs};
+ font-weight: ${({ theme }) => theme.font.weight.semiBold};
+ margin-left: ${({ theme }) => theme.spacing(2)};
+ margin-right: ${({ theme }) => theme.spacing(6)};
+ display: flex;
+ align-items: center;
+`;
+
+const StyledCheckboxLabel = styled.span`
+ margin-left: ${({ theme }) => theme.spacing(2)};
+`;
+
+const StyledCount = styled.span`
+ color: ${({ theme }) => theme.font.color.light};
+ margin-left: ${({ theme }) => theme.spacing(2)};
+`;
+
+export const Schedule = ({
+ targetableObject,
+}: {
+ targetableObject: ActivityTargetableObject;
+}) => {
+ const [showStartDateTimePicker, setShowStartDateTimePicker] = useState(false);
+ const [showStopDateTimePicker, setShowStopDateTimePicker] = useState(false);
+ const [startDate, setStartDate] = useState(null);
+ const [stopDate, setStopDate] = useState(null);
+ const { campaignData, setCampaignData } = useCampaign();
+
+ const handleStartCheckboxChange = (event: React.ChangeEvent) => {
+ const currentDate = new Date();
+ setStartDate(currentDate);
+ setCampaignData({
+ ...campaignData,
+ startDate: currentDate,
+ });
+ };
+
+ const handleStopCheckboxChange = (event: React.ChangeEvent) => {
+ const currentDate = new Date();
+ setStopDate(currentDate);
+ setCampaignData({
+ ...campaignData,
+ endDate: currentDate,
+ });
+ };
+ return (
+
+
+ {/*
+ This Campaign was run4 times.
+ */}
+
+
+ Start
+
+
+
+
+ Immediately
+
+
+ setShowStartDateTimePicker(!showStartDateTimePicker)
+ }
+ indeterminate={false}
+ variant={CheckboxVariant.Primary}
+ size={CheckboxSize.Small}
+ shape={CheckboxShape.Squared}
+ />
+
+ Start Date/Time
+
+ {showStartDateTimePicker && (
+
+ setCampaignData({
+ ...campaignData,
+ startDate: selectedDate,
+ })
+ }
+ minDate={new Date()}
+ value={undefined}
+ />
+ )}
+
+
+
+ Stop
+
+
+
+
+ Immediately
+
+
+ setShowStopDateTimePicker(!showStopDateTimePicker)
+ }
+ indeterminate={false}
+ variant={CheckboxVariant.Primary}
+ size={CheckboxSize.Small}
+ shape={CheckboxShape.Squared}
+ />
+
+ Stop Date/Time
+
+ {showStopDateTimePicker && (
+
+ setCampaignData({
+ ...campaignData,
+ endDate: selectedDate,
+ })
+ }
+ minDate={new Date()}
+ value={undefined}
+ />
+ )}
+
+
+
+ );
+};
diff --git a/packages/twenty-front/src/modules/activities/formTemplate/components/formTemplate.tsx b/packages/twenty-front/src/modules/activities/formTemplate/components/formTemplate.tsx
new file mode 100644
index 000000000000..3fc06648327f
--- /dev/null
+++ b/packages/twenty-front/src/modules/activities/formTemplate/components/formTemplate.tsx
@@ -0,0 +1,142 @@
+import { useEffect, useState } from 'react';
+import styled from '@emotion/styled';
+import { ActivityTargetableObject } from '@/activities/types/ActivityTargetableEntity';
+import { useLazyQuery } from '@apollo/client';
+import { GET_CAMPAIGN_LISTS } from '@/users/graphql/queries/getCampaignList';
+import { Form1 } from '~/pages/campaigns/Form1';
+import { Form2 } from '~/pages/campaigns/Form2';
+import { Form3 } from '~/pages/campaigns/Form3';
+import { EllipsisDisplay } from '@/ui/field/display/components/EllipsisDisplay';
+import { TextDisplay } from '@/ui/field/display/components/TextDisplay';
+import { DateDisplay } from '@/ui/field/display/components/DateDisplay';
+import { GET_CAMPAIGN_TRIGGER } from '@/users/graphql/queries/getOneCampaignTrigger';
+
+const StyledComboInputContainer = styled.div`
+ display: flex;
+ align-items: center;
+ align-self: center;
+ justify-content: start;
+ margin: ${({ theme }) => theme.spacing(10)};
+`;
+
+const StyledTitleBar = styled.div`
+ display: flex;
+ width: 100%;
+`;
+
+const StyledLabelContainer = styled.div`
+ color: ${({ theme }) => theme.font.color.tertiary};
+ width: auto;
+ margin-right: ${({ theme }) => theme.spacing(4)};
+`;
+
+export const FormTemplate = ({
+ targetableObject,
+}: {
+ targetableObject: ActivityTargetableObject;
+}) => {
+ console.log(targetableObject, 'targetableobject');
+ let [selectedCampaign, { data: selectedCampaignData }] =
+ useLazyQuery(GET_CAMPAIGN_LISTS);
+ let [selectedCampaignTrigger, { data: selectedCampaignTriggerData }] =
+ useLazyQuery(GET_CAMPAIGN_TRIGGER, {
+ fetchPolicy: 'network-only',
+ });
+ let campaignId = '';
+ const [form, setForm] = useState('');
+ const [formFetched, setFormFetched] = useState({
+ name: '',
+ description: '',
+ createdAt: '',
+ status: '',
+ });
+
+ useEffect(() => {
+ const fetchFormDetails = async () => {
+ try {
+ if (targetableObject.targetObjectNameSingular === 'campaignTrigger') {
+ const data = await selectedCampaignTrigger({
+ variables: {
+ objectRecordId: targetableObject.id,
+ },
+ });
+
+ campaignId = data.data.campaignTrigger.campaignId;
+ console.log(campaignId, 'campaignId');
+ } else if (targetableObject.targetObjectNameSingular === 'campaign') {
+ campaignId = targetableObject.id;
+ }
+ const data = await selectedCampaign({
+ variables: {
+ filter: {
+ id: { eq: campaignId },
+ },
+ },
+ });
+ const formTemplateName =
+ data?.data?.campaigns?.edges[0]?.node?.formTemplate?.value;
+ setForm(formTemplateName);
+ setFormFetched({
+ name: data?.data?.campaigns?.edges[0]?.node?.formTemplate?.name || '',
+ description:
+ data?.data?.campaigns?.edges[0]?.node?.formTemplate?.description ||
+ '',
+ createdAt:
+ data?.data?.campaigns?.edges[0]?.node?.formTemplate?.createdAt ||
+ '',
+ status:
+ data?.data?.campaigns?.edges[0]?.node?.formTemplate?.status || '',
+ });
+ console.log(formTemplateName, 'formTemplateName');
+ } catch (error) {
+ console.error('Error fetching form template:', error);
+ }
+ };
+
+ fetchFormDetails();
+ }, [targetableObject.id, selectedCampaign]);
+
+ const renderForm = () => {
+ switch (form) {
+ case 'CampaignForm':
+ return ;
+ case 'CampaignForm2':
+ return ;
+ case 'CampaignForm3':
+ return ;
+ default:
+ return null;
+ }
+ };
+ return (
+ <>
+
+
+
+ Name:
+
+
+
+
+
+ Description:
+
+
+
+
+
+ Created At:
+
+
+
+
+
+ Status:
+
+
+
+
+ {renderForm()}
+ >
+ );
+};
diff --git a/packages/twenty-front/src/modules/activities/messageTemplate/components/messageTemplate.tsx b/packages/twenty-front/src/modules/activities/messageTemplate/components/messageTemplate.tsx
new file mode 100644
index 000000000000..693f5f9a8b5b
--- /dev/null
+++ b/packages/twenty-front/src/modules/activities/messageTemplate/components/messageTemplate.tsx
@@ -0,0 +1,130 @@
+import { useEffect, useState } from 'react';
+import styled from '@emotion/styled';
+import { ActivityTargetableObject } from '@/activities/types/ActivityTargetableEntity';
+import { GET_CAMPAIGN_LISTS } from '@/users/graphql/queries/getCampaignList';
+import { useLazyQuery } from '@apollo/client';
+import { EllipsisDisplay } from '@/ui/field/display/components/EllipsisDisplay';
+
+import { TextDisplay } from '@/ui/field/display/components/TextDisplay';
+import { TextArea } from '@/ui/input/components/TextArea';
+import { GET_CAMPAIGN_TRIGGER } from '@/users/graphql/queries/getOneCampaignTrigger';
+
+const StyledDetailContainer = styled.div`
+ display: flex;
+ margin: ${({ theme }) => theme.spacing(6)};
+ // margin-left: ${({ theme }) => theme.spacing(6)};
+`;
+
+const StyledLabelContainer = styled.div`
+ color: ${({ theme }) => theme.font.color.tertiary};
+ flex: 1;
+ margin-left: ${({ theme }) => theme.spacing(0)};
+`;
+
+const StyledValueContainer = styled.div`
+ flex: 5;
+ margin-left: ${({ theme }) => theme.spacing(0)};
+`;
+const StyledAreaValueContainer = styled.div`
+ flex: 5;
+ margin-left: ${({ theme }) => theme.spacing(0)};
+`;
+
+const StyledTextArea = styled.textarea`
+ height: 200px; /* Adjust the height as needed */
+ width: 100%;
+ padding: 8px;
+ font-size: 16px;
+ border-radius: 4px;
+ border: 1px solid #ccc;
+ resize: vertical; /* Allow vertical resizing */
+`;
+export const MessageTemplate = ({
+ targetableObject,
+}: {
+ targetableObject: ActivityTargetableObject;
+}) => {
+ const [messageTemplate, setMessageTemplate] = useState([]);
+ let [selectedCampaign] = useLazyQuery(GET_CAMPAIGN_LISTS);
+ let [selectedCampaignTrigger, { data: selectedCampaignTriggerData }] =
+ useLazyQuery(GET_CAMPAIGN_TRIGGER, {
+ fetchPolicy: 'network-only',
+ });
+ let campaignId = '';
+ const messageTeamplateDetails = async () => {
+ try {
+ if (targetableObject.targetObjectNameSingular === 'campaignTrigger') {
+ const data = await selectedCampaignTrigger({
+ variables: {
+ objectRecordId: targetableObject.id,
+ },
+ });
+
+ campaignId = data.data.campaignTrigger.campaignId;
+ console.log(campaignId, 'campaignId');
+ } else if (targetableObject.targetObjectNameSingular === 'campaign') {
+ campaignId = targetableObject.id;
+ }
+ const data = await selectedCampaign({
+ variables: {
+ filter: {
+ id: { eq: campaignId },
+ },
+ },
+ });
+ setMessageTemplate([
+ data?.data?.campaigns?.edges[0]?.node?.messageTemplate,
+ ]);
+ console.log(messageTemplate, 'Message Template Details');
+ } catch (error) {
+ console.error('Error fetching message template:', error);
+ }
+ };
+
+ useEffect(() => {
+ messageTeamplateDetails();
+ }, [targetableObject.id, selectedCampaign]);
+
+ console.log(messageTemplate[0]?.name, 'messageTemplate?.name');
+ return (
+ <>
+
+
+ Name
+
+
+
+
+
+
+
+ Channel Type
+
+
+
+
+
+
+
+ Status
+
+
+
+
+
+
+
+ Body
+
+
+
+
+
+ >
+ );
+};
diff --git a/packages/twenty-front/src/modules/object-record/record-show/record-detail-section/components/RecordDetailRelationRecordsListItem.tsx b/packages/twenty-front/src/modules/object-record/record-show/record-detail-section/components/RecordDetailRelationRecordsListItem.tsx
index d7d4c7fb7d50..f7252c0e4c70 100644
--- a/packages/twenty-front/src/modules/object-record/record-show/record-detail-section/components/RecordDetailRelationRecordsListItem.tsx
+++ b/packages/twenty-front/src/modules/object-record/record-show/record-detail-section/components/RecordDetailRelationRecordsListItem.tsx
@@ -6,6 +6,7 @@ import {
IconChevronDown,
IconComponent,
IconDotsVertical,
+ IconEye,
IconTrash,
IconUnlink,
} from 'twenty-ui';
@@ -38,7 +39,9 @@ import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
import { DropdownScope } from '@/ui/layout/dropdown/scopes/DropdownScope';
import { MenuItem } from '@/ui/navigation/menu-item/components/MenuItem';
import { AnimatedEaseInOut } from '@/ui/utilities/animation/components/AnimatedEaseInOut';
-
+import { TAB_LIST_COMPONENT_ID } from '@/ui/layout/show-page/components/ShowPageRightContainer';
+import { useTabList } from '@/ui/layout/tab/hooks/useTabList';
+import { useParams } from 'react-router-dom';
const StyledListItem = styled(RecordDetailRecordsListItem)<{
isDropdownOpen?: boolean;
}>`
@@ -83,6 +86,13 @@ export const RecordDetailRelationRecordsListItem = ({
relationRecord,
}: RecordDetailRelationRecordsListItemProps) => {
const { fieldDefinition } = useContext(FieldContext);
+ const { objectNameSingular, objectRecordId } = useParams<{
+ objectNameSingular: string;
+ objectRecordId: string;
+ }>();
+ const { getActiveTabIdState, setActiveTabId } = useTabList(
+ TAB_LIST_COMPONENT_ID,
+ );
const {
relationFieldMetadataId,
@@ -155,7 +165,15 @@ export const RecordDetailRelationRecordsListItem = ({
closeDropdown();
await deleteOneRelationRecord(relationRecord.id);
};
-
+ const handleView = () => {
+ if (relationRecord.__typename == 'FormTemplate') {
+ setActiveTabId('formTemplate');
+ } else if (relationRecord.__typename == 'MessageTemplate') {
+ setActiveTabId('messageTemplate');
+ } else if (relationRecord.__typename == 'Segment') {
+ setActiveTabId('leads');
+ }
+ };
const useUpdateOneObjectRecordMutation: RecordUpdateHook = () => {
const updateEntity = ({ variables }: RecordUpdateHookParams) => {
updateOneRelationRecord?.({
@@ -239,6 +257,17 @@ export const RecordDetailRelationRecordsListItem = ({
dropdownHotkeyScope={{ scope: dropdownScopeId }}
/>
+ {objectNameSingular == 'campaign' &&
+ (relationRecord.__typename == 'FormTemplate' ||
+ relationRecord.__typename == 'MessageTemplate' ||
+ relationRecord.__typename == 'Segment') && (
+
+ )}
diff --git a/packages/twenty-front/src/modules/types/CustomPath.ts b/packages/twenty-front/src/modules/types/CustomPath.ts
index 43866d12583e..f320d04853b2 100644
--- a/packages/twenty-front/src/modules/types/CustomPath.ts
+++ b/packages/twenty-front/src/modules/types/CustomPath.ts
@@ -14,4 +14,14 @@ export enum CustomPath {
CampaignsPage = '/campaigns',
DatePickerPage = '/datepicker',
+
+ CampaignForm = '/campaign/:userid',
+ CampaignForm2 = '/campaign2/:userid',
+ CampaignForm3 = '/campaign3/:userid',
+
+ RunCampaign = '/runcampaign',
+
+ SegmentPage = '/segment',
+
+ CampaignTriggersPage = '/objects/campaignTriggers',
}
diff --git a/packages/twenty-front/src/modules/ui/input/components/internal/date/components/DateTimePicker.tsx b/packages/twenty-front/src/modules/ui/input/components/internal/date/components/DateTimePicker.tsx
index da5e7e3407b3..1edee38fb500 100644
--- a/packages/twenty-front/src/modules/ui/input/components/internal/date/components/DateTimePicker.tsx
+++ b/packages/twenty-front/src/modules/ui/input/components/internal/date/components/DateTimePicker.tsx
@@ -3,12 +3,11 @@ import React, { useState } from 'react';
import ReactDatePicker from 'react-datepicker';
import styled from '@emotion/styled';
-import { IconCalendar } from '@/ui/display/icon';
import { MenuItemLeftContent } from '@/ui/navigation/menu-item/internals/components/MenuItemLeftContent';
import { StyledHoverableMenuItemBase } from '@/ui/navigation/menu-item/internals/components/StyledMenuItemBase';
-import { overlayBackground } from '@/ui/theme/constants/effects';
import 'react-datepicker/dist/react-datepicker.css';
+import { IconCalendar } from '@tabler/icons-react';
const StyledContainer = styled.div`
& .react-datepicker {
@@ -89,9 +88,7 @@ const StyledContainer = styled.div`
}
& .react-datepicker__month-dropdown,
- & .react-datepicker__year-dropdown {
- border: ${({ theme }) => theme.border.color.light};
- ${overlayBackground}
+
overflow-y: scroll;
top: ${({ theme }) => theme.spacing(2)};
}
diff --git a/packages/twenty-front/src/modules/ui/layout/page/RunCampaignButton.tsx b/packages/twenty-front/src/modules/ui/layout/page/RunCampaignButton.tsx
new file mode 100644
index 000000000000..66e9f02c53d1
--- /dev/null
+++ b/packages/twenty-front/src/modules/ui/layout/page/RunCampaignButton.tsx
@@ -0,0 +1,18 @@
+import { IconButton } from '@/ui/input/button/components/IconButton';
+import { IconPlayerPlay } from '@tabler/icons-react';
+
+type PageRunCampaignButtonProps = {
+ onClick: () => void;
+ };
+ export const RunCampaignButton = ({
+ onClick,
+ }: PageRunCampaignButtonProps) => (
+
+);
\ No newline at end of file
diff --git a/packages/twenty-front/src/modules/ui/layout/show-page/components/ShowPageRightContainer.tsx b/packages/twenty-front/src/modules/ui/layout/show-page/components/ShowPageRightContainer.tsx
index 4f6cddbef8da..aebb0cf6c124 100644
--- a/packages/twenty-front/src/modules/ui/layout/show-page/components/ShowPageRightContainer.tsx
+++ b/packages/twenty-front/src/modules/ui/layout/show-page/components/ShowPageRightContainer.tsx
@@ -23,6 +23,12 @@ import { TabList } from '@/ui/layout/tab/components/TabList';
import { useTabList } from '@/ui/layout/tab/hooks/useTabList';
import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile';
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
+import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
+import { IconClock, IconUsersGroup, IconMessage, IconDeviceTabletQuestion } from '@tabler/icons-react';
+import { Schedule } from '@/activities/Schedule/components/schedule';
+import { Leads } from '@/activities/Leads/components/Leads';
+import { MessageTemplate } from '@/activities/messageTemplate/components/messageTemplate';
+import { FormTemplate } from '@/activities/formTemplate/components/formTemplate';
const StyledShowPageRightContainer = styled.div`
display: flex;
@@ -64,7 +70,10 @@ export const ShowPageRightContainer = ({
}: ShowPageRightContainerProps) => {
const { activeTabIdState } = useTabList(TAB_LIST_COMPONENT_ID);
const activeTabId = useRecoilValue(activeTabIdState);
-
+ const { objectMetadataItem: targetableObjectMetadataItem } =
+ useObjectMetadataItem({
+ objectNameSingular: targetableObject.targetObjectNameSingular,
+ });
const shouldDisplayCalendarTab =
useIsFeatureEnabled('IS_CALENDAR_ENABLED') &&
(targetableObject.targetObjectNameSingular ===
@@ -78,52 +87,89 @@ export const ShowPageRightContainer = ({
targetableObject.targetObjectNameSingular ===
CoreObjectNameSingular.Company) ||
targetableObject.targetObjectNameSingular === CoreObjectNameSingular.Person;
+ let TASK_TABS = [];
+
+ if (targetableObject.targetObjectNameSingular === 'campaign'|| targetableObject.targetObjectNameSingular === 'campaignTrigger') {
+ TASK_TABS = [
+ {
+ id: 'schedule',
+ title: 'Schedule',
+ Icon: IconClock,
+ hide: !timeline,
+ },
+ {
+ id: 'leads',
+ title: 'Leads',
+ Icon: IconUsersGroup,
+ hide: !tasks,
+ },
+ {
+ id: 'messageTemplate',
+ title: 'Message Template',
+ Icon: IconMessage,
+ hide: !notes,
+ },
+ {
+ id: 'formTemplate',
+ title: 'Form Template',
+ Icon: IconDeviceTabletQuestion,
+ hide: !notes,
+ },
+ {
+ id: 'emails',
+ title: 'Emails',
+ Icon: IconMail,
+ hide: !shouldDisplayEmailsTab,
+ hasBetaPill: true,
+ },
+ ];
+ }else{ TASK_TABS = [
+ {
+ id: 'timeline',
+ title: 'Timeline',
+ Icon: IconTimelineEvent,
+ hide: !timeline,
+ },
+ {
+ id: 'tasks',
+ title: 'Tasks',
+ Icon: IconCheckbox,
+ hide: !tasks,
+ },
+ {
+ id: 'notes',
+ title: 'Notes',
+ Icon: IconNotes,
+ hide: !notes,
+ },
+ {
+ id: 'files',
+ title: 'Files',
+ Icon: IconPaperclip,
+ hide: !notes,
+ },
+ {
+ id: 'emails',
+ title: 'Emails',
+ Icon: IconMail,
+ hide: !shouldDisplayEmailsTab,
+ },
+ {
+ id: 'calendar',
+ title: 'Calendar',
+ Icon: IconCalendarEvent,
+ hide: !shouldDisplayCalendarTab,
+ },
+ {
+ id: 'logs',
+ title: 'Logs',
+ Icon: IconTimelineEvent,
+ hide: !shouldDisplayLogTab,
+ hasBetaPill: true,
+ },
+ ];}
+
- const TASK_TABS = [
- {
- id: 'timeline',
- title: 'Timeline',
- Icon: IconTimelineEvent,
- hide: !timeline,
- },
- {
- id: 'tasks',
- title: 'Tasks',
- Icon: IconCheckbox,
- hide: !tasks,
- },
- {
- id: 'notes',
- title: 'Notes',
- Icon: IconNotes,
- hide: !notes,
- },
- {
- id: 'files',
- title: 'Files',
- Icon: IconPaperclip,
- hide: !notes,
- },
- {
- id: 'emails',
- title: 'Emails',
- Icon: IconMail,
- hide: !shouldDisplayEmailsTab,
- },
- {
- id: 'calendar',
- title: 'Calendar',
- Icon: IconCalendarEvent,
- hide: !shouldDisplayCalendarTab,
- },
- {
- id: 'logs',
- title: 'Logs',
- Icon: IconTimelineEvent,
- hide: !shouldDisplayLogTab,
- hasBetaPill: true,
- },
- ];
return (
@@ -152,6 +198,19 @@ export const ShowPageRightContainer = ({
{activeTabId === 'logs' && (
)}
+
+{activeTabId === 'schedule' && (
+
+ )}
+ {activeTabId === 'leads' && (
+
+ )}
+ {activeTabId === 'messageTemplate' && (
+
+ )}
+ {activeTabId === 'formTemplate' && (
+
+ )}
);
};
diff --git a/packages/twenty-front/src/modules/users/graphql/queries/addCampaign.ts b/packages/twenty-front/src/modules/users/graphql/queries/addCampaign.ts
index 5a0455a0bd8a..bc6ac03a3203 100644
--- a/packages/twenty-front/src/modules/users/graphql/queries/addCampaign.ts
+++ b/packages/twenty-front/src/modules/users/graphql/queries/addCampaign.ts
@@ -1,98 +1,9 @@
import { gql } from '@apollo/client';
export const ADD_CAMPAIGN = gql`
- mutation CreateOneCampaignList($input: CampaignListCreateInput!) {
- createCampaignList(data: $input) {
- id
- name
- updatedAt
- subSpecialtyType
- position
- endDate
- campaignName
- specialtyType
- activityTargets {
- edges {
- node {
- __typename
- id
- person {
- __typename
- id
- }
- id
- createdAt
- personId
- campaignList {
- __typename
- id
- }
- activity {
- __typename
- id
- }
- company {
- __typename
- id
- }
- opportunityId
- updatedAt
- activityId
- opportunity {
- __typename
- id
- }
- companyId
- campaignListId
- }
- __typename
- }
- __typename
- }
- startDate
- messagingMedia
- id
- createdAt
- description
- favorites {
- edges {
- node {
- __typename
- id
- campaignList {
- __typename
- id
- }
- opportunityId
- company {
- __typename
- id
- }
- updatedAt
- createdAt
- workspaceMember {
- __typename
- id
- }
- person {
- __typename
- id
- }
- workspaceMemberId
- personId
- id
- position
- opportunity {
- __typename
- id
- }
- companyId
- campaignListId
- }
- __typename
- }
- __typename
- }
- __typename
- }
- }
-`;
+mutation CreateOneCampaign($input: CampaignCreateInput!) {
+ createCampaign(data: $input) {
+ id
+ }}`;
+
+
+
\ No newline at end of file
diff --git a/packages/twenty-front/src/modules/users/graphql/queries/addSegment.ts b/packages/twenty-front/src/modules/users/graphql/queries/addSegment.ts
new file mode 100644
index 000000000000..ad74d600c147
--- /dev/null
+++ b/packages/twenty-front/src/modules/users/graphql/queries/addSegment.ts
@@ -0,0 +1,7 @@
+import { gql } from '@apollo/client';
+export const ADD_SEGMENT = gql`
+mutation CreateOneSegment($input: SegmentCreateInput!) {
+ createSegment(data: $input) {
+ id
+ }
+}`;
\ No newline at end of file
diff --git a/packages/twenty-front/src/modules/users/graphql/queries/addTriggerCampaignRecord.ts b/packages/twenty-front/src/modules/users/graphql/queries/addTriggerCampaignRecord.ts
new file mode 100644
index 000000000000..d60c02528889
--- /dev/null
+++ b/packages/twenty-front/src/modules/users/graphql/queries/addTriggerCampaignRecord.ts
@@ -0,0 +1,9 @@
+import { gql } from '@apollo/client';
+
+export const ADD_TRIGGER_CAMPAIGN_RECORD = gql`mutation CreateOneCampaignTrigger($input: CampaignTriggerCreateInput!) {
+ createCampaignTrigger(data: $input) {
+ id
+ name
+ status
+ }
+ }`
\ No newline at end of file
diff --git a/packages/twenty-front/src/modules/users/graphql/queries/filterLeads.ts b/packages/twenty-front/src/modules/users/graphql/queries/filterLeads.ts
new file mode 100644
index 000000000000..22c56a0ee184
--- /dev/null
+++ b/packages/twenty-front/src/modules/users/graphql/queries/filterLeads.ts
@@ -0,0 +1,30 @@
+import { gql } from '@apollo/client';
+
+export const FILTER_LEADS = gql`
+query FindManyLeads($filter: LeadFilterInput, $orderBy: LeadOrderByInput, $lastCursor: String, $limit: Float) {
+ leads(filter: $filter, orderBy: $orderBy, first: $limit, after: $lastCursor) {
+ edges {
+ node {
+ id
+ email
+ age
+ name
+ phoneNumber
+ advertisementName
+ campaignName
+ comments
+ advertisementSource
+ createdAt
+ location
+ }
+ }
+ pageInfo {
+ hasNextPage
+ startCursor
+ endCursor
+ __typename
+ }
+ totalCount
+ __typename
+ }
+ }`;
\ No newline at end of file
diff --git a/packages/twenty-front/src/modules/users/graphql/queries/getCampaignList.ts b/packages/twenty-front/src/modules/users/graphql/queries/getCampaignList.ts
new file mode 100644
index 000000000000..9b9d7614c47b
--- /dev/null
+++ b/packages/twenty-front/src/modules/users/graphql/queries/getCampaignList.ts
@@ -0,0 +1,51 @@
+import { gql } from '@apollo/client';
+
+export const GET_CAMPAIGN_LISTS = gql`
+query FindManyCampaigns($filter: CampaignFilterInput, $orderBy: CampaignOrderByInput, $lastCursor: String, $limit: Float) {
+ campaigns(filter: $filter, orderBy: $orderBy, first: $limit, after: $lastCursor) {
+ edges {
+ node {
+ id
+ name
+ description
+ formTemplate{
+ id
+ name
+ }
+ segment{
+ id
+ name
+ filters
+ }
+ subspecialty
+ specialty
+ messageTemplate{
+ id
+ name
+ channelType
+ body
+ status
+ createdAt
+ }
+ formTemplate{
+ id
+ name
+ value
+ description
+ createdAt
+ status
+ }
+
+ segmentId
+ messageTemplateId
+ }
+ }
+ pageInfo {
+ hasNextPage
+ startCursor
+ endCursor
+ }
+ totalCount
+ }
+
+}`
\ No newline at end of file
diff --git a/packages/twenty-front/src/modules/users/graphql/queries/getFormTemplates.ts b/packages/twenty-front/src/modules/users/graphql/queries/getFormTemplates.ts
new file mode 100644
index 000000000000..c6d2c48ff127
--- /dev/null
+++ b/packages/twenty-front/src/modules/users/graphql/queries/getFormTemplates.ts
@@ -0,0 +1,27 @@
+import { gql } from '@apollo/client';
+
+export const GET_FORM_TEMPLATES = gql`
+query FindManyFormTemplates($filter: FormTemplateFilterInput, $orderBy: FormTemplateOrderByInput, $lastCursor: String, $limit: Float) {
+ formTemplates(
+ filter: $filter
+ orderBy: $orderBy
+ first: $limit
+ after: $lastCursor
+ ) {
+ edges {
+ node {
+ id
+ status
+ value
+ createdAt
+ name
+ }
+ }
+ pageInfo {
+ hasNextPage
+ startCursor
+ endCursor
+ }
+ totalCount
+ }
+ }`
\ No newline at end of file
diff --git a/packages/twenty-front/src/modules/users/graphql/queries/getMessageTemplates.ts b/packages/twenty-front/src/modules/users/graphql/queries/getMessageTemplates.ts
new file mode 100644
index 000000000000..5b9dcf99c2d2
--- /dev/null
+++ b/packages/twenty-front/src/modules/users/graphql/queries/getMessageTemplates.ts
@@ -0,0 +1,295 @@
+import { gql } from '@apollo/client';
+
+export const GET_MESSAGE_TEMPLATES = gql`
+query FindManyMessageTemplates($filter: MessageTemplateFilterInput, $orderBy: MessageTemplateOrderByInput, $lastCursor: String, $limit: Float) {
+ messageTemplates(
+ filter: $filter
+ orderBy: $orderBy
+ first: $limit
+ after: $lastCursor
+ ) {
+ edges {
+ node {
+ id
+ updatedAt
+ createdAt
+ channelType
+ name
+ body
+ id
+ favorites {
+ edges {
+ node {
+ __typename
+ id
+ updatedAt
+ campaign {
+ __typename
+ id
+ }
+ position
+ workspaceMemberId
+ subspecialtyId
+ formResponse {
+ __typename
+ id
+ }
+ specialty {
+ __typename
+ id
+ }
+ personId
+ company {
+ __typename
+ id
+ }
+ formTemplateId
+ lead {
+ __typename
+ id
+ }
+ campaignTrigger {
+ __typename
+ id
+ }
+ messageTemplateId
+ person {
+ __typename
+ id
+ }
+ campaignTriggerId
+ id
+ segmentId
+ opportunityId
+ subspecialty {
+ __typename
+ id
+ }
+ createdAt
+ segment {
+ __typename
+ id
+ }
+ formTemplate {
+ __typename
+ id
+ }
+ campaignId
+ formResponseId
+ specialtyId
+ opportunity {
+ __typename
+ id
+ }
+ communicationLogId
+ messageTemplate {
+ __typename
+ id
+ }
+ workspaceMember {
+ __typename
+ id
+ }
+ companyId
+ leadId
+ communicationLog {
+ __typename
+ id
+ }
+ }
+ __typename
+ }
+ __typename
+ }
+ attachments {
+ edges {
+ node {
+ __typename
+ id
+ specialty {
+ __typename
+ id
+ }
+ fullPath
+ activity {
+ __typename
+ id
+ }
+ updatedAt
+ formResponseId
+ companyId
+ campaign {
+ __typename
+ id
+ }
+ communicationLog {
+ __typename
+ id
+ }
+ type
+ segment {
+ __typename
+ id
+ }
+ formResponse {
+ __typename
+ id
+ }
+ subspecialty {
+ __typename
+ id
+ }
+ communicationLogId
+ specialtyId
+ createdAt
+ messageTemplate {
+ __typename
+ id
+ }
+ person {
+ __typename
+ id
+ }
+ formTemplateId
+ subspecialtyId
+ id
+ leadId
+ company {
+ __typename
+ id
+ }
+ messageTemplateId
+ opportunity {
+ __typename
+ id
+ }
+ formTemplate {
+ __typename
+ id
+ }
+ segmentId
+ lead {
+ __typename
+ id
+ }
+ campaignId
+ name
+ authorId
+ campaignTriggerId
+ campaignTrigger {
+ __typename
+ id
+ }
+ author {
+ __typename
+ id
+ }
+ opportunityId
+ activityId
+ personId
+ }
+ __typename
+ }
+ __typename
+ }
+ activityTargets {
+ edges {
+ node {
+ __typename
+ id
+ subspecialtyId
+ company {
+ __typename
+ id
+ }
+ specialtyId
+ opportunity {
+ __typename
+ id
+ }
+ campaignTrigger {
+ __typename
+ id
+ }
+ campaignTriggerId
+ activityId
+ id
+ person {
+ __typename
+ id
+ }
+ messageTemplate {
+ __typename
+ id
+ }
+ formResponseId
+ createdAt
+ opportunityId
+ segmentId
+ campaignId
+ activity {
+ __typename
+ id
+ }
+ lead {
+ __typename
+ id
+ }
+ formResponse {
+ __typename
+ id
+ }
+ updatedAt
+ subspecialty {
+ __typename
+ id
+ }
+ communicationLogId
+ companyId
+ leadId
+ formTemplate {
+ __typename
+ id
+ }
+ specialty {
+ __typename
+ id
+ }
+ communicationLog {
+ __typename
+ id
+ }
+ segment {
+ __typename
+ id
+ }
+ campaign {
+ __typename
+ id
+ }
+ personId
+ formTemplateId
+ messageTemplateId
+ }
+ __typename
+ }
+ __typename
+ }
+ status
+ position
+ __typename
+ }
+ cursor
+ __typename
+ }
+ pageInfo {
+ hasNextPage
+ startCursor
+ endCursor
+ __typename
+ }
+ totalCount
+ __typename
+ }
+}
+`;
\ No newline at end of file
diff --git a/packages/twenty-front/src/modules/users/graphql/queries/getOneCampaignTrigger.ts b/packages/twenty-front/src/modules/users/graphql/queries/getOneCampaignTrigger.ts
new file mode 100644
index 000000000000..33647d131171
--- /dev/null
+++ b/packages/twenty-front/src/modules/users/graphql/queries/getOneCampaignTrigger.ts
@@ -0,0 +1,360 @@
+import { gql } from '@apollo/client';
+
+export const GET_CAMPAIGN_TRIGGER = gql`query FindOnecampaignTrigger($objectRecordId: UUID!) {
+ campaignTrigger(filter: {id: {eq: $objectRecordId}}) {
+ id
+ attachments {
+ edges {
+ node {
+ __typename
+ id
+ specialty {
+ __typename
+ id
+ }
+ fullPath
+ activity {
+ __typename
+ id
+ }
+ updatedAt
+ formResponseId
+ companyId
+ campaign {
+ __typename
+ id
+ }
+ communicationLog {
+ __typename
+ id
+ }
+ type
+ segment {
+ __typename
+ id
+ }
+ formResponse {
+ __typename
+ id
+ }
+ subspecialty {
+ __typename
+ id
+ }
+ communicationLogId
+ specialtyId
+ createdAt
+ messageTemplate {
+ __typename
+ id
+ }
+ person {
+ __typename
+ id
+ }
+ formTemplateId
+ subspecialtyId
+ id
+ leadId
+ company {
+ __typename
+ id
+ }
+ messageTemplateId
+ opportunity {
+ __typename
+ id
+ }
+ formTemplate {
+ __typename
+ id
+ }
+ segmentId
+ lead {
+ __typename
+ id
+ }
+ campaignId
+ name
+ authorId
+ campaignTriggerId
+ campaignTrigger {
+ __typename
+ id
+ }
+ author {
+ __typename
+ id
+ }
+ opportunityId
+ activityId
+ personId
+ }
+ __typename
+ }
+ __typename
+ }
+ executionId
+ startDate
+ opportunites {
+ edges {
+ node {
+ __typename
+ id
+ campaign {
+ __typename
+ id
+ }
+ lead {
+ __typename
+ id
+ }
+ probability
+ messageStatus
+ activityTargets {
+ edges {
+ node {
+ __typename
+ id
+ }
+ __typename
+ }
+ __typename
+ }
+ favorites {
+ edges {
+ node {
+ __typename
+ id
+ }
+ __typename
+ }
+ __typename
+ }
+ companyId
+ campaignTrigger {
+ __typename
+ id
+ }
+ stage
+ attachments {
+ edges {
+ node {
+ __typename
+ id
+ }
+ __typename
+ }
+ __typename
+ }
+ informedPhoneNumberId
+ informedPhoneNumber {
+ __typename
+ id
+ }
+ createdAt
+ updatedAt
+ id
+ pointOfContact {
+ __typename
+ id
+ }
+ pipelineStepId
+ campaignId
+ amount {
+ amountMicros
+ currencyCode
+ __typename
+ }
+ campaignTriggerId
+ company {
+ __typename
+ id
+ }
+ comments
+ closeDate
+ pipelineStep {
+ __typename
+ id
+ }
+ pointOfContactId
+ leadId
+ name
+ position
+ }
+ __typename
+ }
+ __typename
+ }
+ id
+ createdAt
+ position
+ stopDate
+ activityTargets {
+ edges {
+ node {
+ __typename
+ id
+ subspecialtyId
+ company {
+ __typename
+ id
+ }
+ specialtyId
+ opportunity {
+ __typename
+ id
+ }
+ campaignTrigger {
+ __typename
+ id
+ }
+ campaignTriggerId
+ activityId
+ id
+ person {
+ __typename
+ id
+ }
+ messageTemplate {
+ __typename
+ id
+ }
+ formResponseId
+ createdAt
+ opportunityId
+ segmentId
+ campaignId
+ activity {
+ __typename
+ id
+ }
+ lead {
+ __typename
+ id
+ }
+ formResponse {
+ __typename
+ id
+ }
+ updatedAt
+ subspecialty {
+ __typename
+ id
+ }
+ communicationLogId
+ companyId
+ leadId
+ formTemplate {
+ __typename
+ id
+ }
+ specialty {
+ __typename
+ id
+ }
+ communicationLog {
+ __typename
+ id
+ }
+ segment {
+ __typename
+ id
+ }
+ campaign {
+ __typename
+ id
+ }
+ personId
+ formTemplateId
+ messageTemplateId
+ }
+ __typename
+ }
+ __typename
+ }
+ campaign {
+ __typename
+ id
+ description
+ segment {
+ __typename
+ id
+ }
+ position
+ activityTargets {
+ edges {
+ node {
+ __typename
+ id
+ }
+ __typename
+ }
+ __typename
+ }
+ id
+ segmentId
+ messageTemplateId
+ subspecialty
+ updatedAt
+ formTemplate {
+ __typename
+ id
+ }
+ status
+ favorites {
+ edges {
+ node {
+ __typename
+ id
+ }
+ __typename
+ }
+ __typename
+ }
+ campaignExecution {
+ edges {
+ node {
+ __typename
+ id
+ }
+ __typename
+ }
+ __typename
+ }
+ specialty
+ formTemplateId
+ createdAt
+ opportunities {
+ edges {
+ node {
+ __typename
+ id
+ }
+ __typename
+ }
+ __typename
+ }
+ messageTemplate {
+ __typename
+ id
+ }
+ name
+ attachments {
+ edges {
+ node {
+ __typename
+ id
+ }
+ __typename
+ }
+ __typename
+ }
+ }
+ campaignId
+ status
+ name
+ updatedAt
+ __typename
+ }
+ }`
\ No newline at end of file
diff --git a/packages/twenty-front/src/modules/users/graphql/queries/getSegments.ts b/packages/twenty-front/src/modules/users/graphql/queries/getSegments.ts
new file mode 100644
index 000000000000..9f85bad846dc
--- /dev/null
+++ b/packages/twenty-front/src/modules/users/graphql/queries/getSegments.ts
@@ -0,0 +1,28 @@
+import { gql } from '@apollo/client';
+
+export const GET_SEGMENT_LISTS = gql`
+query FindManySegments($filter: SegmentFilterInput, $orderBy: SegmentOrderByInput, $lastCursor: String, $limit: Float) {
+ segments(
+ filter: $filter
+ orderBy: $orderBy
+ first: $limit
+ after: $lastCursor
+ ) {
+ edges {
+ node {
+ id
+ description
+ filters
+ name
+ }
+ }
+ pageInfo {
+ hasNextPage
+ startCursor
+ endCursor
+ __typename
+ }
+ totalCount
+ __typename
+ }
+ }`
\ No newline at end of file
diff --git a/packages/twenty-front/src/modules/users/graphql/queries/getSpecialtyDetails.ts b/packages/twenty-front/src/modules/users/graphql/queries/getSpecialtyDetails.ts
index b809cd8123c8..15474068d256 100644
--- a/packages/twenty-front/src/modules/users/graphql/queries/getSpecialtyDetails.ts
+++ b/packages/twenty-front/src/modules/users/graphql/queries/getSpecialtyDetails.ts
@@ -1,26 +1,30 @@
import { gql } from '@apollo/client';
export const GET_SPECIALTY = gql`
- query FindManySubspecialties(
- $filter: SubspecialtyFilterInput
- $orderBy: SubspecialtyOrderByInput
- $lastCursor: String
- $limit: Float
+query FindManySubspecialties($filter: SubspecialtyFilterInput, $orderBy: SubspecialtyOrderByInput, $lastCursor: String, $limit: Float) {
+ subspecialties(
+ filter: $filter
+ orderBy: $orderBy
+ first: $limit
+ after: $lastCursor
) {
- subspecialties(
- filter: $filter
- orderBy: $orderBy
- first: $limit
- after: $lastCursor
- ) {
- edges {
- node {
+ edges {
+ node {
+ id
+ name
+ specialty{
name
- specialtyType {
- name
- }
}
+
}
+ cursor
+ }
+ pageInfo {
+ hasNextPage
+ startCursor
+ endCursor
}
+ totalCount
}
-`;
+}
+`;
\ No newline at end of file
diff --git a/packages/twenty-front/src/modules/users/graphql/queries/updateCampaignlistStatus.ts b/packages/twenty-front/src/modules/users/graphql/queries/updateCampaignlistStatus.ts
new file mode 100644
index 000000000000..25da110c7983
--- /dev/null
+++ b/packages/twenty-front/src/modules/users/graphql/queries/updateCampaignlistStatus.ts
@@ -0,0 +1,9 @@
+import { gql } from '@apollo/client';
+
+export const UPDATE_CAMPAIGNLIST_STATUS = gql`
+mutation UpdateOneCampaign($idToUpdate: ID!, $input: CampaignUpdateInput!) {
+ updateCampaign(id: $idToUpdate, data: $input) {
+ id
+ }
+ }
+`;
\ No newline at end of file
diff --git a/packages/twenty-front/src/modules/users/graphql/queries/updateLastExecutionId.ts b/packages/twenty-front/src/modules/users/graphql/queries/updateLastExecutionId.ts
new file mode 100644
index 000000000000..95d89d9a2589
--- /dev/null
+++ b/packages/twenty-front/src/modules/users/graphql/queries/updateLastExecutionId.ts
@@ -0,0 +1,9 @@
+import { gql } from '@apollo/client';
+
+export const UPDATE_LAST_EXECUTION_ID = gql`
+mutation UpdateOneCampaign($idToUpdate: ID!, $input: CampaignUpdateInput!) {
+ updateCampaign(id: $idToUpdate, data: $input) {
+ id
+ }
+ }
+`;
\ No newline at end of file
diff --git a/packages/twenty-front/src/pages/Segment/Segment.tsx b/packages/twenty-front/src/pages/Segment/Segment.tsx
new file mode 100644
index 000000000000..b74488c181bd
--- /dev/null
+++ b/packages/twenty-front/src/pages/Segment/Segment.tsx
@@ -0,0 +1,343 @@
+/* eslint-disable no-restricted-imports */
+import styled from '@emotion/styled';
+import { Section } from '@react-email/components';
+import { Button } from '@/ui/input/button/components/Button';
+import { GRAY_SCALE } from '@/ui/theme/constants/GrayScale';
+import { useMutation } from '@apollo/client';
+import { v4 as uuidv4 } from 'uuid';
+import {
+ IconPlayerPlay,
+ IconPlus,
+ IconUsersGroup,
+ IconX,
+} from '@tabler/icons-react';
+
+import { H2Title } from '@/ui/display/typography/components/H2Title';
+import { useState } from 'react';
+import { PageHeader } from '@/ui/layout/page/PageHeader';
+import { useLazyQuery } from '@apollo/client';
+import { FILTER_LEADS } from '@/users/graphql/queries/filterLeads';
+import { useCampaign } from '~/pages/campaigns/CampaignUseContext';
+import { PreviewLeadsData } from '~/pages/campaigns/PreviewLeadsData';
+import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
+import { ADD_SEGMENT } from '@/users/graphql/queries/addSegment';
+import { useNavigate } from 'react-router-dom';
+import { Select } from '@/ui/input/components/Select';
+import { TextArea } from '@/ui/input/components/TextArea';
+import { TextInput } from '@/ui/input/components/TextInput';
+
+const StyledBoardContainer = styled.div`
+ display: flex;
+ width: 100%;
+ height: auto;
+ flex-direction: column;
+ justify-content: flex-start;
+ background: ${({ theme }) => theme.background.noisy};
+ padding: ${({ theme }) => theme.spacing(2)};
+`;
+
+
+const PageContainer = styled.div`
+ display: flex;
+ flex-direction: column;
+ width: 100%;
+ overflow-y: scroll;
+ scrollbar-color: ${({ theme }) => theme.border.color.strong};
+ scrollbar-width: thin;
+
+ *::-webkit-scrollbar {
+ height: 8px;
+ width: 8px;
+ }
+
+ *::-webkit-scrollbar-corner {
+ background-color: transparent;
+ }
+
+ *::-webkit-scrollbar-thumb {
+ background-color: ${({ theme }) => theme.border.color.strong};
+ border-radius: ${({ theme }) => theme.border.radius.sm};
+ }
+`;
+
+
+const StyledInputCard = styled.div`
+ color: ${({ theme }) => theme.font.color.secondary};
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ height: auto;
+ justify-content: space-between;
+ width: 70%;
+ align-items: center;
+`;
+
+const StyledButton = styled.span`
+ display: flex;
+ gap: 15px;
+ width: 100%;
+ margin-right: ${({ theme }) => theme.spacing(4)};
+`;
+
+const StyledComboInputContainer1 = styled.div`
+ display: flex;
+ flex-direction: row;
+ > * + * {
+ margin-left: ${({ theme }) => theme.spacing(6)};
+ }
+ width: 100%;
+ padding-top: ${({ theme }) => theme.spacing(6)};
+ justify-content: space-evenly;
+`;
+
+const SytledHR = styled.hr`
+ background: ${GRAY_SCALE.gray0};
+ color: ${GRAY_SCALE.gray0};
+ bordercolor: ${GRAY_SCALE.gray0};
+ height: 0.2px;
+ width: 100%;
+ margin: ${({ theme }) => theme.spacing(10)};
+`;
+
+export const Segment = () => {
+ const { setLeadData, leadData } = useCampaign();
+ const [selectedFilterOptions, setSelectedFilterOptions] = useState<
+ Record
+ >({});
+ const navigate=useNavigate()
+
+ const [filterDivs, setFilterDivs] = useState([]);
+ const [segmentName, setSegmentName] = useState('');
+ const [segmentDescription, setSegmentDescription] = useState('');
+ const { enqueueSnackBar } = useSnackBar();
+ const [filterString, setFilterString] = useState("");
+ const handleFilterButtonClick = () => {
+ const key = `filter-${filterDivs.length + 1}`;
+ setFilterDivs([...filterDivs, key]);
+ };
+
+ const handleFilterRemove = (keyToRemove: string) => {
+ setFilterDivs(filterDivs.filter((key) => key !== keyToRemove));
+ setSelectedFilterOptions((prevOptions) => {
+ const {
+ [keyToRemove + '-conditions']: _,
+ [keyToRemove + '-field']: __,
+ [keyToRemove + '-operators']: ___,
+ ...rest
+ } = prevOptions;
+ return rest;
+ });
+ };
+ const createOptions = (options: any[]) =>
+ options.map((option: any) => ({ label: option, value: option }));
+ const [modalOpen, setModalOpen] = useState(false);
+ const conditions = createOptions(['AND', 'OR']);
+ const operators = createOptions(['=', '>', '<', '!=']);
+ const fields = createOptions([
+ 'advertisementSource',
+ 'campaignName',
+ 'location',
+ 'age',
+ ]);
+
+ const handleSelectChange = (key: string, value: string) => {
+ setSelectedFilterOptions((prevOptions) => ({
+ ...prevOptions,
+ [key]: value,
+ }));
+ };
+
+ const [filterleads, { loading, error, data }] = useLazyQuery(FILTER_LEADS, {
+ fetchPolicy: 'network-only',
+ });
+
+ const [addSegment] = useMutation(ADD_SEGMENT);
+
+ const handleRunQuery = async () => {
+ const filter:any= {};
+
+ filterDivs.forEach((key) => {
+ const condition = selectedFilterOptions[`${key}-conditions`];
+ const field = selectedFilterOptions[`${key}-field`];
+ const operator = selectedFilterOptions[`${key}-operators`];
+ const value = selectedFilterOptions[`${key}-value`];
+
+ if (field && operator && value) {
+ const conditionFilter = condition === 'OR' ? 'or' : 'and';
+
+ if (!filter[conditionFilter]) {
+ filter[conditionFilter] = [];
+ }
+ filter[conditionFilter].push({
+ [field]: { ilike: `%${value}%` },
+ });
+ }
+ });
+ // const filterJson = await filter.json()
+
+ let filterString = `{ "filter": ${JSON.stringify(filter)} }`;
+
+ console.log('This is the filter:', filterString);
+
+ const orderBy = { position: 'AscNullsFirst' };
+ try {
+ const result = await filterleads({ variables: { filter, orderBy } });
+ console.log('Data:', result.data);
+
+ setLeadData({ ...leadData, data: result });
+ result.data.leads.edges.forEach((edge: { node: any }) => {
+ const lead = edge.node;
+ console.log('Lead ID:', lead.id);
+ console.log('Lead Email:', lead.email);
+ console.log('Lead Age:', lead.age);
+ console.log('Lead Advertisement Name:', lead.advertisementName);
+ });
+ } catch (error) {
+ console.error('Error fetching data:', error);
+ }
+ setFilterString(filterString)
+ };
+
+ const handlesave = async () => {
+ try {
+ const variables = {
+ input: {
+ id: uuidv4(),
+ name: segmentName,
+ description: segmentDescription,
+ filters: filterString,
+ },
+ };
+ const { data } = await addSegment({
+ variables: variables,
+ });
+ enqueueSnackBar('Segment saved successfully', {
+ variant: 'success',
+ });
+ navigate('/objects/segments')
+ // window.location.reload();
+ } catch (errors: any) {
+ console.log('Error saving segment', error);
+ enqueueSnackBar(errors.message + 'Error while adding Campaign', {
+ variant: 'error',
+ });
+ }
+
+ };
+
+ return (
+ <>
+
+
+
+
+
+
+ setSegmentName(e)}
+ name="segmentName"
+ required
+ fullWidth
+ />
+
+
+
+
+
+ {!loading && data && }
+
+
+ >
+ );
+};
+
diff --git a/packages/twenty-front/src/pages/campaigns/CampaignContext.tsx b/packages/twenty-front/src/pages/campaigns/CampaignContext.tsx
new file mode 100644
index 000000000000..8fe4ad83994d
--- /dev/null
+++ b/packages/twenty-front/src/pages/campaigns/CampaignContext.tsx
@@ -0,0 +1,64 @@
+import { createContext, useState } from 'react';
+
+import { App } from '~/App';
+
+type CampaignData = {
+ campaignName: string;
+ campaignDescription: string;
+ specialtyType: string;
+ subSpecialtyType: string;
+ leads: string;
+};
+export type CampaignContextProps = {
+ currentStep: number;
+ setCurrentStep: (step: number) => void;
+
+ campaignData: any;
+
+ setCampaignData: (data: any) => void;
+
+ leadData: any;
+
+ setLeadData: any;
+};
+
+export const CampaignMultiStepContext =
+ createContext(null);
+
+const CampaignContext = () => {
+ const [currentStep, setCurrentStep] = useState(0);
+ const [leadData, setLeadData] = useState();
+ const [campaignData, setCampaignData] = useState({
+ startDate: '',
+ endDate: '',
+ selectedId: '',
+ unSelectedId: '',
+ querystamp: '',
+ campaignName: '',
+ campaignDescription: '',
+ targetAudience: '',
+ emailTemplate: '',
+ whatsappTemplate: '',
+ pageUrl: '',
+ reload: false
+ });
+
+ return (
+
+ );
+};
+
+export default CampaignContext;
diff --git a/packages/twenty-front/src/pages/campaigns/CampaignDate.tsx b/packages/twenty-front/src/pages/campaigns/CampaignDate.tsx
new file mode 100644
index 000000000000..81f5370c9ffd
--- /dev/null
+++ b/packages/twenty-front/src/pages/campaigns/CampaignDate.tsx
@@ -0,0 +1,125 @@
+/* eslint-disable no-restricted-imports */
+import React from 'react';
+import styled from '@emotion/styled';
+import { Section } from '@react-email/components';
+import { IconArrowLeft } from '@tabler/icons-react';
+import { IconArrowRight } from '@tabler/icons-react';
+import { Button } from 'tsup.ui.index';
+
+import { H2Title } from '@/ui/display/typography/components/H2Title';
+import DateTimePicker from '@/ui/input/components/internal/date/components/DateTimePicker';
+import { useCampaign } from '~/pages/campaigns/CampaignUseContext';
+
+const StyledCard = styled.div`
+ border: 1px solid ${({ theme }) => theme.border.color.medium};
+ border-radius: ${({ theme }) => theme.border.radius.sm};
+ color: ${({ theme }) => theme.font.color.secondary};
+ box-shadow: ${({ theme }) => theme.boxShadow.strong};
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ background: ${({ theme }) => theme.background.primary};
+ height: 90%;
+ width: 70%;
+ margin: auto;
+ align-items: center;
+`;
+
+const StyledInputCard = styled.div`
+ color: ${({ theme }) => theme.font.color.secondary};
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ height: 65%;
+ justify-content: space-between;
+ width: 70%;
+ align-items: center;
+`;
+
+const StyledTitleCard = styled.div`
+ /* align-items: center; */
+ color: ${({ theme }) => theme.font.color.secondary};
+ display: flex;
+ flex-direction: column;
+ height: 10%;
+ width: 100%;
+ justify-content: flex-start;
+`;
+
+const StyledButton = styled.span`
+ display: flex;
+ justify-content: space-between;
+ width: 100%;
+`;
+const StyledLabel = styled.span`
+ color: ${({ theme }) => theme.font.color.light};
+ font-size: ${({ theme }) => theme.font.size.xs};
+ font-weight: ${({ theme }) => theme.font.weight.semiBold};
+ margin-bottom: ${({ theme }) => theme.spacing(1)};
+ text-transform: uppercase;
+`;
+
+export const CampaignDate = () => {
+ const { setCurrentStep, currentStep, campaignData, setCampaignData } =
+ useCampaign();
+
+ return (
+ <>
+
+
+
+
+
+ Start Date
+ {
+ setCampaignData({
+ ...campaignData,
+ startDate: date,
+ });
+ }}
+ minDate={new Date()}
+ showTimeInput
+ />
+
+
+ End Date
+ {
+ setCampaignData({
+ ...campaignData,
+ endDate: date,
+ });
+ }}
+ minDate={campaignData.startDate}
+ showTimeInput
+ />
+
+
+
+ setCurrentStep(currentStep - 1)}
+ />
+ setCurrentStep(currentStep + 1)}
+ />
+
+
+
+ >
+ );
+};
diff --git a/packages/twenty-front/src/pages/campaigns/CampaignDetails.tsx b/packages/twenty-front/src/pages/campaigns/CampaignDetails.tsx
new file mode 100644
index 000000000000..06f6a0b157c8
--- /dev/null
+++ b/packages/twenty-front/src/pages/campaigns/CampaignDetails.tsx
@@ -0,0 +1,143 @@
+/* eslint-disable no-restricted-imports */
+import styled from '@emotion/styled';
+import { Section } from '@react-email/components';
+import { IconArrowLeft } from '@tabler/icons-react';
+import { IconArrowRight } from '@tabler/icons-react';
+import { Button, TextArea, TextInput } from 'tsup.ui.index';
+
+import { H2Title } from '@/ui/display/typography/components/H2Title';
+import { useCampaign } from '~/pages/campaigns/CampaignUseContext';
+
+const StyledCard = styled.div`
+ border: 1px solid ${({ theme }) => theme.border.color.medium};
+ border-radius: ${({ theme }) => theme.border.radius.sm};
+ color: ${({ theme }) => theme.font.color.secondary};
+ box-shadow: ${({ theme }) => theme.boxShadow.strong};
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ background: ${({ theme }) => theme.background.primary};
+ height: 90%;
+ width: 70%;
+ margin: auto;
+ align-items: center;
+`;
+
+const StyledInputCard = styled.div`
+ color: ${({ theme }) => theme.font.color.secondary};
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ height: 65%;
+ justify-content: space-between;
+ width: 70%;
+ align-items: center;
+`;
+
+const StyledTitleCard = styled.div`
+ /* align-items: center; */
+ color: ${({ theme }) => theme.font.color.secondary};
+ display: flex;
+ flex-direction: column;
+ height: 10%;
+ width: 100%;
+ justify-content: flex-start;
+`;
+
+const StyledAreaLabel = styled.span`
+ align-content: flex-start;
+ display: flex;
+ flex-direction: column;
+ margin-bottom: 2%;
+ width: 100%;
+`;
+const StyledButton = styled.span`
+ display: flex;
+ justify-content: space-between;
+ width: 100%;
+`;
+const StyledLabel = styled.span`
+ color: ${({ theme }) => theme.font.color.light};
+ font-size: ${({ theme }) => theme.font.size.xs};
+ font-weight: ${({ theme }) => theme.font.weight.semiBold};
+ margin-bottom: ${({ theme }) => theme.spacing(1)};
+ text-transform: uppercase;
+`;
+
+const StyledTitle = styled.h3`
+ color: ${({ theme }) => theme.font.color.secondary};
+ font-weight: ${({ theme }) => theme.font.weight.medium};
+ font-size: ${({ theme }) => theme.font.size.md};
+`;
+
+export const CampaignDetails = () => {
+ const { setCurrentStep, campaignData, setCampaignData, currentStep } =
+ useCampaign();
+ const handleCampaignChange = (_event: Event | undefined): void => {
+ throw new Error('Function not implemented.');
+ };
+
+ return (
+ <>
+
+
+
+
+
+
+
+
+ setCampaignData({
+ ...campaignData,
+ campaignName: e,
+ })
+ }
+ name="campaignName"
+ required
+ fullWidth
+ />
+
+
+
+
+
+
+
+ setCurrentStep(currentStep + 1)}
+ />
+
+
+
+ >
+ );
+};
diff --git a/packages/twenty-front/src/pages/campaigns/CampaignForm.tsx b/packages/twenty-front/src/pages/campaigns/CampaignForm.tsx
new file mode 100644
index 000000000000..fe3c889d80b5
--- /dev/null
+++ b/packages/twenty-front/src/pages/campaigns/CampaignForm.tsx
@@ -0,0 +1,354 @@
+import { useEffect, useState } from 'react';
+import styled from '@emotion/styled';
+import { Section } from '@react-email/components';
+import { Button } from '@/ui/input/button/components/Button';
+import base64 from 'base64-js';
+import { H2Title } from '@/ui/display/typography/components/H2Title';
+import { useNavigate, useParams } from 'react-router-dom';
+import AnimatedPlaceholder from '@/ui/layout/animated-placeholder/components/AnimatedPlaceholder';
+import {
+ AnimatedPlaceholderErrorContainer,
+ AnimatedPlaceholderErrorTitle,
+} from '@/ui/layout/animated-placeholder/components/ErrorPlaceholderStyled';
+import { addTracingExtensions } from '@sentry/react';
+import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
+import axios from 'axios';
+import { AppPath } from '@/types/AppPath';
+import { Checkbox, CheckboxVariant, CheckboxSize, CheckboxShape } from '@/ui/input/components/Checkbox';
+import { Select } from '@/ui/input/components/Select';
+import { TextArea } from '@/ui/input/components/TextArea';
+import { TextInput } from '@/ui/input/components/TextInput';
+import { AnimatedPlaceholderEmptyTextContainer } from '@/ui/layout/animated-placeholder/components/EmptyPlaceholderStyled';
+const StyledCard = styled.div`
+ border: 1px solid ${({ theme }) => theme.border.color.medium};
+ border-radius: ${({ theme }) => theme.border.radius.sm};
+ color: ${({ theme }) => theme.font.color.secondary};
+ box-shadow: ${({ theme }) => theme.boxShadow.strong};
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ background: ${({ theme }) => theme.background.primary};
+ height: 120%%;
+ width: 70%;
+ margin: auto;
+ align-items: center;
+ margin-bottom: ${({ theme }) => theme.spacing(2)};
+`;
+
+const StyledDiv = styled.div`
+ overflow-y: scroll;
+ border: 1px solid ${({ theme }) => theme.border.color.medium};
+ border-radius: ${({ theme }) => theme.border.radius.sm};
+ color: ${({ theme }) => theme.font.color.secondary};
+ box-shadow: ${({ theme }) => theme.boxShadow.strong};
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ background: ${({ theme }) => theme.background.primary};
+ height: auto%;
+ width: 100%;
+ margin: auto;
+ align-items: center;
+ margin-bottom: ${({ theme }) => theme.spacing(2)};
+`;
+
+const StyledTitleContainer = styled.div`
+ align-items: center;
+ display: flex;
+ justify-content: space-between;
+`;
+
+const StyledTitle = styled.h2`
+ color: ${({ theme }) => theme.font.color.primary};
+ font-size: ${({ theme }) => theme.font.size.lg};
+ font-weight: ${({ theme }) => theme.font.weight.semiBold};
+ padding: ${({ theme }) => theme.spacing(6)};
+`;
+const StyledInputCard = styled.div`
+ color: ${({ theme }) => theme.font.color.secondary};
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ height: 1005%;
+ justify-content: space-between;
+ width: 70%;
+ align-items: center;
+`;
+
+const StyledCheckboxInput = styled.div`
+ margin-top: ${({ theme }) => theme.spacing(4)};
+`;
+
+const StyledAreaLabel = styled.span`
+ align-content: flex-start;
+ display: flex;
+ flex-direction: column;
+ margin-bottom: 2%;
+ width: 100%;
+`;
+const StyledButton = styled.span`
+ display: flex;
+ justify-content: space-between;
+ width: 100%;
+ margin-bottom: ${({ theme }) => theme.spacing(6)};
+ margin-top: ${({ theme }) => theme.spacing(6)};
+`;
+
+const StyledCheckboxLabel = styled.span`
+ margin-left: ${({ theme }) => theme.spacing(2)};
+`;
+
+const StyledComboInputContainer = styled.div`
+ display: flex;
+ flex-direction: row;
+ > * + * {
+ margin-left: ${({ theme }) => theme.spacing(4)};
+ }
+`;
+
+ // const generateRandomId = (username: string, formId: string, campaignname: string) => {
+ // const randomId = `${username}-${formId}-${campaignname}`;
+ // const encodedRandomId = base64.fromByteArray(new TextEncoder().encode(randomId));
+ // return encodedRandomId;
+ // }
+
+ // const username = "Ertha Creboe";
+ // const formname = "abc";
+ // const campaignname = "Healthy Lives";
+
+ // const randomId = generateRandomId(username, formname, campaignname);
+ // console.log("Encoded Random ID:", randomId);
+
+export const CampaignForm = () => {
+ const [firstName, setFirstName] = useState('');
+ const [lastName, setLastName] = useState('');
+ const [contact, setContact] = useState('');
+ const [email, setEmail] = useState('');
+ const [comments, setComments] = useState('');
+ const [loading, setLoading] = useState(true);
+ const [errorType, setErrorType] = useState('');
+ const [location, setLocation] = useState('');
+ const [apptDate, setAptDate] = useState(null);
+ const [apptType, setApptType] = useState('');
+ const { userid } = useParams<{ userid: string }>();
+ const { enqueueSnackBar } = useSnackBar();
+ console.log('USERID', userid);
+ const navigate = useNavigate();
+ const createOptions = (options: any[]) =>
+ options.map((option: any) => ({ label: option, value: option }));
+ const locationOptions = createOptions([
+ 'Yelhanka',
+ 'Rajajinagar',
+ 'Nagawara',
+ ]);
+ const apptTypeOptions = createOptions(['Initial Consultation', 'Follow-up']);
+
+
+ const handleSubmit = async () => {
+ const formData = {
+ email,
+ firstName,
+ lastName,
+ appointmentDate: apptDate,
+ contactNumber: contact,
+ appointmentLocation: location,
+ reasonForAppointment: comments,
+ consent: 'I agree',
+ appointmentType: apptType,
+ };
+
+ try{
+ const response = await axios.post(`http://localhost:3000/campaign/save/${userid}`, formData);
+ console.log('Form data saved,', response.data);
+ enqueueSnackBar('Form Submitted Successfully!',{
+ variant: 'success',
+ });
+ if(response.data){
+ navigate(AppPath.SignInUp)
+ }
+ }
+ catch(error){
+ console.log("error in saving form data:", error)
+ }
+ }
+ useEffect(() => {
+ const fetchUserDetails = async () => {
+ try {
+ const response = await fetch(
+ `http://localhost:3000/campaign/${userid}`,
+ );
+ const userData = await response.json();
+ if(!userData.name){
+ throw new Error('Failed to fetch user details');
+ }
+ console.log('setting user details....');
+ setFirstName(userData.name);
+ setEmail(userData.email);
+ setLoading(false);
+
+ } catch (error: any) {
+ console.error('error in fetching user details', error);
+ if (error.message === 'Form expired') {
+ setErrorType('formexpired');
+ } else {
+ setErrorType('othererror');
+ }
+ }
+ };
+ fetchUserDetails();
+ }, [userid]);
+
+ // if (loading) {
+ // return (
+ // <>
+ //
+ //
+ //
+ // Collecting form data...
+ //
+ //
+ //
+ // >
+ // );
+ // } else
+if (loading && errorType === 'formexpired') {
+ return (
+ <>
+
+
+
+
+ Oops! We are not taking responses anymore.
+
+
+
+ >
+ );
+ }
+
+ return (
+ //div id - save id in form
+
+
+
+ Campaign Form
+
+
+
+
+ setFirstName(e)}
+ />
+
+
+
+ setLastName(e)}
+ />
+
+
+
+
+
+ setContact(e)}
+ />
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+};
diff --git a/packages/twenty-front/src/pages/campaigns/CampaignForm2.tsx b/packages/twenty-front/src/pages/campaigns/CampaignForm2.tsx
new file mode 100644
index 000000000000..326b615d9d96
--- /dev/null
+++ b/packages/twenty-front/src/pages/campaigns/CampaignForm2.tsx
@@ -0,0 +1,324 @@
+import { useEffect, useState } from 'react';
+import { useParams } from 'react-router-dom';
+import styled from '@emotion/styled';
+import { Section } from '@react-email/components';
+import { Button } from '@/ui/input/button/components/Button';
+
+import { H2Title } from '@/ui/display/typography/components/H2Title';
+import { Checkbox } from '@/ui/input/components/Checkbox';
+import { TextInput } from '@/ui/input/components/TextInput';
+
+const StyledCard = styled.div`
+ border: 1px solid ${({ theme }) => theme.border.color.medium};
+ border-radius: ${({ theme }) => theme.border.radius.sm};
+ color: ${({ theme }) => theme.font.color.secondary};
+ box-shadow: ${({ theme }) => theme.boxShadow.strong};
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ background: ${({ theme }) => theme.background.primary};
+ height: 95%;
+ width: 70%;
+ margin: auto;
+ align-items: center;
+ margin-bottom: ${({ theme }) => theme.spacing(2)};
+ overflow-y: scroll;
+`;
+
+const StyledFormTitle = styled.h3`
+ color: ${({ theme }) => theme.font.color.primary};
+ font-weight: ${({ theme }) => theme.font.weight.semiBold};
+`;
+
+const StyledTitleContainer = styled.div`
+ align-items: center;
+ display: flex;
+ justify-content: space-between;
+`;
+
+const StyledTitle = styled.h2`
+ color: ${({ theme }) => theme.font.color.primary};
+ font-size: ${({ theme }) => theme.font.size.lg};
+ font-weight: ${({ theme }) => theme.font.weight.semiBold};
+ padding: ${({ theme }) => theme.spacing(6)};
+`;
+const StyledInputCard = styled.div`
+ color: ${({ theme }) => theme.font.color.secondary};
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ height: 100%;
+ justify-content: space-between;
+ width: 70%;
+ align-items: center;
+ overflow-y: scroll;
+`;
+
+const StyledCheckboxInput = styled.div`
+ display: flex;
+ align-items: center;
+ margin-top: ${({ theme }) => theme.spacing(1)};
+`;
+
+const StyledAreaLabel = styled.span`
+ align-content: flex-start;
+ display: flex;
+ flex-direction: column;
+ margin-bottom: 2%;
+ width: 100%;
+`;
+const StyledButton = styled.span`
+ display: flex;
+ justify-content: space-between;
+ width: 100%;
+`;
+
+const StyledCheckboxLabel = styled.span`
+ margin-left: ${({ theme }) => theme.spacing(2)};
+`;
+
+const StyledComboInputContainer = styled.div`
+ display: flex;
+ flex-direction: row;
+ > * + * {
+ margin-left: ${({ theme }) => theme.spacing(4)};
+ }
+`;
+
+export const CampaignForm2 = () => {
+ const [firstName, setFirstName] = useState('');
+ const [lastName, setLastName] = useState('');
+ const [contact, setContact] = useState('');
+ const [email, setEmail] = useState('');
+ const [age, setAge] = useState('');
+ const [bloodType, setBloodType] = useState('');
+
+ const [symptoms, setSymptoms] = useState({
+ fever: false,
+ cough: false,
+ fatigue: false,
+ headache: false,
+ });
+
+ const [travelHistory, setTravelHistory] = useState({
+ withinCountry: false,
+ international: false,
+ });
+
+ const [contactWithCovid, setContactWithCovid] = useState(false);
+ const [loading, setLoading] = useState(true);
+ const [errorType, setErrorType] = useState('');
+ const { userid } = useParams<{ userid: string }>();
+ console.log('USERID', userid);
+
+ useEffect(() => {
+ const fetchUserDetails = async () => {
+ try {
+ const response = await fetch(
+ `http://localhost:3000/campaign/${userid}`,
+ );
+ if (!response.ok) {
+ throw new Error('Failed to fetch user details');
+ }
+ const userData = await response.json();
+ console.log('setting user details....');
+ setFirstName(userData.name);
+ setEmail(userData.email);
+ setLoading(false);
+ } catch (error: any) {
+ console.error('error in fetching user details', error);
+ if (error.message === 'Form expired') {
+ setErrorType('formexpired');
+ } else {
+ setErrorType('othererror');
+ }
+ }
+ };
+ fetchUserDetails();
+ }, [userid]);
+
+ const handleSymptomCheckboxChange = (symptom: string) => {
+ setSymptoms({
+ ...symptoms,
+ [symptom]: !symptoms[symptom],
+ });
+ };
+
+ const handleTravelHistoryCheckboxChange = (history: string) => {
+ setTravelHistory({
+ ...travelHistory,
+ [history]: !travelHistory[history],
+ });
+ };
+
+ return (
+ <>
+
+
+ Health Screening Form
+
+
+
+
+ setFirstName(e)}
+ />
+
+
+
+ setLastName(e)}
+ />
+
+
+
+
+ setContact(e)}
+ />
+
+
+
+
+
+
+ setBloodType(e)}
+ />
+
+
+
+
+
+
+ handleSymptomCheckboxChange('fever')}
+ />
+ Fever
+
+
+ handleSymptomCheckboxChange('cough')}
+ />
+ Cough
+
+
+ handleSymptomCheckboxChange('fatigue')}
+ />
+ Fatigue
+
+
+ handleSymptomCheckboxChange('headache')}
+ />
+ Headache
+
+
+
+
+
+
+
+
+
+ handleTravelHistoryCheckboxChange('withinCountry')
+ }
+ />
+ Within Country
+
+
+
+ handleTravelHistoryCheckboxChange('international')
+ }
+ />
+ International
+
+
+
+
+
+
+
+ setContactWithCovid(!contactWithCovid)}
+ />
+ Yes, I have
+
+
+
+
+
+
+
+
+ >
+ );
+};
\ No newline at end of file
diff --git a/packages/twenty-front/src/pages/campaigns/CampaignForm3.tsx b/packages/twenty-front/src/pages/campaigns/CampaignForm3.tsx
new file mode 100644
index 000000000000..7e0ba3ae4993
--- /dev/null
+++ b/packages/twenty-front/src/pages/campaigns/CampaignForm3.tsx
@@ -0,0 +1,403 @@
+import { useEffect, useState } from 'react';
+import { useParams } from 'react-router-dom';
+import styled from '@emotion/styled';
+import { Section } from '@react-email/components';
+import { Button } from '@/ui/input/button/components/Button';
+
+import { H2Title } from '@/ui/display/typography/components/H2Title';
+import { Checkbox, CheckboxVariant, CheckboxSize, CheckboxShape } from '@/ui/input/components/Checkbox';
+import { TextInput } from '@/ui/input/components/TextInput';
+
+const StyledCard = styled.div`
+ border: 1px solid ${({ theme }) => theme.border.color.medium};
+ border-radius: ${({ theme }) => theme.border.radius.sm};
+ color: ${({ theme }) => theme.font.color.secondary};
+ box-shadow: ${({ theme }) => theme.boxShadow.strong};
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ background: ${({ theme }) => theme.background.primary};
+ height: 95%;
+ width: 70%;
+ margin: auto;
+ align-items: center;
+ margin-bottom: ${({ theme }) => theme.spacing(2)}
+ overflow-y: scroll;
+`;
+
+const StyledFormTitle = styled.h3`
+ color: ${({ theme }) => theme.font.color.primary};
+ font-weight: ${({ theme }) => theme.font.weight.semiBold};
+`;
+
+const StyledTitleContainer = styled.div`
+ align-items: center;
+ display: flex;
+ justify-content: space-between;
+`;
+
+const StyledTitle = styled.h2`
+ color: ${({ theme }) => theme.font.color.primary};
+ font-size: ${({ theme }) => theme.font.size.lg};
+ font-weight: ${({ theme }) => theme.font.weight.semiBold};
+ padding: ${({ theme }) => theme.spacing(6)};
+`;
+const StyledInputCard = styled.div`
+ color: ${({ theme }) => theme.font.color.secondary};
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ height: 1005%;
+ justify-content: space-between;
+ width: 70%;
+ align-items: center;
+`;
+
+const StyledCheckboxInput = styled.div`
+ margin-top: ${({ theme }) => theme.spacing(4)};
+`;
+
+interface PreexistingConditions {
+ diabetes: boolean;
+ asthma: boolean;
+ seizures: boolean;
+ bloodpressure: boolean;
+}
+
+interface PreexistingDiseases {
+ cardiovascular: boolean;
+ respiratory: boolean;
+ genitourinary: boolean;
+ cns: boolean;
+ other: boolean;
+}
+
+const StyledAreaLabel = styled.span`
+ align-content: flex-start;
+ display: flex;
+ flex-direction: column;
+ margin-bottom: 2%;
+ width: 100%;
+`;
+const StyledButton = styled.span`
+ display: flex;
+ justify-content: space-between;
+ width: 100%;
+`;
+
+const StyledCheckboxLabel = styled.span`
+ margin-left: ${({ theme }) => theme.spacing(2)};
+`;
+
+const StyledComboInputContainer = styled.div`
+ display: flex;
+ flex-direction: row;
+ > * + * {
+ margin-left: ${({ theme }) => theme.spacing(4)};
+ }
+`;
+
+export const CampaignForm3 = () => {
+ const [firstName, setFirstName] = useState('');
+ const [lastName, setLastName] = useState('');
+ const [contact, setContact] = useState('');
+ const [email, setEmail] = useState('');
+ const [height, setHeight] = useState('');
+ const [weight, setWeight] = useState('');
+
+ const [preexistingConditions, setPreexistingConditions] =
+ useState({
+ diabetes: false,
+ asthma: false,
+ seizures: false,
+ bloodpressure: false,
+ });
+
+ const [preexistingDiseases, setPreexistingDiseases] =
+ useState({
+ cardiovascular: false,
+ respiratory: false,
+ genitourinary: false,
+ cns: false,
+ other: false,
+ });
+ const [gender, setGender] = useState('');
+ const [comments, setComments] = useState('');
+ const [loading, setLoading] = useState(true);
+ const [errorType, setErrorType] = useState('');
+ const { userid } = useParams<{ userid: string }>();
+ console.log('USERID', userid);
+
+ useEffect(() => {
+ const fetchUserDetails = async () => {
+ try {
+ const response = await fetch(
+ `http://localhost:3000/campaign/${userid}`,
+ );
+ if (!response.ok) {
+ throw new Error('Failed to fetch user details');
+ }
+ const userData = await response.json();
+ console.log('setting user details....');
+ setFirstName(userData.name);
+ setEmail(userData.email);
+ setLoading(false);
+ } catch (error: any) {
+ console.error('error in fetching user details', error);
+ if (error.message === 'Form expired') {
+ setErrorType('formexpired');
+ } else {
+ setErrorType('othererror');
+ }
+ }
+ };
+ fetchUserDetails();
+ }, [userid]);
+
+ const handleConditionCheckboxChange = (
+ condition: keyof PreexistingConditions,
+ ) => {
+ setPreexistingConditions({
+ ...preexistingConditions,
+ [condition]: !preexistingConditions[condition],
+ });
+ };
+
+ const handleDiseaseCheckboxChange = (
+ condition: keyof PreexistingDiseases,
+ ) => {
+ setPreexistingDiseases({
+ ...preexistingDiseases,
+ [condition]: !preexistingDiseases[condition],
+ });
+ };
+
+ return (
+ <>
+
+
+ Medical Fitness Form
+
+
+
+
+ setFirstName(e)}
+ />
+
+
+
+ setLastName(e)}
+ />
+
+
+
+
+ setContact(e)}
+ />
+
+
+
+
+
+
+ Male
+
+ Female
+
+ Others
+
+
+
+
+
+
+
+
+
+
+
+
+
+ handleConditionCheckboxChange('diabetes')}
+ />
+ Diabetes
+
+
+ handleConditionCheckboxChange('asthma')}
+ />
+ Asthma
+
+
+ handleConditionCheckboxChange('seizures')}
+ />
+ Seizures
+
+
+ handleConditionCheckboxChange('bloodpressure')}
+ />
+ BloodPressure
+
+
+
+
+
+
+ handleDiseaseCheckboxChange('cardiovascular')}
+ />
+ Cardiovascular
+
+
+ handleDiseaseCheckboxChange('respiratory')}
+ />
+ Respiratory
+
+
+ handleDiseaseCheckboxChange('genitourinary')}
+ />
+ Genitourinary
+
+
+ handleDiseaseCheckboxChange('cns')}
+ />
+
+ CNS (Central Nervous System)
+
+
+
+ handleDiseaseCheckboxChange('other')}
+ />
+ Other
+
+
+
+
+
+
+
+
+ I agree to the terms and conditions.
+
+
+
+
+
+
+
+
+ >
+ );
+};
diff --git a/packages/twenty-front/src/pages/campaigns/CampaignUseContext.tsx b/packages/twenty-front/src/pages/campaigns/CampaignUseContext.tsx
new file mode 100644
index 000000000000..931f9830aabf
--- /dev/null
+++ b/packages/twenty-front/src/pages/campaigns/CampaignUseContext.tsx
@@ -0,0 +1,14 @@
+import { useContext } from 'react';
+
+import {
+ CampaignContextProps,
+ CampaignMultiStepContext,
+} from '~/pages/campaigns/CampaignContext';
+
+export const useCampaign = (): CampaignContextProps => {
+ const context = useContext(CampaignMultiStepContext);
+ if (!context) {
+ throw new Error('useCampaign must be used within a CampaignProvider');
+ }
+ return context;
+};
diff --git a/packages/twenty-front/src/pages/campaigns/Campaigns.tsx b/packages/twenty-front/src/pages/campaigns/Campaigns.tsx
new file mode 100644
index 000000000000..8f5bc8fc47c6
--- /dev/null
+++ b/packages/twenty-front/src/pages/campaigns/Campaigns.tsx
@@ -0,0 +1,488 @@
+import styled from '@emotion/styled';
+import { Section } from '@react-email/components';
+import { Button } from '@/ui/input/button/components/Button';
+import { IconSpeakerphone } from '@tabler/icons-react';
+import { ChangeEvent, useEffect, useState } from 'react';
+import { H2Title } from '@/ui/display/typography/components/H2Title';
+import { useCampaign } from '~/pages/campaigns/CampaignUseContext';
+import { GRAY_SCALE } from '@/ui/theme/constants/GrayScale';
+import { PageHeader } from '@/ui/layout/page/PageHeader';
+import { ADD_CAMPAIGN } from '@/users/graphql/queries/addCampaign';
+import { useMutation, useQuery } from '@apollo/client';
+import { v4 as uuidv4 } from 'uuid';
+import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
+import { GET_MESSAGE_TEMPLATES } from '@/users/graphql/queries/getMessageTemplates';
+import { GET_SPECIALTY } from '@/users/graphql/queries/getSpecialtyDetails';
+import { GET_SEGMENT_LISTS } from '@/users/graphql/queries/getSegments';
+import { GET_FORM_TEMPLATES } from '@/users/graphql/queries/getFormTemplates';
+import { useNavigate } from 'react-router-dom';
+import { Checkbox, CheckboxVariant, CheckboxSize, CheckboxShape } from '@/ui/input/components/Checkbox';
+import { Select } from '@/ui/input/components/Select';
+import { TextInput } from '@/ui/input/components/TextInput';
+import { title } from 'process';
+const StyledCheckboxLabel = styled.span`
+ margin-left: ${({ theme }) => theme.spacing(2)};
+`;
+
+const StyledInputCard = styled.div`
+ color: ${({ theme }) => theme.font.color.secondary};
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ height: 65%;
+ justify-content: space-between;
+ width: 70%;
+ align-items: center;
+`;
+
+const PageContainer = styled.div`
+ display: flex;
+ flex-direction: column;
+ width: 100%;
+ overflow-y: scroll;
+`;
+
+const StyledButton = styled.span`
+ display: flex;
+ justify-content: space-between;
+ width: 100%;
+ margin: ${({ theme }) => theme.spacing(10)};
+`;
+const StyledLabel = styled.span`
+ color: ${({ theme }) => theme.font.color.light};
+ font-size: ${({ theme }) => theme.font.size.xs};
+ font-weight: ${({ theme }) => theme.font.weight.semiBold};
+ margin-left: ${({ theme }) => theme.spacing(2)};
+ display: flex;
+ align-items: center;
+ text-transform: uppercase;
+`;
+
+const SytledHR = styled.hr`
+ background: ${GRAY_SCALE.gray0};
+ color: ${GRAY_SCALE.gray0};
+ bordercolor: ${GRAY_SCALE.gray0};
+ height: 0.2px;
+ width: 100%;
+ margin: ${({ theme }) => theme.spacing(8)};
+`;
+
+const StyledBoardContainer = styled.div`
+ display: flex;
+ height: 100%;
+ width: 100%;
+ flex-direction: column;
+ align-items: flex-start;
+ justify-content: flex-start;
+ background: ${({ theme }) => theme.background.noisy};
+ padding: ${({ theme }) => theme.spacing(2)};
+`;
+
+const StyledSection = styled(Section)`
+ align-items: flex-start;
+ display: flex;
+ justify-content: space-between;
+ margin-bottom: 16px;
+ margin-left: 0;
+`;
+
+const StyledComboInputContainer = styled.div`
+ display: flex;
+ align-items: center;
+ > * + * {
+ margin-left: ${({ theme }) => theme.spacing(4)};
+ }
+`;
+type MessageTemplate = {
+ type: string;
+ value: string;
+ label: string;
+};
+type SegmentList = {
+ type: string;
+ value: string;
+ label: string;
+};
+export const Campaigns = () => {
+ const [messageTemplates, setMessageTemplates] = useState(
+ [],
+ );
+ const navigate = useNavigate();
+ const { loading: templatesLoading, data: templatesData } = useQuery(
+ GET_MESSAGE_TEMPLATES,
+ );
+ const fetchTemplates = (channelType: string) => {
+ const channelTemplates = templatesData?.messageTemplates.edges
+ .filter(
+ (edge: { node: any }) =>
+ edge.node?.channelType === channelType,
+ )
+ .map((edge: { node: any }) => ({
+ value: edge.node?.id,
+ label: edge.node?.name,
+ }));
+ setMessageTemplates(channelTemplates);
+ };
+
+ const [segmentsList, setSegmentsList] = useState([]);
+ const { loading: segmentLoading, data: segmentsData } =
+ useQuery(GET_SEGMENT_LISTS);
+ const fetchSegments = () => {
+ if (!segmentLoading) {
+ const segments = segmentsData?.segments.edges.map(
+ (edge: { node: any }) => ({
+ value: edge.node?.id,
+ label: edge.node?.name,
+ }),
+ );
+ setSegmentsList(segments);
+ }
+ };
+
+ const [formTemplates, setFormTemplates] = useState([]);
+ const { loading: formTemplateLoading, data: formTemplateData } =
+ useQuery(GET_FORM_TEMPLATES);
+
+ const fetchFormTemplates = () => {
+ console.log(formTemplateData, '>>>>>>>>>>>>');
+ if (!formTemplateLoading) {
+ const forms = formTemplateData?.formTemplates.edges.map(
+ (edge: { node: any }) => ({
+ value: edge.node?.id,
+ label: edge.node?.name,
+ }),
+ );
+ setFormTemplates(forms);
+ }
+ };
+
+ console.log(messageTemplates, 'MESSAGE TEMPLATES');
+ console.log(formTemplates, 'FORM TEMPLATES');
+ useEffect(() => {
+ fetchSegments();
+ fetchFormTemplates();
+ }, [segmentLoading, formTemplateLoading]);
+
+ let Specialty: any = [];
+ const { loading: queryLoading, data: queryData } = useQuery(GET_SPECIALTY);
+
+ const SpecialtyTypes: any = {};
+ const [specialty, setSpecialty] = useState('');
+ const [subSpecialty, setSubSpecialty] = useState('');
+ if (!queryLoading) {
+ const specialtyTypes = queryData?.subspecialties.edges.map(
+ (edge: { node: { specialty: { name: any } } }) =>
+ edge?.node?.specialty?.name,
+ );
+ const uniqueSpecialtyTypes = Array.from(new Set(specialtyTypes));
+ Specialty = uniqueSpecialtyTypes.map((specialty) => ({
+ value: specialty,
+ label: specialty,
+ }));
+ console.log(queryData, 'UNIQYUE SPECIALTY');
+ queryData?.subspecialties.edges.forEach(
+ (edge: { node: { specialty: { name: any }; name: any } }) => {
+ const specialtyType = edge.node?.specialty?.name;
+ const subSpecialty = edge.node.name;
+
+ // If the specialty type is already a key in the dictionary, push the sub-specialty to its array
+ if (SpecialtyTypes[specialtyType]) {
+ SpecialtyTypes[specialtyType].push({
+ value: subSpecialty,
+ label: subSpecialty,
+ });
+ } else {
+ // If the specialty type is not yet a key, create a new array with the sub-specialty as its first element
+ SpecialtyTypes[specialtyType] = [];
+ SpecialtyTypes[specialtyType].push({
+ value: subSpecialty,
+ label: subSpecialty,
+ });
+ }
+ },
+ );
+ }
+
+ const handleSpecialtySelectChange = (selectedValue: any) => {
+ setSpecialty(selectedValue);
+ };
+
+ const handleSubSpecialtySelectChange = (selectedValue: any) => {
+ setSubSpecialty(selectedValue);
+ };
+
+ const { campaignData, setCampaignData } =
+ useCampaign();
+
+ const { enqueueSnackBar } = useSnackBar();
+ const onSelectCheckBoxChange = (
+ event: ChangeEvent,
+ channel: string,
+ ): void => {
+ // throw new Error('Function not implemented.');
+ setCampaignData((prevData: any) => ({
+ ...prevData,
+ [channel]: event.target.checked,
+ }));
+ };
+ const [addCampaigns, { loading, error }] = useMutation(ADD_CAMPAIGN);
+ const handleSave = async () => {
+ try {
+ console.log( campaignData.whatsappTemplate,"message templates")
+ const messageTemplateId = campaignData.whatsappTemplate?campaignData.whatsappTemplate:campaignData.emailTemplate?campaignData.emailTemplate:null
+ const variables = {
+ input: {
+ name: campaignData.campaignName,
+ description: campaignData.campaignDescription,
+ messageTemplateId: messageTemplateId,
+ specialty: specialty,
+ subspecialty: subSpecialty,
+ segmentId: campaignData.targetAudience,
+ formTemplateId: campaignData.pageUrl
+ },
+ };
+ console.log('Variables: ', variables);
+ const { data } = await addCampaigns({
+ variables: variables,
+ });
+ enqueueSnackBar('Campaign added successfully', {
+ variant: 'success',
+ });
+ navigate('/objects/campaigns')
+ window.location.reload();
+ } catch (errors: any) {
+ console.error('Error adding campaign:', error);
+ enqueueSnackBar(errors.message + 'Error while adding Campaign', {
+ variant: 'error',
+ });
+ }
+ };
+
+ return (
+
+
+
+
+
+
+
+
+ setCampaignData({
+ ...campaignData,
+ campaignName: e,
+ })
+ }
+ name="campaignName"
+ required
+ fullWidth
+ />
+
+
+
+
+
+ setCampaignData({
+ ...campaignData,
+ campaignDescription: e,
+ })
+ }
+ name="campaignDescription"
+ required
+ fullWidth
+ />
+
+
+
+
+
+
+ {specialty && (
+ <>
+
+
+ >
+ )}
+
+
+
+
+
+
+
+
+
+
+
+ {
+ onSelectCheckBoxChange(event, 'WHATSAPP');
+ if (event.target.checked) {
+ fetchTemplates('WHATSAPP');
+ } else {
+ setMessageTemplates([]);
+ }
+ setCampaignData({
+ ...campaignData,
+ Whatsapp: event.target.checked,
+ Email: !event.target.checked
+ ? campaignData.Email
+ : false,
+ });
+ }}
+ variant={CheckboxVariant.Primary}
+ size={CheckboxSize.Small}
+ shape={CheckboxShape.Squared}
+ />
+ WhatsApp
+
+
+ {campaignData.Whatsapp && (
+
+
+
+
+ {
+ onSelectCheckBoxChange(event, 'EMAIL');
+ if (event.target.checked) {
+ fetchTemplates('EMAIL'); // Fetch Email templates
+ } else {
+ setMessageTemplates([]); // Reset templates when Email checkbox is unchecked
+ }
+ setCampaignData({
+ ...campaignData,
+ Email: event.target.checked,
+ Whatsapp: !event.target.checked
+ ? campaignData.Whatsapp
+ : false,
+ });
+ }}
+ variant={CheckboxVariant.Primary}
+ size={CheckboxSize.Small}
+ shape={CheckboxShape.Squared}
+ />
+ Email
+
+
+ {campaignData.Email && (
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+};
diff --git a/packages/twenty-front/src/pages/campaigns/Form1.tsx b/packages/twenty-front/src/pages/campaigns/Form1.tsx
new file mode 100644
index 000000000000..c9a87e0c7e01
--- /dev/null
+++ b/packages/twenty-front/src/pages/campaigns/Form1.tsx
@@ -0,0 +1,221 @@
+import { useState } from 'react';
+import styled from '@emotion/styled';
+import { Section } from '@react-email/components';
+import { H2Title } from '@/ui/display/typography/components/H2Title';
+import { Checkbox } from '@/ui/input/components/Checkbox';
+import { TextInput } from '@/ui/input/components/TextInput';
+
+const StyledDiv = styled.div``;
+
+const StyledCard = styled.div`
+ border: 1px solid ${({ theme }) => theme.border.color.medium};
+ border-radius: ${({ theme }) => theme.border.radius.sm};
+ color: ${({ theme }) => theme.font.color.secondary};
+ box-shadow: ${({ theme }) => theme.boxShadow.strong};
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ background: ${({ theme }) => theme.background.primary};
+ height: auto;
+ width: 100%;
+ margin: auto;
+ align-items: center;
+ margin-bottom: ${({ theme }) => theme.spacing(2)}
+ overflow-y: scroll;
+`;
+
+const StyledTitleContainer = styled.div`
+ align-items: center;
+ display: flex;
+ justify-content: space-between;
+`;
+
+const StyledTitle = styled.h2`
+ color: ${({ theme }) => theme.font.color.primary};
+ font-size: ${({ theme }) => theme.font.size.lg};
+ font-weight: ${({ theme }) => theme.font.weight.semiBold};
+ padding: ${({ theme }) => theme.spacing(6)};
+`;
+
+const StyledInputCard = styled.div`
+ color: ${({ theme }) => theme.font.color.secondary};
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ height: 1005%;
+ justify-content: space-between;
+ width: 70%;
+ align-items: center;
+`;
+
+const StyledAreaLabel = styled.span`
+ align-content: flex-start;
+ display: flex;
+ flex-direction: column;
+ margin-bottom: 2%;
+ width: 100%;
+`;
+
+const StyledSection = styled.div`
+ margin-bottom: ${({ theme }) => theme.spacing(6)};
+`;
+
+const StyledCheckboxInput = styled.div`
+ margin-top: ${({ theme }) => theme.spacing(4)};
+`;
+
+const StyledCheckboxLabel = styled.span`
+ margin-left: ${({ theme }) => theme.spacing(2)};
+`;
+
+const StyledComboInputContainer = styled.div`
+ display: flex;
+ flex-direction: row;
+ > * + * {
+ margin-left: ${({ theme }) => theme.spacing(4)};
+ }
+`;
+
+const StyledButton = styled.span`
+ display: flex;
+ justify-content: space-between;
+ width: 100%;
+`;
+
+export const Form1 = () => {
+ const [symptoms, setSymptoms] = useState({
+ fever: false,
+ cough: false,
+ fatigue: false,
+ headache: false,
+ });
+
+ const [travelHistory, setTravelHistory] = useState({
+ withinCountry: false,
+ international: false,
+ });
+ const [contactWithCovid, setContactWithCovid] = useState(false);
+
+ return (
+
+
+
+ Health Screening Form
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Fever
+
+ Cough
+
+ Fatigue
+
+ Headache
+
+
+
+
+
+
+
+
+
+ Within Country
+
+ International
+
+
+
+
+
+
+
+ Yes, I have
+
+
+
+
+
+
+
+ );
+};
diff --git a/packages/twenty-front/src/pages/campaigns/Form2.tsx b/packages/twenty-front/src/pages/campaigns/Form2.tsx
new file mode 100644
index 000000000000..573ad662cfaf
--- /dev/null
+++ b/packages/twenty-front/src/pages/campaigns/Form2.tsx
@@ -0,0 +1,223 @@
+import styled from '@emotion/styled';
+
+import { H2Title } from '@/ui/display/typography/components/H2Title';
+import { Checkbox, CheckboxVariant, CheckboxSize, CheckboxShape } from '@/ui/input/components/Checkbox';
+import { Select } from '@/ui/input/components/Select';
+import { TextArea } from '@/ui/input/components/TextArea';
+import { TextInput } from '@/ui/input/components/TextInput';
+
+const StyledDiv = styled.div``;
+
+const StyledCard = styled.div`
+ border: 1px solid ${({ theme }) => theme.border.color.medium};
+ border-radius: ${({ theme }) => theme.border.radius.sm};
+ color: ${({ theme }) => theme.font.color.secondary};
+ box-shadow: ${({ theme }) => theme.boxShadow.strong};
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ background: ${({ theme }) => theme.background.primary};
+ height: 120%%;
+ width: 100%;
+ margin: auto;
+ align-items: center;
+ margin-bottom: ${({ theme }) => theme.spacing(2)};
+`;
+
+const StyledTitleContainer = styled.div`
+ align-items: center;
+ display: flex;
+ justify-content: space-between;
+`;
+
+const StyledTitle = styled.h2`
+ color: ${({ theme }) => theme.font.color.primary};
+ font-size: ${({ theme }) => theme.font.size.lg};
+ font-weight: ${({ theme }) => theme.font.weight.semiBold};
+ padding: ${({ theme }) => theme.spacing(6)};
+`;
+
+const StyledInputCard = styled.div`
+ color: ${({ theme }) => theme.font.color.secondary};
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ height: 1005%;
+ justify-content: space-between;
+ width: 70%;
+ align-items: center;
+`;
+
+const StyledAreaLabel = styled.span`
+ align-content: flex-start;
+ display: flex;
+ flex-direction: column;
+ margin-bottom: 2%;
+ width: 100%;
+`;
+
+const StyledSection = styled.div`
+ margin-bottom: ${({ theme }) => theme.spacing(6)};
+`;
+
+const StyledCheckboxInput = styled.div`
+ margin-top: ${({ theme }) => theme.spacing(4)};
+`;
+
+const StyledCheckboxLabel = styled.span`
+ margin-left: ${({ theme }) => theme.spacing(2)};
+`;
+
+const StyledComboInputContainer = styled.div`
+ display: flex;
+ flex-direction: row;
+ > * + * {
+ margin-left: ${({ theme }) => theme.spacing(4)};
+ }
+`;
+
+const StyledButton = styled.span`
+ display: flex;
+ justify-content: space-between;
+ width: 100%;
+ margin-bottom: ${({ theme }) => theme.spacing(6)};
+ margin-top: ${({ theme }) => theme.spacing(6)};
+`;
+
+// const generateRandomId = (username: string, formId: string, campaignname: string) => {
+// const randomId = `${username}-${formId}-${campaignname}`;
+// const encodedRandomId = base64.fromByteArray(new TextEncoder().encode(randomId));
+// return encodedRandomId;
+// }
+
+// const username = "Ertha Creboe";
+// const formname = "abc";
+// const campaignname = "Healthy Lives";
+
+// const randomId = generateRandomId(username, formname, campaignname);
+// console.log("Encoded Random ID:", randomId);
+
+export const Form2 = () => {
+ const createOptions = (options: any[]) =>
+ options.map((option: any) => ({ label: option, value: option }));
+ const locationOptions = createOptions([
+ 'Yelhanka',
+ 'Rajajinagar',
+ 'Nagawara',
+ ]);
+ const apptTypeOptions = createOptions(['Initial Consultation', 'Follow-up']);
+
+ return (
+ //div id - save id in form
+
+
+
+ Campaign Form
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ I agree to the terms and conditions.
+
+
+
+
+
+
+ );
+};
diff --git a/packages/twenty-front/src/pages/campaigns/Form3.tsx b/packages/twenty-front/src/pages/campaigns/Form3.tsx
new file mode 100644
index 000000000000..ad52b167b136
--- /dev/null
+++ b/packages/twenty-front/src/pages/campaigns/Form3.tsx
@@ -0,0 +1,323 @@
+import { useState } from 'react';
+import styled from '@emotion/styled';
+
+
+import { H2Title } from '@/ui/display/typography/components/H2Title';
+import { Checkbox, CheckboxVariant, CheckboxSize, CheckboxShape } from '@/ui/input/components/Checkbox';
+import { TextInput } from '@/ui/input/components/TextInput';
+
+const StyledDiv = styled.div``;
+
+const StyledCard = styled.div`
+ border: 1px solid ${({ theme }) => theme.border.color.medium};
+ border-radius: ${({ theme }) => theme.border.radius.sm};
+ color: ${({ theme }) => theme.font.color.secondary};
+ box-shadow: ${({ theme }) => theme.boxShadow.strong};
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ background: ${({ theme }) => theme.background.primary};
+ height: auto;
+ width: 100%;
+ margin: auto;
+ align-items: center;
+ margin-bottom: ${({ theme }) => theme.spacing(2)}
+ overflow-y: scroll;
+`;
+
+const StyledTitleContainer = styled.div`
+ align-items: center;
+ display: flex;
+ justify-content: space-between;
+`;
+
+const StyledTitle = styled.h2`
+ color: ${({ theme }) => theme.font.color.primary};
+ font-size: ${({ theme }) => theme.font.size.lg};
+ font-weight: ${({ theme }) => theme.font.weight.semiBold};
+ padding: ${({ theme }) => theme.spacing(6)};
+`;
+
+
+const StyledInputCard = styled.div`
+ color: ${({ theme }) => theme.font.color.secondary};
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ height: 1005%;
+ justify-content: space-between;
+ width: 70%;
+ align-items: center;
+`;
+
+
+const StyledAreaLabel = styled.span`
+ align-content: flex-start;
+ display: flex;
+ flex-direction: column;
+ margin-bottom: 2%;
+ width: 100%;
+`;
+
+const StyledSection = styled.div`
+ margin-bottom: ${({ theme }) => theme.spacing(6)};
+`;
+
+const StyledCheckboxInput = styled.div`
+ margin-top: ${({ theme }) => theme.spacing(4)};
+`;
+
+const StyledCheckboxLabel = styled.span`
+ margin-left: ${({ theme }) => theme.spacing(2)};
+`;
+
+const StyledComboInputContainer = styled.div`
+ display: flex;
+ flex-direction: row;
+ > * + * {
+ margin-left: ${({ theme }) => theme.spacing(4)};
+ }
+`;
+
+const StyledButton = styled.span`
+ display: flex;
+ justify-content: space-between;
+ width: 100%;
+`;
+
+interface PreexistingConditions {
+ diabetes: boolean;
+ asthma: boolean;
+ seizures: boolean;
+ bloodpressure: boolean;
+}
+
+interface PreexistingDiseases {
+ cardiovascular: boolean;
+ respiratory: boolean;
+ genitourinary: boolean;
+ cns: boolean;
+ other: boolean;
+}
+
+
+
+
+export const Form3 = () => {
+
+ const [preexistingConditions, setPreexistingConditions] =
+ useState({
+ diabetes: false,
+ asthma: false,
+ seizures: false,
+ bloodpressure: false,
+ });
+
+ const [preexistingDiseases, setPreexistingDiseases] =
+ useState({
+ cardiovascular: false,
+ respiratory: false,
+ genitourinary: false,
+ cns: false,
+ other: false,
+ });
+
+
+ return (
+
+
+
+
+ Medical Fitness Form
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Male
+
+ Female
+
+ Others
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Diabetes
+
+ Asthma
+
+ Seizures
+
+ BloodPressure
+
+
+
+
+
+
+
+
+
+
+
+ Hypertension
+
+
+ Arthritis
+
+
+ Genitourinary
+
+
+
+ Diabetes
+
+
+ Other
+
+
+
+
+
+
+
+
+ I agree to the terms and conditions.
+
+
+
+
+
+
+
+ );
+};
diff --git a/packages/twenty-front/src/pages/campaigns/Lead.tsx b/packages/twenty-front/src/pages/campaigns/Lead.tsx
new file mode 100644
index 000000000000..c8256ff5cfbb
--- /dev/null
+++ b/packages/twenty-front/src/pages/campaigns/Lead.tsx
@@ -0,0 +1,490 @@
+/* eslint-disable @nx/workspace-styled-components-prefixed-with-styled */
+/* eslint-disable prefer-arrow/prefer-arrow-functions */
+/* eslint-disable no-restricted-imports */
+import { useState } from 'react';
+import { useLazyQuery } from '@apollo/client';
+import styled from '@emotion/styled';
+import { IconArrowRight, IconPlus } from '@tabler/icons-react';
+import {
+ IconArrowBadgeRight,
+ IconArrowLeft,
+ IconCalendar,
+ IconEqual,
+ IconSpeakerphone,
+ IconTrash,
+ IconUsersGroup,
+} from '@tabler/icons-react';
+import { MenuItemMultiSelectAvatar, TextInput } from 'tsup.ui.index';
+
+import { ModalWrapper } from '@/spreadsheet-import/components/ModalWrapper';
+import { H2Title } from '@/ui/display/typography/components/H2Title';
+import { Button } from '@/ui/input/button/components/Button';
+import DateTimePicker from '@/ui/input/components/internal/date/components/DateTimePicker';
+import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
+import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
+import { Section } from '@/ui/layout/section/components/Section';
+import { FILTER_LEADS } from '@/users/graphql/queries/filterLeads';
+import { useCampaign } from '~/pages/campaigns/CampaignUseContext';
+import { PreviewLeadsData } from '~/pages/campaigns/PreviewLeadsData';
+
+const StyledCard = styled.div`
+ border: 1px solid ${({ theme }) => theme.border.color.medium};
+ border-radius: ${({ theme }) => theme.border.radius.sm};
+ color: ${({ theme }) => theme.font.color.secondary};
+ box-shadow: ${({ theme }) => theme.boxShadow.strong};
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ background: ${({ theme }) => theme.background.primary};
+ height: 90%;
+ width: 70%;
+ margin: auto;
+ align-items: center;
+ overflow: scroll;
+`;
+
+const StyledInputCard = styled.div`
+ align-items: center;
+ color: ${({ theme }) => theme.font.color.secondary};
+ display: flex;
+ flex-direction: column;
+ height: 65%;
+ justify-content: space-between;
+ width: 70%;
+`;
+
+const StyledTitleCard = styled.div`
+ align-items: center;
+ color: ${({ theme }) => theme.font.color.secondary};
+ display: flex;
+ flex-direction: column;
+ height: 10%;
+ width: 70%;
+ justify-content: flex-start;
+`;
+
+const StyledButton = styled.span`
+ display: flex;
+ justify-content: space-between;
+ width: 100%;
+`;
+
+const StyledAreaLabel = styled.span`
+ align-content: center;
+ display: flex;
+ flex-direction: column;
+ background: ${({ theme }) => theme.background.noisy};
+ justify-content: center;
+ width: 100%;
+`;
+
+const StyledTitle = styled.h3`
+ color: ${({ theme }) => theme.font.color.secondary};
+ font-weight: ${({ theme }) => theme.font.weight.medium};
+ font-size: ${({ theme }) => theme.font.size.md};
+`;
+
+const TextContainer = styled.div`
+ align-items: center;
+ background: ${({ theme }) => theme.background.primary};
+ border: 1px solid ${({ theme }) => theme.border.color.medium};
+
+ border-radius: ${({ theme }) => theme.border.radius.md};
+ display: flex;
+ margin-bottom: ${({ theme }) => theme.spacing(4)};
+ margin-top: ${({ theme }) => theme.spacing(4)};
+ padding-bottom: ${({ theme }) => theme.spacing(2)};
+ padding-left: ${({ theme }) => theme.spacing(5)};
+ padding-right: ${({ theme }) => theme.spacing(5)};
+ padding-top: ${({ theme }) => theme.spacing(2)};
+`;
+const StyledFilter = styled(Section)`
+ margin-left: ${({ theme }) => theme.spacing(2)};
+`;
+const StyledComboInputContainer = styled.div`
+ display: flex;
+ flex-direction: row;
+ > * + * {
+ margin-left: ${({ theme }) => theme.spacing(4)};
+ }
+ align-items: center;
+ justify-content: space-around;
+`;
+
+const StyledComboInputContainer1 = styled.div`
+ display: flex;
+ flex-direction: row;
+ > * + * {
+ margin-left: ${({ theme }) => theme.spacing(4)};
+ }
+ align-items: center;
+`;
+const StyledFilterCard = styled.div`
+ display: flex;
+ flex-direction: row;
+ > * + * {
+ margin-left: ${({ theme }) => theme.spacing(4)};
+ }
+ width: 100%;
+ justify-content: space-between;
+`;
+const Section2 = styled.div`
+ align-items: center;
+ display: flex;
+ justify-content: space-between;
+`;
+
+export const Lead = () => {
+ const {
+ setCurrentStep,
+ currentStep,
+ setLeadData,
+ leadData,
+ campaignData,
+ setCampaignData,
+ } = useCampaign();
+ const [startDate, setStartDate] = useState(new Date());
+ const [endDate, setEndDate] = useState(new Date());
+ const [selectedFilterOptions, setSelectedFilterOptions] = useState<
+ Record
+ >({});
+ const [leadSourceValue, setLeadSourceValue] = useState('');
+ const [campaignNameValue, setCampaignNameValue] = useState('');
+ const [locationValue, setLocationValue] = useState('');
+ const [ageValue, setAgeValue] = useState('');
+ const [modalOpen, setModalOpen] = useState(false);
+
+ const handleLeadSourceChange = (event: any) => {
+ setLeadSourceValue(event.target.value);
+ };
+
+ const handleCampaignNameChange = (event: any) => {
+ setCampaignNameValue(event.target.value);
+ };
+
+ const handleLocationChange = (event: any) => {
+ setLocationValue(event.target.value);
+ };
+
+ const handleAgeChange = (event: any) => {
+ setAgeValue(event.target.value);
+ };
+
+ const [filterleads, { loading, error, data }] = useLazyQuery(FILTER_LEADS, {
+ fetchPolicy: 'network-only',
+ });
+
+ const filterOptions = [
+ { id: '1', name: 'Lead Source' },
+ { id: '2', name: 'Campaign Name' },
+ { id: '3', name: 'Select Date' },
+ { id: '4', name: 'Location' },
+ { id: '5', name: 'Age' },
+ ];
+
+ const handleSubmit = async () => {
+ const filter: Record = {};
+ if (selectedFilterOptions['1']) {
+ filter['advertisementSource'] = { ilike: `%${leadSourceValue}%` };
+ }
+ if (selectedFilterOptions['2']) {
+ filter['campaignName'] = { ilike: `%${campaignNameValue}%` };
+ }
+ if (selectedFilterOptions['4']) {
+ filter['location'] = { ilike: `%${locationValue}%` };
+ }
+ if (selectedFilterOptions['5']) {
+ filter['age'] = { ilike: `%${ageValue}%` };
+ }
+ try {
+ console.log(filter, '----------');
+ const data = await filterleads({ variables: { filter: filter } });
+ setModalOpen(true);
+ console.log('---------=====', data?.data?.leads?.totalCount);
+ setCampaignData({
+ ...campaignData,
+ leads: data?.data?.leads?.totalCount,
+ });
+
+ if (data) {
+ console.log(data);
+ setLeadData({ ...leadData, data: data });
+ }
+ } catch (error) {
+ console.error('Error sending data to API:', error);
+ }
+ };
+
+ const handleCloseModal = () => {
+ setModalOpen(false);
+ };
+
+ const removeFilterOption = (id: string) => {
+ setSelectedFilterOptions((previous) => ({
+ ...previous,
+ [id]: false,
+ }));
+ switch (id) {
+ case '1':
+ setLeadSourceValue('');
+ break;
+ case '2':
+ setCampaignNameValue('');
+ break;
+ case '4':
+ setLocationValue('');
+ break;
+ case '5':
+ setAgeValue('');
+ break;
+ default:
+ break;
+ }
+ };
+
+ const displayFilterSection = () => {
+ return filterOptions.map((item) => {
+ if (selectedFilterOptions[item.id]) {
+ switch (item.id) {
+ case '1':
+ return (
+
+
+
+
+ {' '}
+ Lead Source
+
+
+ is equal to
+
+ handleLeadSourceChange(event)}
+ />
+
+
+
+ removeFilterOption(item.id)}
+ />
+
+
+ );
+ case '2':
+ return (
+
+
+
+
+ {' '}
+ Campaign Name
+
+
+ is equal to
+
+ handleCampaignNameChange(event)}
+ />
+
+
+
+ removeFilterOption(item.id)}
+ />
+
+
+ );
+ case '3':
+ return (
+
+
+
+
+ Select Date
+
+ setStartDate(startDate)}
+ minDate={new Date()}
+ />
+ {/* */}
+
+ to
+
+
+ setEndDate(endDate)}
+ minDate={startDate}
+ />
+
+
+
+ removeFilterOption(item.id)}
+ />
+
+
+ );
+ case '4':
+ return (
+
+
+
+
+ Location
+
+
+ is equal to
+
+ handleLocationChange(event)}
+ />
+
+
+
+ removeFilterOption(item.id)}
+ />
+
+
+ );
+
+ case '5':
+ return (
+
+
+
+
+ Age
+
+
+ is equal to
+
+ handleAgeChange(event)}
+ />
+
+
+
+ removeFilterOption(item.id)}
+ />
+
+
+ );
+
+ default:
+ return null;
+ }
+ }
+ return null;
+ });
+ };
+
+ return (
+ <>
+
+
+
+
+
+
+
+
+
+
+
+ }
+ dropdownComponents={
+
+ {filterOptions.map((item) => (
+
+ setSelectedFilterOptions((previous) => ({
+ ...previous,
+ [item.id]: checked,
+ }))
+ }
+ avatar={undefined}
+ text={item.name}
+ />
+ ))}
+
+ }
+ dropdownHotkeyScope={{
+ scope: 'dropdownId',
+ }}
+ />
+
+
+
+
+ {displayFilterSection()}
+
+
+ setCurrentStep(currentStep - 1)}
+ />
+ setCurrentStep(currentStep + 1)}
+ />
+
+
+
+
+
+ {!loading && data && }
+
+ >
+ );
+};
diff --git a/packages/twenty-front/src/pages/campaigns/LeadsPreviewPage.tsx b/packages/twenty-front/src/pages/campaigns/LeadsPreviewPage.tsx
new file mode 100644
index 000000000000..39b53ed9b455
--- /dev/null
+++ b/packages/twenty-front/src/pages/campaigns/LeadsPreviewPage.tsx
@@ -0,0 +1,81 @@
+/* eslint-disable no-restricted-imports */
+import styled from '@emotion/styled';
+import { IconArrowLeft } from '@tabler/icons-react';
+import { IconArrowRight } from '@tabler/icons-react';
+import { Button } from 'tsup.ui.index';
+import { useCampaign } from '~/pages/campaigns/CampaignUseContext';
+import { PreviewLeadsData } from '~/pages/campaigns/PreviewLeadsData';
+
+const StyledCard = styled.div`
+ border: 1px solid ${({ theme }) => theme.border.color.medium};
+ border-radius: ${({ theme }) => theme.border.radius.sm};
+ color: ${({ theme }) => theme.font.color.secondary};
+ box-shadow: ${({ theme }) => theme.boxShadow.strong};
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ background: ${({ theme }) => theme.background.primary};
+ height: 90%;
+ width: 70%;
+ margin: auto;
+ align-items: center;
+ overflow: scroll;
+`;
+
+const StyledInputCard = styled.div`
+ color: ${({ theme }) => theme.font.color.secondary};
+ display: flex;
+ flex-direction: column;
+ height: 85%;
+ justify-content: space-between;
+ width: 100%;
+ align-items: center;
+`;
+
+const StyledTitleCard = styled.div`
+ /* align-items: center; */
+ color: ${({ theme }) => theme.font.color.secondary};
+ display: flex;
+ flex-direction: column;
+ height: 1%;
+ width: 100%;
+ justify-content: flex-start;
+`;
+
+const StyledButton = styled.span`
+ display: flex;
+ justify-content: space-between;
+ width: 100%;
+`;
+
+const StyledTitle = styled.h3`
+ color: ${({ theme }) => theme.font.color.secondary};
+ font-weight: ${({ theme }) => theme.font.weight.medium};
+ font-size: ${({ theme }) => theme.font.size.md};
+`;
+
+export const LeadsPreviewPage = () => {
+ const { setCurrentStep, currentStep, leadData } = useCampaign();
+ return (
+ <>
+
+
+
+ setCurrentStep(currentStep - 1)}
+ />
+ setCurrentStep(currentStep + 1)}
+ />
+
+
+ >
+ );
+};
diff --git a/packages/twenty-front/src/pages/campaigns/MessagingChannel.tsx b/packages/twenty-front/src/pages/campaigns/MessagingChannel.tsx
new file mode 100644
index 000000000000..834b4952ded1
--- /dev/null
+++ b/packages/twenty-front/src/pages/campaigns/MessagingChannel.tsx
@@ -0,0 +1,225 @@
+/* eslint-disable prefer-arrow/prefer-arrow-functions */
+/* eslint-disable no-restricted-imports */
+import { ChangeEvent } from 'react';
+import styled from '@emotion/styled';
+import { IconArrowLeft } from '@tabler/icons-react';
+import { IconArrowRight } from '@tabler/icons-react';
+import {
+ Checkbox,
+ CheckboxShape,
+ CheckboxSize,
+ CheckboxVariant,
+} from 'tsup.ui.index';
+
+import { H2Title } from '@/ui/display/typography/components/H2Title';
+import { Button } from '@/ui/input/button/components/Button';
+import { Section } from '@/ui/layout/section/components/Section';
+import { useCampaign } from '~/pages/campaigns/CampaignUseContext';
+const StyledCard = styled.div`
+ border: 1px solid ${({ theme }) => theme.border.color.medium};
+ border-radius: ${({ theme }) => theme.border.radius.sm};
+ color: ${({ theme }) => theme.font.color.secondary};
+ box-shadow: ${({ theme }) => theme.boxShadow.strong};
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ background: ${({ theme }) => theme.background.primary};
+ height: 90%;
+ width: 70%;
+ margin: auto;
+ align-items: center;
+`;
+
+const StyledInputCard = styled.div`
+ color: ${({ theme }) => theme.font.color.secondary};
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ height: 65%;
+ justify-content: space-between;
+ width: 70%;
+ align-items: center;
+`;
+
+const StyledTitleCard = styled.div`
+ /* align-items: center; */
+ color: ${({ theme }) => theme.font.color.secondary};
+ display: flex;
+ flex-direction: column;
+ height: 10%;
+ width: 100%;
+ justify-content: flex-start;
+`;
+
+const StyledButton = styled.span`
+ display: flex;
+ justify-content: space-between;
+ width: 100%;
+`;
+const StyledLabel = styled.span`
+ color: ${({ theme }) => theme.font.color.light};
+ font-size: ${({ theme }) => theme.font.size.xs};
+ font-weight: ${({ theme }) => theme.font.weight.semiBold};
+ margin-bottom: ${({ theme }) => theme.spacing(1)};
+ text-transform: uppercase;
+ display: flex;
+`;
+
+const StyledCheckboxLabel = styled.span`
+ margin-left: ${({ theme }) => theme.spacing(2)};
+`;
+
+const StyledTitle = styled.h3`
+ color: ${({ theme }) => theme.font.color.secondary};
+ font-weight: ${({ theme }) => theme.font.weight.medium};
+ font-size: ${({ theme }) => theme.font.size.md};
+ justify-content: flex-start;
+`;
+
+const StyledSection = styled(Section)`
+ align-items: flex-start;
+ display: flex;
+ justify-content: space-between;
+ margin-bottom: 16px;
+ margin-left: 0;
+`;
+export const MessagingChannel = () => {
+ const { setCurrentStep, currentStep, campaignData, setCampaignData } =
+ useCampaign();
+
+ const onSelectCheckBoxChange = (
+ event: ChangeEvent,
+ channel: string,
+ ): void => {
+ // throw new Error('Function not implemented.');
+ setCampaignData((prevData: any) => ({
+ ...prevData,
+ [channel]: event.target.checked,
+ }));
+ };
+
+ return (
+ <>
+
+
+
+
+
+
+
+ {
+ onSelectCheckBoxChange(event, 'SMS');
+ setCampaignData({
+ ...campaignData,
+ SMS: event.target.checked,
+ });
+ }}
+ variant={CheckboxVariant.Primary}
+ size={CheckboxSize.Small}
+ shape={CheckboxShape.Squared}
+ />{' '}
+ SMS
+
+
+
+ {
+ onSelectCheckBoxChange(event, 'Whatsapp');
+ setCampaignData({
+ ...campaignData,
+ Whatsapp: event.target.checked,
+ });
+ }}
+ variant={CheckboxVariant.Primary}
+ size={CheckboxSize.Small}
+ shape={CheckboxShape.Squared}
+ />
+ WhatsApp
+
+
+
+ {
+ onSelectCheckBoxChange(event, 'Email');
+ setCampaignData({
+ ...campaignData,
+ Email: event.target.checked,
+ });
+ }}
+ variant={CheckboxVariant.Primary}
+ size={CheckboxSize.Small}
+ shape={CheckboxShape.Squared}
+ />
+ Email
+
+
+
+ {
+ onSelectCheckBoxChange(event, 'GBM');
+ setCampaignData({
+ ...campaignData,
+ GBM: event.target.checked,
+ });
+ }}
+ variant={CheckboxVariant.Primary}
+ size={CheckboxSize.Small}
+ shape={CheckboxShape.Squared}
+ />
+ GBM
+
+
+
+ {
+ onSelectCheckBoxChange(event, 'CALL');
+ setCampaignData({
+ ...campaignData,
+ CALL: event.target.checked,
+ });
+ }}
+ variant={CheckboxVariant.Primary}
+ size={CheckboxSize.Small}
+ shape={CheckboxShape.Squared}
+ />
+ CALL
+
+
+
+ setCurrentStep(currentStep - 1)}
+ />
+ setCurrentStep(currentStep + 1)}
+ />
+
+
+
+ >
+ );
+};
diff --git a/packages/twenty-front/src/pages/campaigns/Preview.tsx b/packages/twenty-front/src/pages/campaigns/Preview.tsx
new file mode 100644
index 000000000000..366b0cd7e515
--- /dev/null
+++ b/packages/twenty-front/src/pages/campaigns/Preview.tsx
@@ -0,0 +1,394 @@
+/* eslint-disable no-restricted-globals */
+/* eslint-disable @nx/workspace-styled-components-prefixed-with-styled */
+import { useState } from 'react';
+import { useMutation, useQuery } from '@apollo/client';
+import styled from '@emotion/styled';
+import {
+ Checkbox,
+ CheckboxShape,
+ CheckboxSize,
+ CheckboxVariant,
+ Select,
+ TextInput,
+} from 'tsup.ui.index';
+import { v4 as uuidv4 } from 'uuid';
+
+import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer';
+import { IconMail } from '@/ui/display/icon';
+import { H1Title } from '@/ui/display/typography/components/H1Title';
+import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
+import { Button } from '@/ui/input/button/components/Button';
+import DateTimePicker from '@/ui/input/components/internal/date/components/DateTimePicker';
+import { SubMenuTopBarContainer } from '@/ui/layout/page/SubMenuTopBarContainer';
+import { Section } from '@/ui/layout/section/components/Section';
+import { ADD_CAMPAIGN } from '@/users/graphql/queries/addCampaign';
+import { GET_SPECIALTY } from '@/users/graphql/queries/getSpecialtyDetails';
+import { SAVE_SMS_RESPONSE } from '@/users/graphql/queries/saveSmsResponse';
+
+const StyledH1Title = styled(H1Title)`
+ margin-bottom: 0;
+`;
+
+const StyledSection = styled(Section)`
+ align-items: center;
+ display: flex;
+ justify-content: space-around;
+ margin-bottom: 16px;
+ margin-left: 0;
+`;
+
+const SaveButtonContainer = styled.div`
+ display: flex;
+ justify-content: flex-end;
+ width: auto;
+`;
+
+const StyledLabel = styled.span`
+ color: ${({ theme }) => theme.font.color.light};
+ font-size: ${({ theme }) => theme.font.size.xs};
+ font-weight: ${({ theme }) => theme.font.weight.semiBold};
+ margin-bottom: ${({ theme }) => theme.spacing(1)};
+ text-transform: uppercase;
+`;
+
+const StyledCheckboxLabel = styled.label`
+ align-items: center;
+ display: flex;
+`;
+
+export const Preview = () => {
+ let Specialty: any = [];
+
+ const SpecialtyTypes: any = {};
+
+ const [campaignName, setCampaignName] = useState('');
+ const [description, setDescription] = useState('');
+ const [specialty, setSpecialty] = useState('');
+ const [subSpecialty, setSubSpecialty] = useState('');
+ const [startDate, setStartDate] = useState(new Date());
+ const [endDate, setEndDate] = useState(new Date());
+ const [selectedMessaging, setSelectedMessaging] = useState(new Set());
+ const { loading: queryLoading, data: queryData } = useQuery(GET_SPECIALTY);
+
+ const [showSmsInput, setShowSmsInput] = useState(false);
+ const [smsMessage, setSmsMessage] = useState('');
+
+ if (!queryLoading) {
+ const specialtyTypes = queryData?.subspecialties.edges.map(
+ (edge: { node: { specialtyType: { name: any } } }) =>
+ edge?.node?.specialtyType?.name,
+ );
+ const uniqueSpecialtyTypes = Array.from(new Set(specialtyTypes));
+ Specialty = uniqueSpecialtyTypes.map((specialtyType) => ({
+ value: specialtyType,
+ label: specialtyType,
+ }));
+
+ queryData?.subspecialties.edges.forEach(
+ (edge: { node: { specialtyType: { name: any }; name: any } }) => {
+ const specialtyType = edge.node.specialtyType.name;
+ const subSpecialty = edge.node.name;
+
+ // If the specialty type is already a key in the dictionary, push the sub-specialty to its array
+ if (SpecialtyTypes[specialtyType]) {
+ SpecialtyTypes[specialtyType].push({
+ value: subSpecialty,
+ label: subSpecialty,
+ });
+ } else {
+ // If the specialty type is not yet a key, create a new array with the sub-specialty as its first element
+ SpecialtyTypes[specialtyType] = [];
+ SpecialtyTypes[specialtyType].push({
+ value: subSpecialty,
+ label: subSpecialty,
+ });
+ }
+ },
+ );
+ }
+
+ const [addCampaigns, { loading, error }] = useMutation(ADD_CAMPAIGN);
+
+ const [saveSmsResponse] = useMutation(SAVE_SMS_RESPONSE);
+
+ const { enqueueSnackBar } = useSnackBar();
+
+ const handleCampaignChange = (e: any) => {
+ setCampaignName(e.target.value);
+ };
+
+ const handleDescriptionChange = (e: any) => {
+ setDescription(e.target.value);
+ };
+
+ const handleSpecialtySelectChange = (selectedValue: any) => {
+ setSpecialty(selectedValue);
+ };
+
+ const handleSubSpecialtySelectChange = (selectedValue: any) => {
+ setSubSpecialty(selectedValue);
+ };
+
+ const onSelectCheckBoxChange = (event: any, checkedOption: string) => {
+ const { checked } = event.target;
+ if (checked) {
+ setSelectedMessaging(selectedMessaging.add(checkedOption));
+ if (checkedOption === 'SMS') {
+ setShowSmsInput(true);
+ }
+ } else {
+ selectedMessaging.delete(checkedOption);
+ setSelectedMessaging(selectedMessaging);
+ if (checkedOption === 'SMS') {
+ setShowSmsInput(false);
+ }
+ }
+ };
+ const resetCampaignData = () => {
+ setCampaignName('');
+ setDescription('');
+ setStartDate(new Date());
+ setSelectedMessaging(new Set());
+ setSpecialty('');
+ setSubSpecialty('');
+ };
+ const saveSMSResponse = async (response: any, campaignName: string) => {
+ const variables = {
+ input: {
+ id: uuidv4(),
+ campaignName: campaignName,
+ sid: response.sid,
+ status: response.status,
+ dateCreated: response.date_created,
+ to: response.to,
+ body: response.body,
+ },
+ };
+
+ const { data } = await saveSmsResponse({
+ variables: variables,
+ });
+
+ enqueueSnackBar('SMS response Saved Successfully', {
+ variant: 'success',
+ });
+
+ console.log('ashahsuahsh', data);
+ };
+ const handleSave = async () => {
+ try {
+ console.log('Start Date', startDate);
+
+ console.log('End Date', endDate);
+ const variables = {
+ input: {
+ id: uuidv4(),
+ campaignName: campaignName,
+ specialtyType: specialty,
+ description: description,
+ subSpecialtyType: subSpecialty,
+ startDate: startDate,
+ endDate: endDate,
+ messagingMedia: Array.from(selectedMessaging).join(' '),
+ },
+ };
+ console.log('Variables', variables);
+
+ const { data } = await addCampaigns({
+ variables: variables,
+ });
+ enqueueSnackBar('Campaign added successfully', {
+ variant: 'success',
+ });
+
+ const myHeaders = new Headers();
+ myHeaders.append('Content-Type', 'application/x-www-form-urlencoded');
+ myHeaders.append(
+ 'Authorization',
+ 'Basic QUM1ZGQxNjZiMDhjN2M3MGQ0YzZjNDM1N2I2OTFkODMwZjo0NDdmZmU0OWU1N2VhZmM4ZmIxNjAxZDNiOGEwMDVjYg==',
+ );
+
+ const urlencoded = new URLSearchParams();
+ enqueueSnackBar('SMS sent successfully', {
+ variant: 'success',
+ });
+ urlencoded.append('To', ' 919108223419');
+ urlencoded.append('From', ' 16506035403');
+ urlencoded.append('Body', smsMessage);
+
+ const requestOptions: Object = {
+ method: 'POST',
+ headers: myHeaders,
+ body: urlencoded,
+ redirect: 'follow',
+ };
+
+ const response: any = await fetch(
+ 'https://api.twilio.com/2010-04-01/Accounts/AC5dd166b08c7c70d4c6c4357b691d830f/Messages.json',
+ requestOptions,
+ ).catch((error) => console.error(error));
+ const respData = await response.json();
+
+ if (respData.body) {
+ enqueueSnackBar('SMS sent successfully', {
+ variant: 'success',
+ });
+
+ await saveSMSResponse(respData, campaignName);
+ }
+
+ resetCampaignData();
+ } catch (errors: any) {
+ console.error('Error updating user:', error);
+ enqueueSnackBar(errors.message + 'Error while Submitting Campaign', {
+ variant: 'error',
+ });
+ }
+ };
+ return (
+
+
+
+
+ handleCampaignChange(event)}
+ placeholder="Campaign Name"
+ name="campaignName"
+ required
+ fullWidth
+ />
+
+
+ handleDescriptionChange(event)}
+ placeholder="Description about campaign"
+ name="description"
+ required
+ fullWidth
+ />
+
+
+ {specialty && (
+
+ )}
+
+ Start Date
+ setStartDate(startDate)}
+ minDate={new Date()}
+ />
+
+
+ End Date
+ setEndDate(endDate)}
+ minDate={startDate}
+ />
+
+
+ Messaging
+
+
+ onSelectCheckBoxChange(event, 'SMS')}
+ variant={CheckboxVariant.Primary}
+ size={CheckboxSize.Small}
+ shape={CheckboxShape.Squared}
+ />
+ SMS
+
+
+
+ onSelectCheckBoxChange(event, 'Whatsapp')}
+ variant={CheckboxVariant.Primary}
+ size={CheckboxSize.Small}
+ shape={CheckboxShape.Squared}
+ />
+ WhastApp
+
+
+
+ onSelectCheckBoxChange(event, 'GBM')}
+ variant={CheckboxVariant.Primary}
+ size={CheckboxSize.Small}
+ shape={CheckboxShape.Squared}
+ />
+ GBM
+
+
+
+ onSelectCheckBoxChange(event, 'Call')}
+ variant={CheckboxVariant.Primary}
+ size={CheckboxSize.Small}
+ shape={CheckboxShape.Squared}
+ />
+ Call
+
+
+
+ {showSmsInput && (
+
+ SMS Message Body
+ setSmsMessage(value)}
+ placeholder="Enter SMS message body"
+ fullWidth
+ />
+
+ )}
+
+
+
+ handleSave()}
+ />
+
+
+
+ );
+};
diff --git a/packages/twenty-front/src/pages/campaigns/PreviewCampaignDate.tsx b/packages/twenty-front/src/pages/campaigns/PreviewCampaignDate.tsx
new file mode 100644
index 000000000000..63aa3fd7c795
--- /dev/null
+++ b/packages/twenty-front/src/pages/campaigns/PreviewCampaignDate.tsx
@@ -0,0 +1,38 @@
+import styled from '@emotion/styled';
+import { Section } from '@react-email/components';
+import { TextInput } from 'tsup.ui.index';
+
+import { H2Title } from '@/ui/display/typography/components/H2Title';
+const StyledComboInputContainer = styled.div`
+ display: flex;
+ flex-direction: row;
+ > * + * {
+ margin-left: ${({ theme }) => theme.spacing(4)};
+ }
+ width: 100%;
+ margin-top: ${({ theme }) => theme.spacing(4)};
+`;
+
+const StyledPreviewCampaignDate = styled.span`
+ margin-top: ${({ theme }) => theme.spacing(4)};
+ margin-bottom: ${({ theme }) => theme.spacing(4)};
+ width: 100%;
+`;
+export const PreviewCampaignDate = ({ startDate, endDate }) => {
+ return (
+ <>
+
+
+
+
+
+
+ >
+ );
+};
diff --git a/packages/twenty-front/src/pages/campaigns/PreviewCampaignDetailsTab.tsx b/packages/twenty-front/src/pages/campaigns/PreviewCampaignDetailsTab.tsx
new file mode 100644
index 000000000000..d26187e795fa
--- /dev/null
+++ b/packages/twenty-front/src/pages/campaigns/PreviewCampaignDetailsTab.tsx
@@ -0,0 +1,60 @@
+import styled from '@emotion/styled';
+import { Section } from '@react-email/components';
+import { TextArea, TextInput } from 'tsup.ui.index';
+
+import { H2Title } from '@/ui/display/typography/components/H2Title';
+
+const StyledAreaLabel = styled.span`
+ align-content: flex-start;
+ display: flex;
+ flex-direction: column;
+ margin-top: ${({ theme }) => theme.spacing(10)};
+ margin-bottom: ${({ theme }) => theme.spacing(4)};
+
+ width: 100%;
+`;
+const StyledPreviewCampaignDetails = styled.span`
+ margin-top: ${({ theme }) => theme.spacing(4)};
+ margin-bottom: ${({ theme }) => theme.spacing(4)};
+ width: 100%;
+`;
+
+export const PreviewCampaignDetailsTab = ({
+ campaignName,
+ campaignDescription,
+}) => {
+ return (
+ <>
+
+
+
+
+
+
+
+
+ >
+ );
+};
diff --git a/packages/twenty-front/src/pages/campaigns/PreviewLeadsData.tsx b/packages/twenty-front/src/pages/campaigns/PreviewLeadsData.tsx
new file mode 100644
index 000000000000..0b19ea70a0db
--- /dev/null
+++ b/packages/twenty-front/src/pages/campaigns/PreviewLeadsData.tsx
@@ -0,0 +1,111 @@
+import { EllipsisDisplay } from '@/ui/field/display/components/EllipsisDisplay';
+import styled from '@emotion/styled';
+import { capitalize } from '~/utils/string/capitalize';
+
+const StyledTable = styled.table<{ cursorPointer: boolean }>`
+ width: 100%;
+ border-collapse: collapse;
+ height: 10px;
+ margin-bottom: ${({ theme }) => theme.spacing(6)};
+ background-color: ${({ theme }) => theme.background.primary};
+ cursor: ${({ cursorPointer }) => (cursorPointer ? 'pointer' : 'inherit')};
+ font-family: inherit;
+ font-size: inherit;
+
+ font-weight: ${({ theme }) => theme.font.weight.regular};
+ max-width: 100%;
+ overflow: hidden;
+ text-decoration: inherit;
+
+ text-overflow: ellipsis;
+ white-space: nowrap;
+`;
+
+const StyledTableRow = styled.tr`
+ &:nth-of-type(odd) {
+ background-color: ${({ theme }) => theme.background.primary};
+ }
+`;
+
+const StyledTableCell = styled.td`
+ padding: 5px;
+ height: 25px;
+ border: 1px solid ${({ theme }) => theme.border.color.light};
+ font-weight: ${({ theme }) => theme.font.weight.regular};
+ &:hover {
+ background-color: ${({ theme }) => theme.background.tertiary};
+ }
+`;
+
+const StyledTableHeaderCell = styled.td`
+ padding: 5px;
+ border: 1px solid ${({ theme }) => theme.border.color.medium};
+ height: 25px;
+`;
+const StyledLabelContainer = styled.div`
+ color: ${({ theme }) => theme.font.color.tertiary};
+ width: auto;
+`;
+
+export const PreviewLeadsData = ({ data }) => {
+ return (
+
+
+
+
+ Name
+
+
+ Age
+
+
+ Location
+
+
+ Campaign Name
+
+
+ Advertisement Source
+
+
+ Phone Number
+
+
+ Comments
+
+
+ Advertisement Name
+
+
+ {data?.leads?.edges.map((leads: any) => (
+
+
+ {leads.node?.name}
+
+
+ {leads.node?.age}
+
+
+ {leads.node?.location}
+
+
+ {leads.node?.campaignName}
+
+
+ {leads.node?.advertisementSource}
+
+
+ {leads.node?.phoneNumber}
+
+
+ {leads.node?.comments}
+
+
+ {leads.node?.advertisementName}
+
+
+ ))}
+
+
+ );
+};
diff --git a/packages/twenty-front/src/pages/campaigns/PreviewMessagingChannel.tsx b/packages/twenty-front/src/pages/campaigns/PreviewMessagingChannel.tsx
new file mode 100644
index 000000000000..e358d2052fa8
--- /dev/null
+++ b/packages/twenty-front/src/pages/campaigns/PreviewMessagingChannel.tsx
@@ -0,0 +1,54 @@
+import styled from '@emotion/styled';
+import { Section } from '@react-email/components';
+import { TextInput } from 'tsup.ui.index';
+
+import { H2Title } from '@/ui/display/typography/components/H2Title';
+const StyledComboInputContainer = styled.div`
+ display: flex;
+ flex-direction: row;
+ > * + * {
+ margin-left: ${({ theme }) => theme.spacing(4)};
+ }
+ width: 100%;
+ margin-top: ${({ theme }) => theme.spacing(4)};
+`;
+
+const StyledPreviewMessagingChannel = styled.span`
+ margin-top: ${({ theme }) => theme.spacing(4)};
+ margin-bottom: ${({ theme }) => theme.spacing(8)};
+ width: 100%;
+`;
+
+export const PreviewMessagingChannel = ({ selectedChannels }) => {
+ return (
+ <>
+
+
+
+
+ {selectedChannels.length > 0 ? (
+
+ ) : (
+ No channels selected
+ )}
+
+ {/* */}
+
+
+ >
+ );
+};
diff --git a/packages/twenty-front/src/pages/campaigns/PreviewPage.tsx b/packages/twenty-front/src/pages/campaigns/PreviewPage.tsx
new file mode 100644
index 000000000000..ebedb56b1791
--- /dev/null
+++ b/packages/twenty-front/src/pages/campaigns/PreviewPage.tsx
@@ -0,0 +1,160 @@
+/* eslint-disable prefer-arrow/prefer-arrow-functions */
+/* eslint-disable no-restricted-imports */
+import { useMutation } from '@apollo/client';
+import styled from '@emotion/styled';
+import { IconArrowLeft } from '@tabler/icons-react';
+import { IconArrowRight } from '@tabler/icons-react';
+import { v4 as uuidv4 } from 'uuid';
+
+import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
+import { Button } from '@/ui/input/button/components/Button';
+import { ADD_CAMPAIGN } from '@/users/graphql/queries/addCampaign';
+import { useCampaign } from '~/pages/campaigns/CampaignUseContext';
+import { PreviewCampaignDate } from '~/pages/campaigns/PreviewCampaignDate';
+import { PreviewCampaignDetailsTab } from '~/pages/campaigns/PreviewCampaignDetailsTab';
+import { PreviewMessagingChannel } from '~/pages/campaigns/PreviewMessagingChannel';
+import { PreviewSpecialty } from '~/pages/campaigns/PreviewSpecialty';
+
+const StyledCard = styled.div`
+ border: 1px solid ${({ theme }) => theme.border.color.medium};
+ border-radius: ${({ theme }) => theme.border.radius.sm};
+ color: ${({ theme }) => theme.font.color.secondary};
+ box-shadow: ${({ theme }) => theme.boxShadow.strong};
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ background: ${({ theme }) => theme.background.primary};
+ height: 90%;
+ width: 70%;
+ margin: auto;
+ align-items: center;
+ overflow: scroll;
+`;
+
+const StyledInputCard = styled.div`
+ color: ${({ theme }) => theme.font.color.secondary};
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ height: 65%;
+ justify-content: space-between;
+ width: 70%;
+ align-items: center;
+`;
+
+const StyledTitleCard = styled.div`
+ /* align-items: center; */
+ color: ${({ theme }) => theme.font.color.secondary};
+ display: flex;
+ flex-direction: column;
+ height: 5%;
+ width: 100%;
+ justify-content: flex-start;
+`;
+
+const StyledButton = styled.span`
+ display: flex;
+ justify-content: space-between;
+ width: 100%;
+ margin-top: ${({ theme }) => theme.spacing(10)};
+ margin-bottom: ${({ theme }) => theme.spacing(10)};
+`;
+
+const StyledTitle = styled.h3`
+ color: ${({ theme }) => theme.font.color.secondary};
+ font-weight: ${({ theme }) => theme.font.weight.medium};
+ font-size: ${({ theme }) => theme.font.size.md};
+`;
+export const PreviewPage = () => {
+ const { setCurrentStep, currentStep, campaignData, setCampaignData } =
+ useCampaign();
+ const [addCampaigns, { error }] = useMutation(ADD_CAMPAIGN);
+ const { enqueueSnackBar } = useSnackBar();
+
+ const selectedChannels = ['SMS', 'Whatsapp', 'Email', 'GBM', 'CALL']
+ .filter((channel) => campaignData[channel])
+ .join(', ');
+
+ const resetFormData = () => {
+ setCampaignData({
+ ...campaignData,
+ campaignName: '',
+ campaignDescription: '',
+ specialtyType: '',
+ subSpecialtyType: '',
+ leads: '',
+ startDate: '',
+ endDate: '',
+ });
+ setCurrentStep(0);
+ };
+ const handleSave = async () => {
+ try {
+ const variables = {
+ input: {
+ id: uuidv4(),
+ campaignName: campaignData?.campaignName,
+ specialtyType: campaignData?.specialtyType,
+ description: campaignData?.campaignDescription,
+ subSpecialtyType: campaignData?.subSpecialtyType,
+ startDate: campaignData?.startDate,
+ endDate: campaignData?.endDate,
+ messagingMedia: selectedChannels,
+ leads: `${campaignData?.leads}`,
+ },
+ };
+ const { data } = await addCampaigns({
+ variables: variables,
+ });
+ enqueueSnackBar('Campaign Created successfully', {
+ variant: 'success',
+ });
+ resetFormData();
+ } catch (errors: any) {
+ console.error('Error while creating Campaign :', error);
+ enqueueSnackBar(errors.message + 'Error while creating Campaign', {
+ variant: 'error',
+ });
+ }
+ };
+ return (
+ <>
+
+
+
+
+
+
+
+
+
+
+ setCurrentStep(currentStep - 1)}
+ />
+
+
+
+
+ >
+ );
+};
diff --git a/packages/twenty-front/src/pages/campaigns/PreviewSpecialty.tsx b/packages/twenty-front/src/pages/campaigns/PreviewSpecialty.tsx
new file mode 100644
index 000000000000..8cfddcb20d8a
--- /dev/null
+++ b/packages/twenty-front/src/pages/campaigns/PreviewSpecialty.tsx
@@ -0,0 +1,56 @@
+import styled from '@emotion/styled';
+import { Section } from '@react-email/components';
+import { TextInput } from 'tsup.ui.index';
+
+import { H2Title } from '@/ui/display/typography/components/H2Title';
+
+const StyledComboInputContainer = styled.div`
+ display: flex;
+ flex-direction: row;
+ > * + * {
+ margin-left: ${({ theme }) => theme.spacing(4)};
+ }
+ width: 100%;
+ margin-top: ${({ theme }) => theme.spacing(4)};
+`;
+
+const StyledPreviewSpecialty = styled.span`
+ margin-top: ${({ theme }) => theme.spacing(2)};
+ margin-bottom: ${({ theme }) => theme.spacing(4)};
+ width: 100%;
+`;
+
+export const PreviewSpecialty = ({ specialtyType, subSpecialityType }) => {
+ return (
+ <>
+
+
+
+
+
+
+ >
+ );
+};
diff --git a/packages/twenty-front/src/pages/campaigns/Specialty.tsx b/packages/twenty-front/src/pages/campaigns/Specialty.tsx
new file mode 100644
index 000000000000..ba8f5ff71c35
--- /dev/null
+++ b/packages/twenty-front/src/pages/campaigns/Specialty.tsx
@@ -0,0 +1,178 @@
+/* eslint-disable no-restricted-imports */
+import { useQuery } from '@apollo/client';
+import styled from '@emotion/styled';
+import { IconArrowLeft } from '@tabler/icons-react';
+import { IconArrowRight } from '@tabler/icons-react';
+
+import { H2Title } from '@/ui/display/typography/components/H2Title';
+import { Button } from '@/ui/input/button/components/Button';
+import { Select } from '@/ui/input/components/Select';
+import { Section } from '@/ui/layout/section/components/Section';
+import { GET_SPECIALTY } from '@/users/graphql/queries/getSpecialtyDetails';
+import { useCampaign } from '~/pages/campaigns/CampaignUseContext';
+
+const StyledCard = styled.div`
+ border: 1px solid ${({ theme }) => theme.border.color.medium};
+ border-radius: ${({ theme }) => theme.border.radius.sm};
+ color: ${({ theme }) => theme.font.color.secondary};
+ box-shadow: ${({ theme }) => theme.boxShadow.strong};
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ background: ${({ theme }) => theme.background.primary};
+ height: 90%;
+ width: 70%;
+ margin: auto;
+ align-items: center;
+`;
+
+const StyledInputCard = styled.div`
+ color: ${({ theme }) => theme.font.color.secondary};
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ height: 65%;
+ justify-content: space-between;
+ width: 70%;
+
+ align-items: center;
+`;
+
+const StyledTitleCard = styled.div`
+ align-items: center;
+ color: ${({ theme }) => theme.font.color.secondary};
+ display: flex;
+ flex-direction: column;
+ height: 10%;
+ width: 70%;
+ justify-content: flex-start;
+`;
+
+const StyledButton = styled.span`
+ display: flex;
+ justify-content: space-between;
+ width: 100%;
+`;
+const StyledLabel = styled.span`
+ color: ${({ theme }) => theme.font.color.light};
+ font-size: ${({ theme }) => theme.font.size.xs};
+ font-weight: ${({ theme }) => theme.font.weight.semiBold};
+ margin-bottom: ${({ theme }) => theme.spacing(1)};
+ text-transform: uppercase;
+`;
+
+const StyledTitle = styled.h3`
+ color: ${({ theme }) => theme.font.color.secondary};
+ font-weight: ${({ theme }) => theme.font.weight.medium};
+ font-size: ${({ theme }) => theme.font.size.md};
+`;
+
+export const Specialty = () => {
+ const { setCurrentStep, campaignData, setCampaignData, currentStep } =
+ useCampaign();
+
+ let Specialty: any = [];
+ const SpecialtyTypes: any = {};
+ const { loading: queryLoading, data: queryData } = useQuery(GET_SPECIALTY);
+
+ if (!queryLoading) {
+ const specialtyTypes = queryData?.subspecialties.edges.map(
+ (edge: { node: { specialtyType: { name: any } } }) =>
+ edge?.node?.specialtyType?.name,
+ );
+ const uniqueSpecialtyTypes = Array.from(new Set(specialtyTypes));
+ Specialty = uniqueSpecialtyTypes.map((specialtyType) => ({
+ value: specialtyType,
+ label: specialtyType,
+ }));
+
+ queryData?.subspecialties.edges.forEach(
+ (edge: { node: { specialtyType: { name: any }; name: any } }) => {
+ const specialtyType = edge.node.specialtyType.name;
+ const subSpecialty = edge.node.name;
+
+ // If the specialty type is already a key in the dictionary, push the sub-specialty to its array
+ if (SpecialtyTypes[specialtyType]) {
+ SpecialtyTypes[specialtyType].push({
+ value: subSpecialty,
+ label: subSpecialty,
+ });
+ } else {
+ // If the specialty type is not yet a key, create a new array with the sub-specialty as its first element
+ SpecialtyTypes[specialtyType] = [];
+ SpecialtyTypes[specialtyType].push({
+ value: subSpecialty,
+ label: subSpecialty,
+ });
+ }
+ },
+ );
+ }
+
+ return (
+ <>
+
+
+
+
+
+
+
+
+ {campaignData?.specialtyType && (
+
+
+
+
+ )}
+
+ setCurrentStep(currentStep - 1)}
+ />
+ setCurrentStep(currentStep + 1)}
+ />
+
+
+
+ >
+ );
+};
diff --git a/packages/twenty-front/src/pages/object-record/RecordIndexPageHeader.tsx b/packages/twenty-front/src/pages/object-record/RecordIndexPageHeader.tsx
index 5039ec7a3447..3d2ff43a3815 100644
--- a/packages/twenty-front/src/pages/object-record/RecordIndexPageHeader.tsx
+++ b/packages/twenty-front/src/pages/object-record/RecordIndexPageHeader.tsx
@@ -1,4 +1,4 @@
-import { useParams } from 'react-router-dom';
+import { useNavigate, useParams } from 'react-router-dom';
import { useRecoilValue } from 'recoil';
import { useIcons } from 'twenty-ui';
@@ -9,6 +9,7 @@ import { PageHeader } from '@/ui/layout/page/PageHeader';
import { PageHotkeysEffect } from '@/ui/layout/page/PageHotkeysEffect';
import { ViewType } from '@/views/types/ViewType';
import { capitalize } from '~/utils/string/capitalize';
+import { useState, useEffect } from 'react';
type RecordIndexPageHeaderProps = {
createRecord: () => void;
@@ -31,7 +32,25 @@ export const RecordIndexPageHeader = ({
);
const recordIndexViewType = useRecoilValue(recordIndexViewTypeState);
+ const navigate = useNavigate();
+ const [page, setPage] = useState('');
+
+ useEffect(() => {
+ if (objectNamePlural === 'campaigns') {
+ setPage('/campaigns');
+ } else if (objectNamePlural === 'segments') {
+ setPage('/segment');
+ } else if (objectNamePlural === 'campaignTriggers') {
+ setPage('/campaignTriggers');
+ }
+ });
+
+ const handleClick = () => {
+ if (page) {
+ navigate(page);
+ }
+ };
const canAddRecord =
recordIndexViewType === ViewType.Table && !objectMetadataItem?.isRemote;
@@ -41,7 +60,9 @@ export const RecordIndexPageHeader = ({
return (
- {canAddRecord && }
+ {canAddRecord && (
+
+ )}
);
};
diff --git a/packages/twenty-front/src/pages/object-record/RecordShowPage.tsx b/packages/twenty-front/src/pages/object-record/RecordShowPage.tsx
index 336f70523458..e20b6aa1fab7 100644
--- a/packages/twenty-front/src/pages/object-record/RecordShowPage.tsx
+++ b/packages/twenty-front/src/pages/object-record/RecordShowPage.tsx
@@ -1,5 +1,5 @@
-import { useEffect } from 'react';
-import { useParams } from 'react-router-dom';
+import { useEffect, useState } from 'react';
+import { useNavigate, useParams } from 'react-router-dom';
import { useSetRecoilState } from 'recoil';
import { useIcons } from 'twenty-ui';
@@ -20,6 +20,13 @@ import { PageTitle } from '@/ui/utilities/page-title/PageTitle';
import { FieldMetadataType } from '~/generated-metadata/graphql';
import { isDefined } from '~/utils/isDefined';
import { capitalize } from '~/utils/string/capitalize';
+import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
+import { ADD_TRIGGER_CAMPAIGN_RECORD } from '@/users/graphql/queries/addTriggerCampaignRecord';
+import { GET_CAMPAIGN_LISTS } from '@/users/graphql/queries/getCampaignList';
+import { useLazyQuery, useMutation } from '@apollo/client';
+import { useCampaign } from '~/pages/campaigns/CampaignUseContext';
+import { ConfirmationModal } from '@/ui/layout/modal/components/ConfirmationModal';
+import { RunCampaignButton } from '@/ui/layout/page/RunCampaignButton';
export const RecordShowPage = () => {
const { objectNameSingular, objectRecordId } = useParams<{
@@ -84,6 +91,106 @@ export const RecordShowPage = () => {
}
};
+ let [selectedCampaign, { data: selectedCampaignData }] =
+ useLazyQuery(GET_CAMPAIGN_LISTS);
+
+useEffect(() => {
+ const fetchData = async () => {
+ try {
+ const data = await selectedCampaign({
+ variables: {
+ filter: {
+ id: { eq: objectRecordId },
+ },
+ },
+ });
+ const fetchedCampaigns = data?.data?.campaigns?.edges ?? [];
+ setCampaigns(fetchedCampaigns);
+ } catch (error) {
+ console.error('Error fetching campaign:', error);
+ }
+ };
+
+ fetchData();
+}, [objectRecordId, selectedCampaign]);
+
+const { campaignData, setCampaignData } = useCampaign();
+const [campaigns, setCampaigns] = useState([]);
+const [addTriggerCampaignRecord] = useMutation(ADD_TRIGGER_CAMPAIGN_RECORD);
+const { enqueueSnackBar } = useSnackBar();
+const navigate = useNavigate();
+const [isConfirmModalOpen, setIsConfirmModalOpen] = useState(false);
+
+const handleConfirmRun = async () => {
+ try {
+ const { data: addTriggerData } = await addTriggerCampaignRecord({
+ variables: {
+ input: {
+ name: campaigns[0]?.node?.name,
+ startDate: campaignData.startDate.toISOString(),
+ stopDate: campaignData.endDate.toISOString(),
+ status: 'ACTIVE',
+ campaignId: campaigns[0]?.node?.id,
+ },
+ },
+ });
+
+ console.log(
+ 'Response from ADD_TRIGGER_CAMPAIGN_RECORD:',
+ addTriggerData.createCampaignTrigger.id,
+ );
+
+ let requestBody: {
+ campaignId: string;
+ queryTimestamp: any;
+ campaignTriggerId: any;
+ startDate: any;
+ stopDate: any;
+ id: { selectedID: any } | { unselectedID: any };
+ } = {
+ campaignId: objectRecordId,
+ queryTimestamp: campaignData.querystamp,
+ campaignTriggerId: addTriggerData?.createCampaignTrigger?.id,
+ startDate: campaignData.startDate,
+ stopDate: campaignData.endDate,
+ id: { selectedID: campaignData.selectedId },
+ };
+
+ if (campaignData.selectedId.length > campaignData.unSelectedId.length) {
+ requestBody.id = { unselectedID: campaignData.unSelectedId };
+ }
+
+ console.log(requestBody, 'request body');
+
+ const response = await fetch('http://localhost:3000/campaign/execute', {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json',
+ },
+ body: JSON.stringify(requestBody),
+ });
+ const data = await response.json();
+
+ console.log('Response from the API:', data);
+ enqueueSnackBar('Campaign added successfully', {
+ variant: 'success',
+ });
+ navigate('/objects/campaignTriggers');
+ window.location.reload();
+ } catch (error) {
+ console.error('Error in running campaign:', error);
+ enqueueSnackBar('Campaign added successfully', {
+ variant: 'error',
+ });
+ }
+};
+
+const handleRuncampaign = async () => {
+ setIsConfirmModalOpen(true);
+};
+
+
+
const labelIdentifierFieldValue =
record?.[labelIdentifierFieldMetadataItem?.name ?? ''];
@@ -129,8 +236,27 @@ export const RecordShowPage = () => {
objectNameSingular={objectNameSingular}
/>
>
+ )}
+ {record && objectNameSingular === 'campaign' && (
+ <>
+
+ >
)}
+
+ Are you sure you want to trigger this campaign?
Triggering
+ this campaign will send notifications to all subscribed users.
+ >
+ }
+ onConfirmClick={handleConfirmRun}
+ deleteButtonText="Run Campaign"
+ />
Date: Fri, 3 May 2024 14:23:16 +0530
Subject: [PATCH 022/122] Updated Queries
---
packages/twenty-front/src/App.tsx | 7 +-
.../effect-components/PageChangeEffect.tsx | 40 +-
.../modules/apollo/hooks/useApolloFactory.ts | 6 +-
.../src/modules/auth/components/Modal.tsx | 6 +-
.../src/modules/types/AppBasePath.ts | 2 +-
.../twenty-front/src/modules/types/AppPath.ts | 12 +-
.../src/modules/types/PageHotkeyScope.ts | 1 +
.../modules/ui/input/components/TextArea.tsx | 2 +-
.../layout/modal/components/ModalLayout.tsx | 7 +-
.../users/graphql/queries/filterLeads.ts | 2 +-
.../users/graphql/queries/getCampaignList.ts | 2 +-
.../users/graphql/queries/getFormTemplates.ts | 2 +-
.../graphql/queries/getMessageTemplates.ts | 2 +-
.../graphql/queries/getOneCampaignTrigger.ts | 354 +-----------------
.../users/graphql/queries/getSegments.ts | 2 +-
.../graphql/queries/getSpecialtyDetails.ts | 2 +-
.../users/graphql/queries/saveSmsResponse.ts | 151 --------
.../queries/updateCampaignlistStatus.ts | 9 -
.../graphql/queries/updateLastExecutionId.ts | 9 -
.../src/pages/campaigns/CampaignForm.tsx | 26 +-
.../object-record/RecordIndexPageHeader.tsx | 4 +-
.../twenty-ui/src/theme/constants/Modal.ts | 1 +
22 files changed, 88 insertions(+), 561 deletions(-)
delete mode 100644 packages/twenty-front/src/modules/users/graphql/queries/saveSmsResponse.ts
delete mode 100644 packages/twenty-front/src/modules/users/graphql/queries/updateCampaignlistStatus.ts
delete mode 100644 packages/twenty-front/src/modules/users/graphql/queries/updateLastExecutionId.ts
diff --git a/packages/twenty-front/src/App.tsx b/packages/twenty-front/src/App.tsx
index 8a99fa82757a..d6a60f814cf9 100644
--- a/packages/twenty-front/src/App.tsx
+++ b/packages/twenty-front/src/App.tsx
@@ -72,7 +72,8 @@ export const App = () => {
}>
} />
- } />
+ } />
+ } />
} />
} />
} />
@@ -221,7 +222,7 @@ export const App = () => {
}>
} />
-
+ }>
} />
} />
@@ -230,8 +231,10 @@ export const App = () => {
} />
+
+
>
);
};
\ No newline at end of file
diff --git a/packages/twenty-front/src/effect-components/PageChangeEffect.tsx b/packages/twenty-front/src/effect-components/PageChangeEffect.tsx
index dba2d07ab9d0..30b6cc4fd91a 100644
--- a/packages/twenty-front/src/effect-components/PageChangeEffect.tsx
+++ b/packages/twenty-front/src/effect-components/PageChangeEffect.tsx
@@ -24,6 +24,7 @@ import { isDefined } from '~/utils/isDefined';
import { isUndefinedOrNull } from '~/utils/isUndefinedOrNull';
import { useIsMatchingLocation } from '../hooks/useIsMatchingLocation';
+import { CustomPath } from '@/types/CustomPath';
// TODO: break down into smaller functions and / or hooks
export const PageChangeEffect = () => {
@@ -59,7 +60,7 @@ export const PageChangeEffect = () => {
useEffect(() => {
const isMatchingOngoingUserCreationRoute =
- isMatchingLocation(AppPath.SignInUp) ||
+ isMatchingLocation(AppPath.SignIn) ||
isMatchingLocation(AppPath.Invite) ||
isMatchingLocation(AppPath.Verify);
@@ -74,16 +75,25 @@ export const PageChangeEffect = () => {
enqueueSnackBar('workspace does not exist', {
variant: 'error',
});
- navigate(AppPath.SignInUp);
+ navigate(AppPath.SignUp);
};
-
if (
+ isMatchingLocation(CustomPath.CampaignForm) ||
+ isMatchingLocation(CustomPath.CampaignForm2) ||
+ isMatchingLocation(CustomPath.CampaignForm3)
+ ) {
+ console.log('Path Location:', location.pathname);
+ navigate(location.pathname);
+ return;
+ }
+ else if (
onboardingStatus === OnboardingStatus.OngoingUserCreation &&
!isMatchingOngoingUserCreationRoute &&
!isMatchingLocation(AppPath.ResetPassword)
) {
navigate(AppPath.SignInUp);
- } else if (
+ }
+ else if (
isDefined(onboardingStatus) &&
onboardingStatus === OnboardingStatus.Incomplete &&
!isMatchingLocation(AppPath.PlanRequired)
@@ -169,6 +179,28 @@ export const PageChangeEffect = () => {
});
break;
}
+ case isMatchingLocation(CustomPath.CampaignForm): {
+ setHotkeyScope(PageHotkeyScope.CampaignForm, {
+ goto: true,
+ keyboardShortcutMenu: true,
+ });
+ break;
+ }
+ case isMatchingLocation(CustomPath.CampaignForm2): {
+ setHotkeyScope(PageHotkeyScope.CampaignForm, {
+ goto: true,
+ keyboardShortcutMenu: true,
+ });
+ break;
+ }
+ case isMatchingLocation(CustomPath.CampaignForm3): {
+ setHotkeyScope(PageHotkeyScope.CampaignForm, {
+ goto: true,
+ keyboardShortcutMenu: true,
+ });
+ break;
+ }
+
case isMatchingLocation(AppPath.OpportunitiesPage): {
setHotkeyScope(PageHotkeyScope.OpportunitiesPage, {
goto: true,
diff --git a/packages/twenty-front/src/modules/apollo/hooks/useApolloFactory.ts b/packages/twenty-front/src/modules/apollo/hooks/useApolloFactory.ts
index 768142302afb..2b9748985aa7 100644
--- a/packages/twenty-front/src/modules/apollo/hooks/useApolloFactory.ts
+++ b/packages/twenty-front/src/modules/apollo/hooks/useApolloFactory.ts
@@ -14,6 +14,7 @@ import { useUpdateEffect } from '~/hooks/useUpdateEffect';
import { isDefined } from '~/utils/isDefined';
import { ApolloFactory, Options } from '../services/apollo.factory';
+import { CustomPath } from '@/types/CustomPath';
export const useApolloFactory = (options: Partial> = {}) => {
// eslint-disable-next-line @nx/workspace-no-state-useref
@@ -49,7 +50,10 @@ export const useApolloFactory = (options: Partial> = {}) => {
},
onUnauthenticatedError: () => {
setTokenPair(null);
- if (
+ if (isMatchingLocation(CustomPath.CampaignForm) || isMatchingLocation(CustomPath.CampaignForm2) || isMatchingLocation(CustomPath.CampaignForm3)) {
+ navigate(location.pathname);
+ }
+ else if (
!isMatchingLocation(AppPath.Verify) &&
!isMatchingLocation(AppPath.SignInUp) &&
!isMatchingLocation(AppPath.Invite) &&
diff --git a/packages/twenty-front/src/modules/auth/components/Modal.tsx b/packages/twenty-front/src/modules/auth/components/Modal.tsx
index f40de47cf5d9..011f74b3974d 100644
--- a/packages/twenty-front/src/modules/auth/components/Modal.tsx
+++ b/packages/twenty-front/src/modules/auth/components/Modal.tsx
@@ -5,13 +5,15 @@ import { ModalLayout } from '@/ui/layout/modal/components/ModalLayout';
const StyledContent = styled(ModalLayout.Content)`
align-items: center;
- width: calc(400px - ${({ theme }) => theme.spacing(10 * 2)});
+ width: 100%;
+ height: 100%;
+ justify-content: center;
`;
type AuthModalProps = { children: React.ReactNode };
export const AuthModal = ({ children }: AuthModalProps) => (
-
+
{children}
);
diff --git a/packages/twenty-front/src/modules/types/AppBasePath.ts b/packages/twenty-front/src/modules/types/AppBasePath.ts
index a9ae5f757914..0a5f8330a942 100644
--- a/packages/twenty-front/src/modules/types/AppBasePath.ts
+++ b/packages/twenty-front/src/modules/types/AppBasePath.ts
@@ -1,5 +1,5 @@
export enum AppBasePath {
Auth = '/auth',
Settings = '/settings',
- Root = '/',
+ Root = '/root',
}
diff --git a/packages/twenty-front/src/modules/types/AppPath.ts b/packages/twenty-front/src/modules/types/AppPath.ts
index fe66bd4d68c6..cbd685769841 100644
--- a/packages/twenty-front/src/modules/types/AppPath.ts
+++ b/packages/twenty-front/src/modules/types/AppPath.ts
@@ -1,9 +1,13 @@
+import { AppBasePath } from "@/types/AppBasePath";
+
export enum AppPath {
// Not logged-in
- Verify = '/verify',
- SignInUp = '/welcome',
- Invite = '/invite/:workspaceInviteHash',
- ResetPassword = '/reset-password/:passwordResetToken',
+ SignInUp = `${AppBasePath.Auth}/sign-in`,
+ Verify = `${AppBasePath.Auth}/verify`,
+ SignIn = `${AppBasePath.Auth}/sign-in`,
+ SignUp = `${AppBasePath.Auth}/sign-up`,
+ Invite = `${AppBasePath.Auth}/invite/:workspaceInviteHash`,
+ ResetPassword = `${AppBasePath.Auth}/reset-password/:passwordResetToken`,
// Onboarding
CreateWorkspace = '/create/workspace',
diff --git a/packages/twenty-front/src/modules/types/PageHotkeyScope.ts b/packages/twenty-front/src/modules/types/PageHotkeyScope.ts
index db175a7925b6..bd0cd7331cb9 100644
--- a/packages/twenty-front/src/modules/types/PageHotkeyScope.ts
+++ b/packages/twenty-front/src/modules/types/PageHotkeyScope.ts
@@ -13,4 +13,5 @@ export enum PageHotkeyScope {
ProfilePage = 'profile-page',
WorkspaceMemberPage = 'workspace-member-page',
TaskPage = 'task-page',
+ CampaignForm='campaignform'
}
diff --git a/packages/twenty-front/src/modules/ui/input/components/TextArea.tsx b/packages/twenty-front/src/modules/ui/input/components/TextArea.tsx
index 4d116a173489..9f533396fda7 100644
--- a/packages/twenty-front/src/modules/ui/input/components/TextArea.tsx
+++ b/packages/twenty-front/src/modules/ui/input/components/TextArea.tsx
@@ -6,7 +6,7 @@ import { usePreviousHotkeyScope } from '@/ui/utilities/hotkey/hooks/usePreviousH
import { InputHotkeyScope } from '../types/InputHotkeyScope';
-const MAX_ROWS = 5;
+const MAX_ROWS = 100;
export type TextAreaProps = {
disabled?: boolean;
diff --git a/packages/twenty-front/src/modules/ui/layout/modal/components/ModalLayout.tsx b/packages/twenty-front/src/modules/ui/layout/modal/components/ModalLayout.tsx
index c6437c247096..c8d91482d670 100644
--- a/packages/twenty-front/src/modules/ui/layout/modal/components/ModalLayout.tsx
+++ b/packages/twenty-front/src/modules/ui/layout/modal/components/ModalLayout.tsx
@@ -12,7 +12,8 @@ const StyledModalDiv = styled(motion.div)<{
color: ${({ theme }) => theme.font.color.primary};
border-radius: ${({ theme }) => theme.border.radius.md};
overflow: hidden;
- max-height: 90vh;
+ height: 100%;
+ justify-content: center;
z-index: 10000; // should be higher than Backdrop's z-index
width: ${({ size, theme }) => {
@@ -23,6 +24,8 @@ const StyledModalDiv = styled(motion.div)<{
return theme.modal.size.md;
case 'large':
return theme.modal.size.lg;
+ case 'extralarge':
+ return theme.modal.size.xl;
default:
return 'auto';
}
@@ -117,7 +120,7 @@ const ModalLayoutFooter = ({ children, className }: ModalLayoutFooterProps) => (
/**
* Modal
*/
-export type ModalSize = 'small' | 'medium' | 'large';
+export type ModalSize = 'small' | 'medium' | 'large' | 'extralarge';
export type ModalPadding = 'none' | 'small' | 'medium' | 'large';
export type ModalLayoutProps = React.PropsWithChildren & {
diff --git a/packages/twenty-front/src/modules/users/graphql/queries/filterLeads.ts b/packages/twenty-front/src/modules/users/graphql/queries/filterLeads.ts
index 22c56a0ee184..ce3480ca2eeb 100644
--- a/packages/twenty-front/src/modules/users/graphql/queries/filterLeads.ts
+++ b/packages/twenty-front/src/modules/users/graphql/queries/filterLeads.ts
@@ -1,7 +1,7 @@
import { gql } from '@apollo/client';
export const FILTER_LEADS = gql`
-query FindManyLeads($filter: LeadFilterInput, $orderBy: LeadOrderByInput, $lastCursor: String, $limit: Float) {
+query FindManyLeads($filter: LeadFilterInput, $orderBy: LeadOrderByInput, $lastCursor: String, $limit: Int) {
leads(filter: $filter, orderBy: $orderBy, first: $limit, after: $lastCursor) {
edges {
node {
diff --git a/packages/twenty-front/src/modules/users/graphql/queries/getCampaignList.ts b/packages/twenty-front/src/modules/users/graphql/queries/getCampaignList.ts
index 9b9d7614c47b..57d1fdb96df8 100644
--- a/packages/twenty-front/src/modules/users/graphql/queries/getCampaignList.ts
+++ b/packages/twenty-front/src/modules/users/graphql/queries/getCampaignList.ts
@@ -1,7 +1,7 @@
import { gql } from '@apollo/client';
export const GET_CAMPAIGN_LISTS = gql`
-query FindManyCampaigns($filter: CampaignFilterInput, $orderBy: CampaignOrderByInput, $lastCursor: String, $limit: Float) {
+query FindManyCampaigns($filter: CampaignFilterInput, $orderBy: CampaignOrderByInput, $lastCursor: String, $limit: Int) {
campaigns(filter: $filter, orderBy: $orderBy, first: $limit, after: $lastCursor) {
edges {
node {
diff --git a/packages/twenty-front/src/modules/users/graphql/queries/getFormTemplates.ts b/packages/twenty-front/src/modules/users/graphql/queries/getFormTemplates.ts
index c6d2c48ff127..8a5b05935a94 100644
--- a/packages/twenty-front/src/modules/users/graphql/queries/getFormTemplates.ts
+++ b/packages/twenty-front/src/modules/users/graphql/queries/getFormTemplates.ts
@@ -1,7 +1,7 @@
import { gql } from '@apollo/client';
export const GET_FORM_TEMPLATES = gql`
-query FindManyFormTemplates($filter: FormTemplateFilterInput, $orderBy: FormTemplateOrderByInput, $lastCursor: String, $limit: Float) {
+query FindManyFormTemplates($filter: FormTemplateFilterInput, $orderBy: FormTemplateOrderByInput, $lastCursor: String, $limit: Int) {
formTemplates(
filter: $filter
orderBy: $orderBy
diff --git a/packages/twenty-front/src/modules/users/graphql/queries/getMessageTemplates.ts b/packages/twenty-front/src/modules/users/graphql/queries/getMessageTemplates.ts
index 5b9dcf99c2d2..cc9ae36d23c1 100644
--- a/packages/twenty-front/src/modules/users/graphql/queries/getMessageTemplates.ts
+++ b/packages/twenty-front/src/modules/users/graphql/queries/getMessageTemplates.ts
@@ -1,7 +1,7 @@
import { gql } from '@apollo/client';
export const GET_MESSAGE_TEMPLATES = gql`
-query FindManyMessageTemplates($filter: MessageTemplateFilterInput, $orderBy: MessageTemplateOrderByInput, $lastCursor: String, $limit: Float) {
+query FindManyMessageTemplates($filter: MessageTemplateFilterInput, $orderBy: MessageTemplateOrderByInput, $lastCursor: String, $limit: Int) {
messageTemplates(
filter: $filter
orderBy: $orderBy
diff --git a/packages/twenty-front/src/modules/users/graphql/queries/getOneCampaignTrigger.ts b/packages/twenty-front/src/modules/users/graphql/queries/getOneCampaignTrigger.ts
index 33647d131171..68398c7ecbab 100644
--- a/packages/twenty-front/src/modules/users/graphql/queries/getOneCampaignTrigger.ts
+++ b/packages/twenty-front/src/modules/users/graphql/queries/getOneCampaignTrigger.ts
@@ -1,360 +1,8 @@
import { gql } from '@apollo/client';
-export const GET_CAMPAIGN_TRIGGER = gql`query FindOnecampaignTrigger($objectRecordId: UUID!) {
+export const GET_CAMPAIGN_TRIGGER = gql`query FindOnecampaignTrigger($objectRecordId: ID!) {
campaignTrigger(filter: {id: {eq: $objectRecordId}}) {
id
- attachments {
- edges {
- node {
- __typename
- id
- specialty {
- __typename
- id
- }
- fullPath
- activity {
- __typename
- id
- }
- updatedAt
- formResponseId
- companyId
- campaign {
- __typename
- id
- }
- communicationLog {
- __typename
- id
- }
- type
- segment {
- __typename
- id
- }
- formResponse {
- __typename
- id
- }
- subspecialty {
- __typename
- id
- }
- communicationLogId
- specialtyId
- createdAt
- messageTemplate {
- __typename
- id
- }
- person {
- __typename
- id
- }
- formTemplateId
- subspecialtyId
- id
- leadId
- company {
- __typename
- id
- }
- messageTemplateId
- opportunity {
- __typename
- id
- }
- formTemplate {
- __typename
- id
- }
- segmentId
- lead {
- __typename
- id
- }
- campaignId
- name
- authorId
- campaignTriggerId
- campaignTrigger {
- __typename
- id
- }
- author {
- __typename
- id
- }
- opportunityId
- activityId
- personId
- }
- __typename
- }
- __typename
- }
- executionId
- startDate
- opportunites {
- edges {
- node {
- __typename
- id
- campaign {
- __typename
- id
- }
- lead {
- __typename
- id
- }
- probability
- messageStatus
- activityTargets {
- edges {
- node {
- __typename
- id
- }
- __typename
- }
- __typename
- }
- favorites {
- edges {
- node {
- __typename
- id
- }
- __typename
- }
- __typename
- }
- companyId
- campaignTrigger {
- __typename
- id
- }
- stage
- attachments {
- edges {
- node {
- __typename
- id
- }
- __typename
- }
- __typename
- }
- informedPhoneNumberId
- informedPhoneNumber {
- __typename
- id
- }
- createdAt
- updatedAt
- id
- pointOfContact {
- __typename
- id
- }
- pipelineStepId
- campaignId
- amount {
- amountMicros
- currencyCode
- __typename
- }
- campaignTriggerId
- company {
- __typename
- id
- }
- comments
- closeDate
- pipelineStep {
- __typename
- id
- }
- pointOfContactId
- leadId
- name
- position
- }
- __typename
- }
- __typename
- }
- id
- createdAt
- position
- stopDate
- activityTargets {
- edges {
- node {
- __typename
- id
- subspecialtyId
- company {
- __typename
- id
- }
- specialtyId
- opportunity {
- __typename
- id
- }
- campaignTrigger {
- __typename
- id
- }
- campaignTriggerId
- activityId
- id
- person {
- __typename
- id
- }
- messageTemplate {
- __typename
- id
- }
- formResponseId
- createdAt
- opportunityId
- segmentId
- campaignId
- activity {
- __typename
- id
- }
- lead {
- __typename
- id
- }
- formResponse {
- __typename
- id
- }
- updatedAt
- subspecialty {
- __typename
- id
- }
- communicationLogId
- companyId
- leadId
- formTemplate {
- __typename
- id
- }
- specialty {
- __typename
- id
- }
- communicationLog {
- __typename
- id
- }
- segment {
- __typename
- id
- }
- campaign {
- __typename
- id
- }
- personId
- formTemplateId
- messageTemplateId
- }
- __typename
- }
- __typename
- }
- campaign {
- __typename
- id
- description
- segment {
- __typename
- id
- }
- position
- activityTargets {
- edges {
- node {
- __typename
- id
- }
- __typename
- }
- __typename
- }
- id
- segmentId
- messageTemplateId
- subspecialty
- updatedAt
- formTemplate {
- __typename
- id
- }
- status
- favorites {
- edges {
- node {
- __typename
- id
- }
- __typename
- }
- __typename
- }
- campaignExecution {
- edges {
- node {
- __typename
- id
- }
- __typename
- }
- __typename
- }
- specialty
- formTemplateId
- createdAt
- opportunities {
- edges {
- node {
- __typename
- id
- }
- __typename
- }
- __typename
- }
- messageTemplate {
- __typename
- id
- }
- name
- attachments {
- edges {
- node {
- __typename
- id
- }
- __typename
- }
- __typename
- }
- }
campaignId
- status
- name
- updatedAt
- __typename
}
}`
\ No newline at end of file
diff --git a/packages/twenty-front/src/modules/users/graphql/queries/getSegments.ts b/packages/twenty-front/src/modules/users/graphql/queries/getSegments.ts
index 9f85bad846dc..749ed030c394 100644
--- a/packages/twenty-front/src/modules/users/graphql/queries/getSegments.ts
+++ b/packages/twenty-front/src/modules/users/graphql/queries/getSegments.ts
@@ -1,7 +1,7 @@
import { gql } from '@apollo/client';
export const GET_SEGMENT_LISTS = gql`
-query FindManySegments($filter: SegmentFilterInput, $orderBy: SegmentOrderByInput, $lastCursor: String, $limit: Float) {
+query FindManySegments($filter: SegmentFilterInput, $orderBy: SegmentOrderByInput, $lastCursor: String, $limit: Int) {
segments(
filter: $filter
orderBy: $orderBy
diff --git a/packages/twenty-front/src/modules/users/graphql/queries/getSpecialtyDetails.ts b/packages/twenty-front/src/modules/users/graphql/queries/getSpecialtyDetails.ts
index 15474068d256..2292d9188a65 100644
--- a/packages/twenty-front/src/modules/users/graphql/queries/getSpecialtyDetails.ts
+++ b/packages/twenty-front/src/modules/users/graphql/queries/getSpecialtyDetails.ts
@@ -1,7 +1,7 @@
import { gql } from '@apollo/client';
export const GET_SPECIALTY = gql`
-query FindManySubspecialties($filter: SubspecialtyFilterInput, $orderBy: SubspecialtyOrderByInput, $lastCursor: String, $limit: Float) {
+query FindManySubspecialties($filter: SubspecialtyFilterInput, $orderBy: SubspecialtyOrderByInput, $lastCursor: String, $limit: Int) {
subspecialties(
filter: $filter
orderBy: $orderBy
diff --git a/packages/twenty-front/src/modules/users/graphql/queries/saveSmsResponse.ts b/packages/twenty-front/src/modules/users/graphql/queries/saveSmsResponse.ts
deleted file mode 100644
index a7c0a9f9bd31..000000000000
--- a/packages/twenty-front/src/modules/users/graphql/queries/saveSmsResponse.ts
+++ /dev/null
@@ -1,151 +0,0 @@
-import { gql } from '@apollo/client';
-export const SAVE_SMS_RESPONSE = gql`
- mutation CreateOneSms($input: SmsCreateInput!) {
- createSms(data: $input) {
- id
- dateCreated
- campaignName
- sid
- numSegments
- dateupdated
- createdAt
- uri
- status
- favorites {
- edges {
- node {
- __typename
- id
- campaignList {
- __typename
- id
- }
- specialty {
- __typename
- id
- }
- subspecialty {
- __typename
- id
- }
- subspecialtyId
- opportunityId
- company {
- __typename
- id
- }
- updatedAt
- createdAt
- messageResponseId
- workspaceMember {
- __typename
- id
- }
- person {
- __typename
- id
- }
- sms {
- __typename
- id
- }
- workspaceMemberId
- abcId
- personId
- abc {
- __typename
- id
- }
- id
- position
- opportunity {
- __typename
- id
- }
- companyId
- specialtyId
- campaignListId
- messageResponse {
- __typename
- id
- }
- smsId
- }
- __typename
- }
- __typename
- }
- position
- activityTargets {
- edges {
- node {
- __typename
- id
- abcId
- person {
- __typename
- id
- }
- id
- createdAt
- personId
- campaignList {
- __typename
- id
- }
- subspecialty {
- __typename
- id
- }
- activity {
- __typename
- id
- }
- specialty {
- __typename
- id
- }
- messageResponse {
- __typename
- id
- }
- company {
- __typename
- id
- }
- opportunityId
- specialtyId
- updatedAt
- subspecialtyId
- abc {
- __typename
- id
- }
- activityId
- opportunity {
- __typename
- id
- }
- smsId
- companyId
- messageResponseId
- sms {
- __typename
- id
- }
- campaignListId
- }
- __typename
- }
- __typename
- }
- id
- direction
- body
- to
- updatedAt
- from
- __typename
- }
- }
-`;
diff --git a/packages/twenty-front/src/modules/users/graphql/queries/updateCampaignlistStatus.ts b/packages/twenty-front/src/modules/users/graphql/queries/updateCampaignlistStatus.ts
deleted file mode 100644
index 25da110c7983..000000000000
--- a/packages/twenty-front/src/modules/users/graphql/queries/updateCampaignlistStatus.ts
+++ /dev/null
@@ -1,9 +0,0 @@
-import { gql } from '@apollo/client';
-
-export const UPDATE_CAMPAIGNLIST_STATUS = gql`
-mutation UpdateOneCampaign($idToUpdate: ID!, $input: CampaignUpdateInput!) {
- updateCampaign(id: $idToUpdate, data: $input) {
- id
- }
- }
-`;
\ No newline at end of file
diff --git a/packages/twenty-front/src/modules/users/graphql/queries/updateLastExecutionId.ts b/packages/twenty-front/src/modules/users/graphql/queries/updateLastExecutionId.ts
deleted file mode 100644
index 95d89d9a2589..000000000000
--- a/packages/twenty-front/src/modules/users/graphql/queries/updateLastExecutionId.ts
+++ /dev/null
@@ -1,9 +0,0 @@
-import { gql } from '@apollo/client';
-
-export const UPDATE_LAST_EXECUTION_ID = gql`
-mutation UpdateOneCampaign($idToUpdate: ID!, $input: CampaignUpdateInput!) {
- updateCampaign(id: $idToUpdate, data: $input) {
- id
- }
- }
-`;
\ No newline at end of file
diff --git a/packages/twenty-front/src/pages/campaigns/CampaignForm.tsx b/packages/twenty-front/src/pages/campaigns/CampaignForm.tsx
index fe3c889d80b5..a4bfd88a1c20 100644
--- a/packages/twenty-front/src/pages/campaigns/CampaignForm.tsx
+++ b/packages/twenty-front/src/pages/campaigns/CampaignForm.tsx
@@ -198,19 +198,19 @@ export const CampaignForm = () => {
fetchUserDetails();
}, [userid]);
- // if (loading) {
- // return (
- // <>
- //
- //
- //
- // Collecting form data...
- //
- //
- //
- // >
- // );
- // } else
+ // if (loading) {
+ // return (
+ // <>
+ //
+ //
+ //
+ // Collecting form data...
+ //
+ //
+ //
+ // >
+ // );
+ // } else
if (loading && errorType === 'formexpired') {
return (
<>
diff --git a/packages/twenty-front/src/pages/object-record/RecordIndexPageHeader.tsx b/packages/twenty-front/src/pages/object-record/RecordIndexPageHeader.tsx
index 3d2ff43a3815..667517384832 100644
--- a/packages/twenty-front/src/pages/object-record/RecordIndexPageHeader.tsx
+++ b/packages/twenty-front/src/pages/object-record/RecordIndexPageHeader.tsx
@@ -41,10 +41,8 @@ export const RecordIndexPageHeader = ({
setPage('/campaigns');
} else if (objectNamePlural === 'segments') {
setPage('/segment');
- } else if (objectNamePlural === 'campaignTriggers') {
- setPage('/campaignTriggers');
}
- });
+ },[objectNamePlural]);
const handleClick = () => {
if (page) {
diff --git a/packages/twenty-ui/src/theme/constants/Modal.ts b/packages/twenty-ui/src/theme/constants/Modal.ts
index 2a53265cc00e..5450ba4169c4 100644
--- a/packages/twenty-ui/src/theme/constants/Modal.ts
+++ b/packages/twenty-ui/src/theme/constants/Modal.ts
@@ -3,5 +3,6 @@ export const MODAL = {
sm: '300px',
md: '400px',
lg: '53%',
+ xl:'100%',
},
};
From a195568008df4841fd1d8caf1cf23710263c8572 Mon Sep 17 00:00:00 2001
From: sanjana0190 <56463647+sanjana0190@users.noreply.github.com>
Date: Fri, 3 May 2024 14:39:33 +0530
Subject: [PATCH 023/122] Back-end API Controller
---
packages/twenty-server/src/app.module.ts | 2 +
.../src/campaign/campaign-execution.dto.ts | 24 ++
.../src/campaign/campaign.controller.spec.ts | 31 ++
.../src/campaign/campaign.controller.ts | 52 ++++
.../src/campaign/campaign.module.ts | 23 ++
.../src/campaign/campaign.service.ts | 286 ++++++++++++++++++
.../campaign/create-form-response-query.ts | 35 +++
.../src/campaign/formdata.dto.ts | 46 +++
.../campaign/get-campaign-trigger-query.ts | 38 +++
.../src/campaign/get-form-template-query.ts | 45 +++
.../src/campaign/get-lead-query.ts | 32 ++
.../src/campaign/get-opportunity-query.ts | 40 +++
.../twenty-server/src/campaign/id-list.dto.ts | 12 +
packages/twenty-server/src/campaign/id.dto.ts | 6 +
14 files changed, 672 insertions(+)
create mode 100644 packages/twenty-server/src/campaign/campaign-execution.dto.ts
create mode 100644 packages/twenty-server/src/campaign/campaign.controller.spec.ts
create mode 100644 packages/twenty-server/src/campaign/campaign.controller.ts
create mode 100644 packages/twenty-server/src/campaign/campaign.module.ts
create mode 100644 packages/twenty-server/src/campaign/campaign.service.ts
create mode 100644 packages/twenty-server/src/campaign/create-form-response-query.ts
create mode 100644 packages/twenty-server/src/campaign/formdata.dto.ts
create mode 100644 packages/twenty-server/src/campaign/get-campaign-trigger-query.ts
create mode 100644 packages/twenty-server/src/campaign/get-form-template-query.ts
create mode 100644 packages/twenty-server/src/campaign/get-lead-query.ts
create mode 100644 packages/twenty-server/src/campaign/get-opportunity-query.ts
create mode 100644 packages/twenty-server/src/campaign/id-list.dto.ts
create mode 100644 packages/twenty-server/src/campaign/id.dto.ts
diff --git a/packages/twenty-server/src/app.module.ts b/packages/twenty-server/src/app.module.ts
index c7af6a6450c9..5cfaad6b8a5f 100644
--- a/packages/twenty-server/src/app.module.ts
+++ b/packages/twenty-server/src/app.module.ts
@@ -26,6 +26,7 @@ import { WorkspaceCacheVersionModule } from 'src/engine/metadata-modules/workspa
import { CoreEngineModule } from './engine/core-modules/core-engine.module';
import { IntegrationsModule } from './engine/integrations/integrations.module';
+import { CampaignModule } from 'src/campaign/campaign.module';
@Module({
imports: [
@@ -47,6 +48,7 @@ import { IntegrationsModule } from './engine/integrations/integrations.module';
}),
// Integrations module, contains all the integrations with other services
IntegrationsModule,
+ CampaignModule,
// Core engine module, contains all the core modules
CoreEngineModule,
// Modules module, contains all business logic modules
diff --git a/packages/twenty-server/src/campaign/campaign-execution.dto.ts b/packages/twenty-server/src/campaign/campaign-execution.dto.ts
new file mode 100644
index 000000000000..c6c4e0cf3f24
--- /dev/null
+++ b/packages/twenty-server/src/campaign/campaign-execution.dto.ts
@@ -0,0 +1,24 @@
+import { Type } from 'class-transformer';
+import { IsISO8601, IsUUID, ValidateNested } from 'class-validator';
+
+import { IdList } from 'src/campaign/id-list.dto';
+
+export class CampaignExecutionDTO {
+ @IsUUID()
+ campaignId: string;
+
+ @IsISO8601({ strict: true })
+ queryTimestamp: string;
+
+ campaignTriggerId: string;
+
+ @IsISO8601({ strict: true })
+ startDate: Date;
+
+ @IsISO8601({ strict: true })
+ stopDate: Date;
+
+ @ValidateNested()
+ @Type(() => IdList)
+ id: IdList;
+}
diff --git a/packages/twenty-server/src/campaign/campaign.controller.spec.ts b/packages/twenty-server/src/campaign/campaign.controller.spec.ts
new file mode 100644
index 000000000000..796656f80d7b
--- /dev/null
+++ b/packages/twenty-server/src/campaign/campaign.controller.spec.ts
@@ -0,0 +1,31 @@
+import { HealthCheckService, HttpHealthIndicator } from '@nestjs/terminus';
+import { Test, TestingModule } from '@nestjs/testing';
+
+import { HealthController } from 'src/health/health.controller';
+
+describe('HealthController', () => {
+ let healthController: HealthController;
+ let testingModule: TestingModule;
+
+ beforeEach(async () => {
+ testingModule = await Test.createTestingModule({
+ providers: [
+ HealthController,
+ {
+ provide: HealthCheckService,
+ useValue: {},
+ },
+ {
+ provide: HttpHealthIndicator,
+ useValue: {},
+ },
+ ],
+ }).compile();
+
+ healthController = testingModule.get(HealthController);
+ });
+
+ it('should be defined', () => {
+ expect(healthController).toBeDefined();
+ });
+});
diff --git a/packages/twenty-server/src/campaign/campaign.controller.ts b/packages/twenty-server/src/campaign/campaign.controller.ts
new file mode 100644
index 000000000000..1a2019157e2b
--- /dev/null
+++ b/packages/twenty-server/src/campaign/campaign.controller.ts
@@ -0,0 +1,52 @@
+import { Body, Controller, Get, Param, Post } from '@nestjs/common';
+
+import { CampaignExecutionDTO } from 'src/campaign/campaign-execution.dto';
+import { CampaignService } from 'src/campaign/campaign.service';
+import { FormDataDTO } from 'src/campaign/formdata.dto';
+@Controller('/campaign')
+export class CampaignController {
+ constructor(private campaignService: CampaignService) {}
+
+ @Get('/:id')
+ async validateFormDetails(@Param() id: any) {
+ try {
+ id = id.id.toString();
+
+ return this.campaignService.validateFormDetails(id);
+ } catch (error) {
+ return error;
+ }
+ }
+
+ @Post('/save/:id')
+ async saveFormResponse(@Param() id: any, @Body() formData: FormDataDTO) {
+ try {
+ id = id.id.toString();
+
+ return this.campaignService.saveFormResponse(id, formData);
+ } catch (error) {
+ return error;
+ }
+ }
+
+ @Post('/execute')
+ async executeCampaign(@Body() campaignExecutionData: CampaignExecutionDTO) {
+ try {
+ return this.campaignService.triggerCampaignStartWorkflow(campaignExecutionData);
+ } catch (error) {
+ return error;
+ }
+ }
+ @Post('/lead/register/:id')
+ executeLeadRegistration(@Param() id: any,@Body() data:any){
+ // console.log(id.id)
+ try {
+ console.log(id.id)
+ this.campaignService.triggerLeadRegistrationWorkflow(id.id);
+ return true
+ } catch (error) {
+ return error;
+ }
+ }
+
+}
diff --git a/packages/twenty-server/src/campaign/campaign.module.ts b/packages/twenty-server/src/campaign/campaign.module.ts
new file mode 100644
index 000000000000..e242b4dad6fd
--- /dev/null
+++ b/packages/twenty-server/src/campaign/campaign.module.ts
@@ -0,0 +1,23 @@
+import { Module } from '@nestjs/common';
+
+import { CampaignController } from 'src/campaign/campaign.controller';
+import { CampaignService } from 'src/campaign/campaign.service';
+import { CreateFormResponse } from 'src/campaign/create-form-response-query';
+import { GetCampaignTrigger } from 'src/campaign/get-campaign-trigger-query';
+import { GetFormTemplate } from 'src/campaign/get-form-template-query';
+import { GetLeadData } from 'src/campaign/get-lead-query';
+import { GetOpportunityData } from 'src/campaign/get-opportunity-query';
+
+@Module({
+ imports: [],
+ controllers: [CampaignController],
+ providers: [
+ CampaignService,
+ CreateFormResponse,
+ GetCampaignTrigger,
+ GetFormTemplate,
+ GetLeadData,
+ GetOpportunityData,
+ ],
+})
+export class CampaignModule {}
diff --git a/packages/twenty-server/src/campaign/campaign.service.ts b/packages/twenty-server/src/campaign/campaign.service.ts
new file mode 100644
index 000000000000..a46f3022ca09
--- /dev/null
+++ b/packages/twenty-server/src/campaign/campaign.service.ts
@@ -0,0 +1,286 @@
+import { Injectable } from '@nestjs/common';
+
+import { error } from 'console';
+
+import fetch from 'node-fetch';
+import base64 from 'base64-js';
+
+import { FormDataDTO } from 'src/campaign/formdata.dto';
+import { CampaignExecutionDTO } from 'src/campaign/campaign-execution.dto';
+import { GetCampaignTrigger } from 'src/campaign/get-campaign-trigger-query';
+import { GetFormTemplate } from 'src/campaign/get-form-template-query';
+import { GetLeadData } from 'src/campaign/get-lead-query';
+import { CreateFormResponse } from 'src/campaign/create-form-response-query';
+import { GetOpportunityData } from 'src/campaign/get-opportunity-query';
+import { response } from 'express';
+
+@Injectable()
+export class CampaignService {
+
+ constructor(
+ private createFormResponse: CreateFormResponse,
+ private getCampaignTrigger: GetCampaignTrigger,
+ private getFormTemplate: GetFormTemplate,
+ private getLeadData: GetLeadData,
+ private getOpportunityData: GetOpportunityData,
+ ) {}
+
+ async triggerLeadRegistrationWorkflow(id: any) {
+ const data={
+ conf:{
+ patient_uuid:id
+ }
+ }
+ try {
+ let response = await fetch(
+ `${process.env.AIRFLOW_HOST}/api/v1/dags/${process.env.DAG_CONTACTED_OPPORTUNITIES}/dagRuns`,
+ {
+ method: 'post',
+ body: JSON.stringify(data),
+ headers: {
+ 'Content-Type': 'application/json',
+ Authorization: `Basic ${process.env.AIRFLOW_AUTH_TOKEN}`,
+ },
+ },
+ );
+
+ response = await response.json();
+ console.log(response)
+ return response;
+ } catch (error) {
+ return error;
+ }
+ }
+
+ async triggerIdentifiedWorkflow(requestBody: any) {
+ const data = {
+ conf: requestBody,
+ };
+
+ try {
+ let response = await fetch(
+ `${process.env.AIRFLOW_HOST}/api/v1/dags/${process.env.DAG_IDENTIFIED}/dagRuns`,
+ {
+ method: 'post',
+ body: JSON.stringify(data),
+ headers: {
+ 'Content-Type': 'application/json',
+ Authorization: `Basic ${process.env.AIRFLOW_AUTH_TOKEN}`,
+ },
+ },
+ );
+
+ response = await response.json();
+
+ return response;
+ } catch (error) {
+ return error;
+ }
+ }
+
+ async triggerCampaignStartWorkflow(
+ campaignExecutionData: CampaignExecutionDTO,
+ ) {
+ const data = {
+ conf: campaignExecutionData,
+ dag_run_id: `${campaignExecutionData.campaignTriggerId}-${Date.parse(Date())}`,
+ logical_date: campaignExecutionData.startDate,
+ note: 'string',
+ };
+
+ console.log(JSON.stringify(data));
+ try {
+ let response = await fetch(
+ `${process.env.AIRFLOW_HOST}/api/v1/dags/${process.env.DAG_CAMPAIGN}/dagRuns`,
+ {
+ method: 'post',
+ body: JSON.stringify(data),
+ headers: {
+ 'Content-Type': 'application/json',
+ Authorization: `Basic ${process.env.AIRFLOW_AUTH_TOKEN}`,
+ },
+ },
+ );
+
+ response = await response.json();
+ console.log(response)
+ return response;
+ } catch (error) {
+ return error;
+ }
+ }
+
+ uri = 'http://localhost:3000/graphql';
+ headers = {
+ 'Content-Type': 'application/json',
+ Authorization: `Bearer ${process.env.AUTH_TOKEN}`,
+ };
+
+ async apiCall(queryData, queryDataName) {
+ const response = await fetch(this.uri, {
+ method: 'post',
+ body: JSON.stringify(queryData),
+ headers: this.headers,
+ });
+
+ let data = await response.json();
+
+ data = data.data;
+ if (queryDataName === 'formTemplate') {
+ data = data.formTemplates.edges[0];
+ let valid: boolean = false;
+
+ if (data?.node?.status == 'ACTIVE') {
+ // console.log('askakskas', data?.node?.validDate);
+ // valid = Date.parse(data?.node?.validDate) > Date.parse(Date());
+ valid = true;
+ }
+ if (!valid) {
+ throw error('Form is not Active');
+ }
+ }
+ if (queryDataName === 'campaignTriggers') {
+ data = data.campaignTriggers.edges[0];
+ let valid: boolean = false;
+
+ if (data?.node?.stopDate !== null) {
+ valid = Date.parse(data?.node?.stopDate) > Date.parse(Date());
+ }
+ if (!valid) {
+ throw error('Campaign is not Active');
+ }
+ }
+ if (queryDataName === 'leads') {
+ data = data.leads.edges[0];
+ }
+ if (queryDataName === 'opportunity') {
+ return data.opportunities.totalCount == 1;
+ }
+
+ return data == undefined;
+ }
+
+ async fetchLeadData(queryData) {
+ try {
+ const response = await fetch(this.uri, {
+ method: 'post',
+ body: JSON.stringify(queryData),
+ headers: this.headers,
+ });
+
+ const data = await response.json();
+
+ return data;
+ } catch (error) {
+ console.error(error);
+ }
+ }
+ extractIdsFromRandomId = (decodedRandomId: string) => {
+ const idComponents = decodedRandomId.split('--');
+ const leadId = idComponents[0];
+ const formTemplateId = idComponents[1];
+ const campaignTriggerId = idComponents[2];
+
+ return {
+ leadId,
+ formTemplateId,
+ campaignTriggerId,
+ };
+ };
+
+ decodeRandomId = (encodedRandomId: string) => {
+ const decodedRandomId = new TextDecoder().decode(
+ base64.toByteArray(encodedRandomId),
+ );
+
+ return this.extractIdsFromRandomId(decodedRandomId);
+ };
+
+ async validateFormDetails(id: string) {
+ const decoded_ids = this.decodeRandomId(id);
+
+ console.log(decoded_ids);
+ try {
+ if (
+ await this.apiCall(
+ this.getFormTemplate.queryFormTemplate(decoded_ids.formTemplateId),
+ 'formTemplate',
+ )
+ ) {
+ throw error('Camapign Form Not Found');
+ }
+ if (
+ await this.apiCall(
+ this.getCampaignTrigger.queryCampaignTrigger(
+ decoded_ids.campaignTriggerId,
+ ),
+ 'campaignTriggers',
+ )
+ ) {
+ throw error('Camapign Execution Not Found');
+ }
+ if (
+ await this.apiCall(
+ this.getLeadData.queryLeadData(decoded_ids.leadId),
+ 'leads',
+ )
+ ) {
+ throw error('Lead Not Found');
+ }
+ const response = await this.fetchLeadData(
+ this.getLeadData.queryLeadData(decoded_ids.leadId),
+ );
+
+ // console.log(response?.data?.leads?.edges[0].node?.name);
+ const fetchedData = {
+ name: response?.data?.leads?.edges[0].node?.name,
+ email: response?.data?.leads?.edges[0].node?.email,
+ };
+
+ return fetchedData;
+ } catch (error) {
+ console.error(error);
+ return error
+ }
+ }
+
+ async saveFormResponse(id: string, formData: FormDataDTO) {
+ try {
+ const decoded_ids = this.decodeRandomId(id);
+
+ console.log(decoded_ids);
+ const response = await fetch(this.uri, {
+ method: 'post',
+ body: JSON.stringify(
+ this.createFormResponse.queryFormResponse(formData, decoded_ids),
+ ),
+ headers: this.headers,
+ });
+
+ const data = await response.json();
+ if (data.errors) {
+ throw error('Required Form Data is Invalid');
+ }
+
+ const requestbody = {
+ leadId: decoded_ids.leadId,
+ campaignTriggerId: decoded_ids.campaignTriggerId,
+ };
+
+ const opportunityIdExists = await this.apiCall(
+ this.getOpportunityData.queryOpportunityId(requestbody),
+ 'opportunity',
+ );
+
+ if (opportunityIdExists) {
+ const airflowResponse =
+ await this.triggerIdentifiedWorkflow(requestbody);
+
+ console.log(airflowResponse, 'airflowResponse');
+ }
+ return 'Form Data Saved Successfully';
+ } catch (error) {
+ console.error(error);
+ }
+ }
+}
diff --git a/packages/twenty-server/src/campaign/create-form-response-query.ts b/packages/twenty-server/src/campaign/create-form-response-query.ts
new file mode 100644
index 000000000000..97e1e50cfe2e
--- /dev/null
+++ b/packages/twenty-server/src/campaign/create-form-response-query.ts
@@ -0,0 +1,35 @@
+import { Injectable } from '@nestjs/common';
+
+@Injectable()
+export class CreateFormResponse {
+ queryFormResponse(data, decoded_ids) {
+ const queryCreateFormResponse = {
+ query: `mutation CreateOneFormResponse($input: FormResponseCreateInput!) {
+ createFormResponse(data: $input) {
+ id
+ }
+ }`,
+ variables: {
+ input: {
+ email: `${data?.email ?? ''}`,
+ firstName: `${data?.firstName ?? ''}`,
+ lastName: `${data?.lastName ?? ''}`,
+ consent: `${data?.consent ?? ''}`,
+ leadId: `${decoded_ids?.leadId}`,
+ name: `${data?.firstName ?? ''}`,
+ weight: `${data?.weight ?? ''}`,
+ gender: `${data?.gender ?? ''}`,
+ medicalHistory: `${data?.medicalHistory ?? ''}`,
+ appointmentReason: `${data?.appointmentReason ?? ''}`,
+ height: `${data?.height ?? ''}`,
+ appointmentType: `${data?.appointmentType ?? ''}`,
+ appointmentLocation: `${data?.appointmentLocation ?? ''}`,
+ phoneNumber: `${data?.phoneNumber ?? ''}`,
+ appointmentDate: data?.appintmentDate ?? null,
+ },
+ },
+ };
+
+ return queryCreateFormResponse;
+ }
+}
diff --git a/packages/twenty-server/src/campaign/formdata.dto.ts b/packages/twenty-server/src/campaign/formdata.dto.ts
new file mode 100644
index 000000000000..2a23f79f8bf6
--- /dev/null
+++ b/packages/twenty-server/src/campaign/formdata.dto.ts
@@ -0,0 +1,46 @@
+import { IsOptional } from 'class-validator';
+
+export class FormDataDTO {
+ @IsOptional()
+ email: string;
+
+ @IsOptional()
+ firstName: string;
+
+ @IsOptional()
+ name: string;
+
+ @IsOptional()
+ weight: string;
+
+ @IsOptional()
+ gender: string;
+
+ @IsOptional()
+ medicalHistory: string;
+
+ @IsOptional()
+ appointmentReason: string;
+
+ @IsOptional()
+ height: string;
+
+ @IsOptional()
+ appointmentType: string;
+
+ @IsOptional()
+ appointmentLocation: string;
+
+ @IsOptional()
+ consent: string;
+
+ @IsOptional()
+ phoneNumber: string;
+
+ @IsOptional()
+ lastName: string;
+
+ @IsOptional()
+ appointmentDate: Date;
+
+}
diff --git a/packages/twenty-server/src/campaign/get-campaign-trigger-query.ts b/packages/twenty-server/src/campaign/get-campaign-trigger-query.ts
new file mode 100644
index 000000000000..30a1fff2006f
--- /dev/null
+++ b/packages/twenty-server/src/campaign/get-campaign-trigger-query.ts
@@ -0,0 +1,38 @@
+import { Injectable } from '@nestjs/common';
+
+@Injectable()
+export class GetCampaignTrigger {
+ queryCampaignTrigger(id: string) {
+ const queryCampaignTriggerData = {
+ query: `query FindManyCampaignTriggers($filter: CampaignTriggerFilterInput, $orderBy: CampaignTriggerOrderByInput, $lastCursor: String, $limit: Float) {
+ campaignTriggers(
+ filter: $filter
+ orderBy: $orderBy
+ first: $limit
+ after: $lastCursor
+ ) {
+
+ edges {
+ node {
+ id
+ stopDate
+ }
+ }
+ totalCount
+ }
+ }`,
+ variables: {
+ filter: {
+ id: {
+ eq: `${id}`,
+ },
+ },
+ orderBy: {
+ position: 'AscNullsFirst',
+ },
+ },
+ };
+
+ return queryCampaignTriggerData;
+ }
+}
diff --git a/packages/twenty-server/src/campaign/get-form-template-query.ts b/packages/twenty-server/src/campaign/get-form-template-query.ts
new file mode 100644
index 000000000000..2af319615df3
--- /dev/null
+++ b/packages/twenty-server/src/campaign/get-form-template-query.ts
@@ -0,0 +1,45 @@
+import { Injectable } from '@nestjs/common';
+
+@Injectable()
+export class GetFormTemplate {
+ queryFormTemplate(id: string) {
+ const queryFormTemplateExists = {
+ query: `query FindManyFormTemplates($filter: FormTemplateFilterInput, $orderBy: FormTemplateOrderByInput, $lastCursor: String, $limit: Float) {
+ formTemplates(
+ filter: $filter
+ orderBy: $orderBy
+ first: $limit
+ after: $lastCursor
+ ) {
+ edges {
+ node {
+ id
+ name
+ status
+ }
+ cursor
+ __typename
+ }
+ pageInfo {
+ hasNextPage
+ startCursor
+ endCursor
+ }
+ totalCount
+ }
+ }`,
+ variables: {
+ filter: {
+ id: {
+ eq: `${id}`,
+ },
+ },
+ orderBy: {
+ position: 'AscNullsFirst',
+ },
+ },
+ };
+
+ return queryFormTemplateExists;
+ }
+}
diff --git a/packages/twenty-server/src/campaign/get-lead-query.ts b/packages/twenty-server/src/campaign/get-lead-query.ts
new file mode 100644
index 000000000000..d5b6bcb16ce7
--- /dev/null
+++ b/packages/twenty-server/src/campaign/get-lead-query.ts
@@ -0,0 +1,32 @@
+import { Injectable } from '@nestjs/common';
+
+@Injectable()
+export class GetLeadData {
+ queryLeadData(id: string) {
+ const queryLeadDataExists = {
+ query: `query FindManyLeads($filter: LeadFilterInput, $orderBy: LeadOrderByInput, $lastCursor: String, $limit: Float) {
+ leads(filter: $filter, orderBy: $orderBy, first: $limit, after: $lastCursor) {
+ edges {
+ node {
+ id,
+ name,
+ email
+ }
+ }
+ }
+ }`,
+ variables: {
+ filter: {
+ id: {
+ eq: `${id}`,
+ },
+ },
+ orderBy: {
+ position: 'AscNullsFirst',
+ },
+ },
+ };
+
+ return queryLeadDataExists;
+ }
+}
diff --git a/packages/twenty-server/src/campaign/get-opportunity-query.ts b/packages/twenty-server/src/campaign/get-opportunity-query.ts
new file mode 100644
index 000000000000..d0ac082675af
--- /dev/null
+++ b/packages/twenty-server/src/campaign/get-opportunity-query.ts
@@ -0,0 +1,40 @@
+import { Injectable } from '@nestjs/common';
+
+@Injectable()
+export class GetOpportunityData {
+ queryOpportunityId(data: any) {
+ const queryOpportunityIdExists = {
+ query: `query FindManyOpportunities($filter: OpportunityFilterInput, $orderBy: OpportunityOrderByInput, $lastCursor: String, $limit: Float) {
+ opportunities(
+ filter: $filter
+ orderBy: $orderBy
+ first: $limit
+ after: $lastCursor
+ ) {
+ edges {
+ node {
+ id
+ }
+ }
+ totalCount
+ }
+ }
+ `,
+ variables: {
+ filter: {
+ campaignTriggerId: {
+ eq: `${data.campaignTriggerId}`,
+ },
+ leadId: {
+ eq: `${data.leadId}`,
+ },
+ stage: {
+ eq: 'INFORMED',
+ },
+ },
+ },
+ };
+
+ return queryOpportunityIdExists;
+ }
+}
diff --git a/packages/twenty-server/src/campaign/id-list.dto.ts b/packages/twenty-server/src/campaign/id-list.dto.ts
new file mode 100644
index 000000000000..f8160e080584
--- /dev/null
+++ b/packages/twenty-server/src/campaign/id-list.dto.ts
@@ -0,0 +1,12 @@
+import { Type } from 'class-transformer';
+import { IsOptional, ValidateNested } from 'class-validator';
+
+import { IdDto } from 'src/campaign/id.dto';
+
+export class IdList {
+ @IsOptional()
+ selectedID: [];
+
+ @IsOptional()
+ unselectedID: [];
+}
diff --git a/packages/twenty-server/src/campaign/id.dto.ts b/packages/twenty-server/src/campaign/id.dto.ts
new file mode 100644
index 000000000000..5c4fc3e1a886
--- /dev/null
+++ b/packages/twenty-server/src/campaign/id.dto.ts
@@ -0,0 +1,6 @@
+import { IsUUID } from 'class-validator';
+
+export class IdDto {
+ @IsUUID()
+ id: string;
+}
From f24474c9d4f132bf0aceaa2d6fb3e04aa8f777c7 Mon Sep 17 00:00:00 2001
From: Sanjana
Date: Fri, 3 May 2024 22:08:24 +0530
Subject: [PATCH 024/122] Updated Button UI
---
.../ui/input/button/components/Button.tsx | 59 +++++++-----
.../src/pages/campaigns/CampaignForm.tsx | 89 +++++++------------
.../src/pages/campaigns/Campaigns.tsx | 2 +-
.../src/pages/campaigns/Form2.tsx | 15 +---
.../pages/object-record/RecordShowPage.tsx | 22 ++++-
.../src/theme/constants/MainColors.ts | 1 +
6 files changed, 93 insertions(+), 95 deletions(-)
diff --git a/packages/twenty-front/src/modules/ui/input/button/components/Button.tsx b/packages/twenty-front/src/modules/ui/input/button/components/Button.tsx
index 6fa8c4565e76..9188e99af8ff 100644
--- a/packages/twenty-front/src/modules/ui/input/button/components/Button.tsx
+++ b/packages/twenty-front/src/modules/ui/input/button/components/Button.tsx
@@ -1,12 +1,15 @@
import React from 'react';
import { css, useTheme } from '@emotion/react';
import styled from '@emotion/styled';
-import { IconComponent, Pill } from 'twenty-ui';
+import { IconComponent } from '@ui/display/icon/types/IconComponent';
+import { Pill } from '@ui/components/Pill/Pill';
+
+
export type ButtonSize = 'medium' | 'small';
export type ButtonPosition = 'standalone' | 'left' | 'middle' | 'right';
export type ButtonVariant = 'primary' | 'secondary' | 'tertiary';
-export type ButtonAccent = 'default' | 'blue' | 'danger';
+export type ButtonAccent = 'default' | 'blue' | 'danger' | 'dark';
export type ButtonProps = {
className?: string;
@@ -18,22 +21,15 @@ export type ButtonProps = {
position?: ButtonPosition;
accent?: ButtonAccent;
soon?: boolean;
- justify?: 'center' | 'flex-start' | 'flex-end';
disabled?: boolean;
focus?: boolean;
onClick?: (event: React.MouseEvent) => void;
-} & React.ComponentProps<'button'>;
+};
const StyledButton = styled.button<
Pick<
ButtonProps,
- | 'fullWidth'
- | 'variant'
- | 'size'
- | 'position'
- | 'accent'
- | 'focus'
- | 'justify'
+ 'fullWidth' | 'variant' | 'size' | 'position' | 'accent' | 'focus'
>
>`
align-items: center;
@@ -117,6 +113,30 @@ const StyledButton = styled.button<
}
`}
`;
+ case 'dark':
+ return css`
+ background: ${theme.color.black};
+ border-color: ${!disabled
+ ? focus
+ ? theme.color.black
+ : theme.background.transparent.light
+ : 'transparent'};
+ border-width: ${!disabled && focus ? '1px 1px !important' : 0};
+ box-shadow: ${!disabled && focus
+ ? `0 0 0 3px ${theme.color.gray70}`
+ : 'none'};
+ color: ${theme.grayScale.gray0};
+ opacity: ${disabled ? 0.24 : 1};
+
+ ${disabled
+ ? ''
+ : css`
+ &:hover,
+ &:active {
+ background: ${theme.color.gray50};
+ }
+ `}
+ `;
}
break;
case 'secondary':
@@ -182,7 +202,9 @@ const StyledButton = styled.button<
`;
case 'danger':
return css`
- background: transparent;
+ background: ${!disabled
+ ? theme.background.transparent.primary
+ : 'transparent'};
border-color: ${variant === 'secondary'
? focus
? theme.color.red
@@ -213,13 +235,13 @@ const StyledButton = styled.button<
border-radius: ${({ position, theme }) => {
switch (position) {
case 'left':
- return `${theme.border.radius.sm} 0px 0px ${theme.border.radius.sm}`;
+ return `${theme.border.radius.md} 0px 0px ${theme.border.radius.md}`;
case 'right':
- return `0px ${theme.border.radius.sm} ${theme.border.radius.sm} 0px`;
+ return `0px ${theme.border.radius.md} ${theme.border.radius.md} 0px`;
case 'middle':
return '0px';
case 'standalone':
- return theme.border.radius.sm;
+ return theme.border.radius.md;
}
}};
border-style: solid;
@@ -239,9 +261,8 @@ const StyledButton = styled.button<
font-weight: 500;
gap: ${({ theme }) => theme.spacing(1)};
height: ${({ size }) => (size === 'small' ? '24px' : '32px')};
- justify-content: ${({ justify }) => justify};
padding: ${({ theme }) => {
- return `0 ${theme.spacing(2)}`;
+ return `0 ${theme.spacing(8)}`;
}};
transition: background 0.1s ease;
@@ -270,7 +291,6 @@ export const Button = ({
position = 'standalone',
soon = false,
disabled = false,
- justify = 'flex-start',
focus = false,
onClick,
}: ButtonProps) => {
@@ -284,7 +304,6 @@ export const Button = ({
position={position}
disabled={soon || disabled}
focus={focus}
- justify={justify}
accent={accent}
className={className}
onClick={onClick}
@@ -294,4 +313,4 @@ export const Button = ({
{soon && }
);
-};
+};
\ No newline at end of file
diff --git a/packages/twenty-front/src/pages/campaigns/CampaignForm.tsx b/packages/twenty-front/src/pages/campaigns/CampaignForm.tsx
index a4bfd88a1c20..7cf0839d0703 100644
--- a/packages/twenty-front/src/pages/campaigns/CampaignForm.tsx
+++ b/packages/twenty-front/src/pages/campaigns/CampaignForm.tsx
@@ -19,37 +19,19 @@ import { Select } from '@/ui/input/components/Select';
import { TextArea } from '@/ui/input/components/TextArea';
import { TextInput } from '@/ui/input/components/TextInput';
import { AnimatedPlaceholderEmptyTextContainer } from '@/ui/layout/animated-placeholder/components/EmptyPlaceholderStyled';
-const StyledCard = styled.div`
- border: 1px solid ${({ theme }) => theme.border.color.medium};
- border-radius: ${({ theme }) => theme.border.radius.sm};
+
+const StyledInputCard = styled.div`
color: ${({ theme }) => theme.font.color.secondary};
- box-shadow: ${({ theme }) => theme.boxShadow.strong};
display: flex;
flex-direction: column;
justify-content: center;
- background: ${({ theme }) => theme.background.primary};
- height: 120%%;
- width: 70%;
- margin: auto;
align-items: center;
- margin-bottom: ${({ theme }) => theme.spacing(2)};
+ width:100%;
`;
-
const StyledDiv = styled.div`
- overflow-y: scroll;
- border: 1px solid ${({ theme }) => theme.border.color.medium};
- border-radius: ${({ theme }) => theme.border.radius.sm};
- color: ${({ theme }) => theme.font.color.secondary};
- box-shadow: ${({ theme }) => theme.boxShadow.strong};
- display: flex;
- flex-direction: column;
- justify-content: center;
- background: ${({ theme }) => theme.background.primary};
- height: auto%;
- width: 100%;
- margin: auto;
- align-items: center;
- margin-bottom: ${({ theme }) => theme.spacing(2)};
+`;
+const StyledSection = styled.div`
+ margin-bottom: ${({ theme }) => theme.spacing(6)};
`;
const StyledTitleContainer = styled.div`
@@ -64,16 +46,7 @@ const StyledTitle = styled.h2`
font-weight: ${({ theme }) => theme.font.weight.semiBold};
padding: ${({ theme }) => theme.spacing(6)};
`;
-const StyledInputCard = styled.div`
- color: ${({ theme }) => theme.font.color.secondary};
- display: flex;
- flex-direction: column;
- justify-content: center;
- height: 1005%;
- justify-content: space-between;
- width: 70%;
- align-items: center;
-`;
+
const StyledCheckboxInput = styled.div`
margin-top: ${({ theme }) => theme.spacing(4)};
@@ -228,13 +201,12 @@ if (loading && errorType === 'formexpired') {
return (
//div id - save id in form
-
-
+
Campaign Form
-
-
+
+
setFirstName(e)}
/>
-
-
+
+
+
+
setLastName(e)}
/>
-
-
+
+
+
+
setEmail(e)}
/>
-
-
-
+
+
+
+
setContact(e)}
/>
-
-
+
+
-
-
-
-
-
);
};
diff --git a/packages/twenty-front/src/pages/campaigns/Campaigns.tsx b/packages/twenty-front/src/pages/campaigns/Campaigns.tsx
index 8f5bc8fc47c6..e6ed5e44bb09 100644
--- a/packages/twenty-front/src/pages/campaigns/Campaigns.tsx
+++ b/packages/twenty-front/src/pages/campaigns/Campaigns.tsx
@@ -477,7 +477,7 @@ export const Campaigns = () => {
size="medium"
title="Save"
variant="primary"
- // accent="dark"
+ accent="dark"
onClick={handleSave}
/>
diff --git a/packages/twenty-front/src/pages/campaigns/Form2.tsx b/packages/twenty-front/src/pages/campaigns/Form2.tsx
index 573ad662cfaf..3c11a44208af 100644
--- a/packages/twenty-front/src/pages/campaigns/Form2.tsx
+++ b/packages/twenty-front/src/pages/campaigns/Form2.tsx
@@ -42,7 +42,7 @@ const StyledInputCard = styled.div`
display: flex;
flex-direction: column;
justify-content: center;
- height: 1005%;
+ height: 100%;
justify-content: space-between;
width: 70%;
align-items: center;
@@ -84,19 +84,6 @@ const StyledButton = styled.span`
margin-top: ${({ theme }) => theme.spacing(6)};
`;
-// const generateRandomId = (username: string, formId: string, campaignname: string) => {
-// const randomId = `${username}-${formId}-${campaignname}`;
-// const encodedRandomId = base64.fromByteArray(new TextEncoder().encode(randomId));
-// return encodedRandomId;
-// }
-
-// const username = "Ertha Creboe";
-// const formname = "abc";
-// const campaignname = "Healthy Lives";
-
-// const randomId = generateRandomId(username, formname, campaignname);
-// console.log("Encoded Random ID:", randomId);
-
export const Form2 = () => {
const createOptions = (options: any[]) =>
options.map((option: any) => ({ label: option, value: option }));
diff --git a/packages/twenty-front/src/pages/object-record/RecordShowPage.tsx b/packages/twenty-front/src/pages/object-record/RecordShowPage.tsx
index e20b6aa1fab7..96e49471a61f 100644
--- a/packages/twenty-front/src/pages/object-record/RecordShowPage.tsx
+++ b/packages/twenty-front/src/pages/object-record/RecordShowPage.tsx
@@ -27,6 +27,7 @@ import { useLazyQuery, useMutation } from '@apollo/client';
import { useCampaign } from '~/pages/campaigns/CampaignUseContext';
import { ConfirmationModal } from '@/ui/layout/modal/components/ConfirmationModal';
import { RunCampaignButton } from '@/ui/layout/page/RunCampaignButton';
+import { useDialogManager } from '@/ui/feedback/dialog-manager/hooks/useDialogManager';
export const RecordShowPage = () => {
const { objectNameSingular, objectRecordId } = useParams<{
@@ -119,6 +120,7 @@ const [campaigns, setCampaigns] = useState([]);
const [addTriggerCampaignRecord] = useMutation(ADD_TRIGGER_CAMPAIGN_RECORD);
const { enqueueSnackBar } = useSnackBar();
const navigate = useNavigate();
+const { enqueueDialog } = useDialogManager();
const [isConfirmModalOpen, setIsConfirmModalOpen] = useState(false);
const handleConfirmRun = async () => {
@@ -186,7 +188,20 @@ const handleConfirmRun = async () => {
};
const handleRuncampaign = async () => {
- setIsConfirmModalOpen(true);
+ enqueueDialog({
+ title: ' Are you sure you want to trigger this campaign?',
+ message:
+ 'Triggering this campaign will send notifications to all subscribed users.',
+ buttons: [
+ { title: 'Cancel' },
+ {
+ title: 'Run',
+ variant: 'primary',
+ onClick: handleConfirmRun,
+ role: 'confirm',
+ },
+ ],
+ });
};
@@ -243,7 +258,8 @@ const handleRuncampaign = async () => {
>
)}
- {
}
onConfirmClick={handleConfirmRun}
deleteButtonText="Run Campaign"
- />
+ /> */}
Date: Sat, 4 May 2024 09:23:37 +0530
Subject: [PATCH 025/122] triggered note drawer on change of opportunity stage
---
.../activities/components/ActivityTitle.tsx | 6 +-
.../display/components/SelectFieldDisplay.tsx | 12 +-
.../components/RecordInlineCell.tsx | 124 ++-
.../src/pages/Segment/Segment.tsx | 80 +-
.../twenty-front/src/pages/campaigns/Lead.tsx | 776 ++++++++----------
.../src/pages/campaigns/PreviewLeadsData.tsx | 2 +-
.../campaign/get-campaign-trigger-query.ts | 2 +-
.../src/campaign/get-form-template-query.ts | 2 +-
.../src/campaign/get-lead-query.ts | 2 +-
.../src/campaign/get-opportunity-query.ts | 2 +-
10 files changed, 513 insertions(+), 495 deletions(-)
diff --git a/packages/twenty-front/src/modules/activities/components/ActivityTitle.tsx b/packages/twenty-front/src/modules/activities/components/ActivityTitle.tsx
index da1c10d2f7cc..4a9982214a9d 100644
--- a/packages/twenty-front/src/modules/activities/components/ActivityTitle.tsx
+++ b/packages/twenty-front/src/modules/activities/components/ActivityTitle.tsx
@@ -24,6 +24,7 @@ import {
import { usePreviousHotkeyScope } from '@/ui/utilities/hotkey/hooks/usePreviousHotkeyScope';
import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
import { isDefined } from '~/utils/isDefined';
+import { useCampaign } from '~/pages/campaigns/CampaignUseContext';
const StyledEditableTitleInput = styled.input<{
completed: boolean;
@@ -78,7 +79,8 @@ export const ActivityTitle = ({ activityId }: ActivityTitleProps) => {
);
const { upsertActivity } = useUpsertActivity();
-
+ const {campaignData}=useCampaign();
+ const value=`Lead stage changed from [ ${campaignData.draftValue} to ${campaignData.fieldValue} ]`
const {
setHotkeyScopeAndMemorizePreviousScope,
goBackToPreviousHotkeyScope,
@@ -187,7 +189,7 @@ export const ActivityTitle = ({ activityId }: ActivityTitleProps) => {
autoComplete="off"
autoFocus
ref={titleInputRef}
- placeholder={`${activity.type} title`}
+ placeholder={campaignData.draftValue?value:`${activity.type} title`}
onChange={(event) => handleTitleChange(event.target.value)}
value={activityTitle}
completed={completed}
diff --git a/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/SelectFieldDisplay.tsx b/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/SelectFieldDisplay.tsx
index 5c2b52b3cfd7..68f2cf6a76c5 100644
--- a/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/SelectFieldDisplay.tsx
+++ b/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/SelectFieldDisplay.tsx
@@ -1,14 +1,24 @@
import { Tag } from '@/ui/display/tag/components/Tag';
import { useSelectField } from '../../hooks/useSelectField';
+import { useEffect } from 'react';
+import { useCampaign } from '~/pages/campaigns/CampaignUseContext';
export const SelectFieldDisplay = () => {
- const { fieldValue, fieldDefinition } = useSelectField();
+ const { fieldValue,draftValue, fieldDefinition } = useSelectField();
const selectedOption = fieldDefinition.metadata.options.find(
(option) => option.value === fieldValue,
);
+ const {campaignData,setCampaignData}=useCampaign()
+ useEffect(()=>{
+ setCampaignData({
+ ...campaignData,
+ draftValue:draftValue,
+ fieldValue:fieldValue
+ })
+ },[draftValue,fieldValue])
return selectedOption ? (
) : (
diff --git a/packages/twenty-front/src/modules/object-record/record-inline-cell/components/RecordInlineCell.tsx b/packages/twenty-front/src/modules/object-record/record-inline-cell/components/RecordInlineCell.tsx
index a35a3b7cbe2e..f0a930ae0c88 100644
--- a/packages/twenty-front/src/modules/object-record/record-inline-cell/components/RecordInlineCell.tsx
+++ b/packages/twenty-front/src/modules/object-record/record-inline-cell/components/RecordInlineCell.tsx
@@ -14,6 +14,8 @@ import { RelationPickerHotkeyScope } from '@/object-record/relation-picker/types
import { useInlineCell } from '../hooks/useInlineCell';
import { RecordInlineCellContainer } from './RecordInlineCellContainer';
+import { useOpenCreateActivityDrawer } from '@/activities/hooks/useOpenCreateActivityDrawer';
+import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
type RecordInlineCellProps = {
readonly?: boolean;
@@ -44,6 +46,26 @@ export const RecordInlineCell = ({ readonly }: RecordInlineCellProps) => {
closeInlineCell();
};
+ const openCreateActivity = useOpenCreateActivityDrawer();
+ const { enqueueSnackBar } = useSnackBar();
+ const handleStageChange: FieldInputEvent = (persistField) => {
+ persistField();
+ closeInlineCell();
+ openCreateActivity({
+ type: 'Note',
+ targetableObjects: [
+ {
+ id: entityId,
+ targetObjectNameSingular:
+ fieldDefinition.metadata.objectMetadataNameSingular,
+ },
+ ],
+ });
+
+ enqueueSnackBar('Changed Opportunity Stage', {
+ variant: 'success',
+ });
+ };
const handleEscape = () => {
closeInlineCell();
};
@@ -66,39 +88,75 @@ export const RecordInlineCell = ({ readonly }: RecordInlineCellProps) => {
const { getIcon } = useIcons();
return (
-
+ {fieldDefinition.metadata.fieldName !== 'stage' && (
+
+ }
+ displayModeContent={}
+ isDisplayModeContentEmpty={isFieldEmpty}
+ isDisplayModeFixHeight
+ editModeContentOnly={isFieldInputOnly}
+ />
+ )}
+ {fieldDefinition.metadata.fieldName === 'stage' && (
+
+ }
+ displayModeContent={}
+ isDisplayModeContentEmpty={isFieldEmpty}
+ isDisplayModeFixHeight
+ editModeContentOnly={isFieldInputOnly}
/>
- }
- displayModeContent={}
- isDisplayModeContentEmpty={isFieldEmpty}
- isDisplayModeFixHeight
- editModeContentOnly={isFieldInputOnly}
- />
+ )}
+ >
);
};
diff --git a/packages/twenty-front/src/pages/Segment/Segment.tsx b/packages/twenty-front/src/pages/Segment/Segment.tsx
index b74488c181bd..1ac0f33a52f9 100644
--- a/packages/twenty-front/src/pages/Segment/Segment.tsx
+++ b/packages/twenty-front/src/pages/Segment/Segment.tsx
@@ -1,11 +1,11 @@
-/* eslint-disable no-restricted-imports */
import styled from '@emotion/styled';
-import { Section } from '@react-email/components';
+import { Section } from '@react-email/components';
import { Button } from '@/ui/input/button/components/Button';
import { GRAY_SCALE } from '@/ui/theme/constants/GrayScale';
import { useMutation } from '@apollo/client';
import { v4 as uuidv4 } from 'uuid';
import {
+ IconLoader,
IconPlayerPlay,
IconPlus,
IconUsersGroup,
@@ -36,7 +36,6 @@ const StyledBoardContainer = styled.div`
padding: ${({ theme }) => theme.spacing(2)};
`;
-
const PageContainer = styled.div`
display: flex;
flex-direction: column;
@@ -44,10 +43,9 @@ const PageContainer = styled.div`
overflow-y: scroll;
scrollbar-color: ${({ theme }) => theme.border.color.strong};
scrollbar-width: thin;
-
- *::-webkit-scrollbar {
+ *::-webkit-scrollbar {
height: 8px;
- width: 8px;
+ width: 8px;
}
*::-webkit-scrollbar-corner {
@@ -55,12 +53,11 @@ const PageContainer = styled.div`
}
*::-webkit-scrollbar-thumb {
- background-color: ${({ theme }) => theme.border.color.strong};
+ background-color: ${({ theme }) => theme.border.color.strong};
border-radius: ${({ theme }) => theme.border.radius.sm};
}
`;
-
const StyledInputCard = styled.div`
color: ${({ theme }) => theme.font.color.secondary};
display: flex;
@@ -100,17 +97,21 @@ const SytledHR = styled.hr`
`;
export const Segment = () => {
- const { setLeadData, leadData } = useCampaign();
+ const [leadData, setLeadData] = useState([]);
const [selectedFilterOptions, setSelectedFilterOptions] = useState<
Record
>({});
- const navigate=useNavigate()
+ const navigate = useNavigate();
const [filterDivs, setFilterDivs] = useState([]);
const [segmentName, setSegmentName] = useState('');
const [segmentDescription, setSegmentDescription] = useState('');
const { enqueueSnackBar } = useSnackBar();
- const [filterString, setFilterString] = useState("");
+ const [filterString, setFilterString] = useState('');
+ const [filter, setFilter] = useState('');
+ const [cursor, setCursor] = useState(null);
+ const [filterLoading, setFilterLoading] = useState(false);
+
const handleFilterButtonClick = () => {
const key = `filter-${filterDivs.length + 1}`;
setFilterDivs([...filterDivs, key]);
@@ -154,7 +155,7 @@ export const Segment = () => {
const [addSegment] = useMutation(ADD_SEGMENT);
const handleRunQuery = async () => {
- const filter:any= {};
+ const filter: any = {};
filterDivs.forEach((key) => {
const condition = selectedFilterOptions[`${key}-conditions`];
@@ -173,31 +174,44 @@ export const Segment = () => {
});
}
});
- // const filterJson = await filter.json()
-
+ setFilter(filter);
let filterString = `{ "filter": ${JSON.stringify(filter)} }`;
console.log('This is the filter:', filterString);
const orderBy = { position: 'AscNullsFirst' };
try {
- const result = await filterleads({ variables: { filter, orderBy } });
+ const result = await filterleads({ variables: { filter } });
console.log('Data:', result.data);
- setLeadData({ ...leadData, data: result });
- result.data.leads.edges.forEach((edge: { node: any }) => {
- const lead = edge.node;
- console.log('Lead ID:', lead.id);
- console.log('Lead Email:', lead.email);
- console.log('Lead Age:', lead.age);
- console.log('Lead Advertisement Name:', lead.advertisementName);
- });
+ setLeadData(result.data.leads.edges);
+ setCursor(result.data.leads.pageInfo.endCursor);
+ if (result.data.leads.pageInfo.hasNextPage == true) {
+ setFilterLoading(true);
+ }
+ // result.data.leads.edges.forEach((edge: { node: any }) => {
+ // const lead = edge.node;
+ // });
} catch (error) {
console.error('Error fetching data:', error);
}
- setFilterString(filterString)
+ setFilterString(filterString);
};
+ const loadMore = async () => {
+ if (filterLoading) {
+ const result = await filterleads({
+ variables: {
+ filter,
+ lastCursor: cursor,
+ },
+ });
+ setCursor(result.data.leads.pageInfo.endCursor);
+ console.log(result.data, 'new DATA');
+ const newData = result.data.leads.edges;
+ setLeadData([...leadData, ...newData]);
+ }
+ };
const handlesave = async () => {
try {
const variables = {
@@ -214,15 +228,14 @@ export const Segment = () => {
enqueueSnackBar('Segment saved successfully', {
variant: 'success',
});
- navigate('/objects/segments')
- // window.location.reload();
+ navigate('/objects/segments');
+ window.location.reload();
} catch (errors: any) {
console.log('Error saving segment', error);
enqueueSnackBar(errors.message + 'Error while adding Campaign', {
variant: 'error',
});
}
-
};
return (
@@ -334,10 +347,17 @@ export const Segment = () => {
- {!loading && data && }
-
+ {!loading && data && }
+ {filterLoading && (
+
+ )}
>
);
};
-
diff --git a/packages/twenty-front/src/pages/campaigns/Lead.tsx b/packages/twenty-front/src/pages/campaigns/Lead.tsx
index c8256ff5cfbb..89d5022ca1b5 100644
--- a/packages/twenty-front/src/pages/campaigns/Lead.tsx
+++ b/packages/twenty-front/src/pages/campaigns/Lead.tsx
@@ -1,490 +1,418 @@
-/* eslint-disable @nx/workspace-styled-components-prefixed-with-styled */
-/* eslint-disable prefer-arrow/prefer-arrow-functions */
-/* eslint-disable no-restricted-imports */
-import { useState } from 'react';
-import { useLazyQuery } from '@apollo/client';
+import { useEffect, useRef, useState } from 'react';
import styled from '@emotion/styled';
-import { IconArrowRight, IconPlus } from '@tabler/icons-react';
+import { ActivityTargetableObject } from '@/activities/types/ActivityTargetableEntity';
+import { GET_CAMPAIGN_LISTS } from '@/users/graphql/queries/getCampaignList';
+import { GET_CAMPAIGN_TRIGGER } from '@/users/graphql/queries/getOneCampaignTrigger';
+import { useLazyQuery } from '@apollo/client';
+import { FILTER_LEADS } from '@/users/graphql/queries/filterLeads';
+import { Checkbox } from '@/ui/input/components/Checkbox';
+import { capitalize } from '~/utils/string/capitalize';
+import { useCampaign } from '~/pages/campaigns/CampaignUseContext';
+import { formatToHumanReadableDate } from '~/utils';
+import { EllipsisDisplay } from '@/ui/field/display/components/EllipsisDisplay';
+import { NumberDisplay } from '@/ui/field/display/components/NumberDisplay';
import {
- IconArrowBadgeRight,
- IconArrowLeft,
- IconCalendar,
- IconEqual,
+ IconRefresh,
+ IconUser,
+ IconListNumbers,
+ IconLocation,
+ IconBrandCampaignmonitor,
+ IconDeviceTv,
IconSpeakerphone,
- IconTrash,
- IconUsersGroup,
+ IconTextCaption,
+ IconCalendar,
+ IconLoader,
} from '@tabler/icons-react';
-import { MenuItemMultiSelectAvatar, TextInput } from 'tsup.ui.index';
-
-import { ModalWrapper } from '@/spreadsheet-import/components/ModalWrapper';
-import { H2Title } from '@/ui/display/typography/components/H2Title';
+import { IconButton } from '@/ui/input/button/components/IconButton';
+import { TextDisplay } from '@/ui/field/display/components/TextDisplay';
import { Button } from '@/ui/input/button/components/Button';
-import DateTimePicker from '@/ui/input/components/internal/date/components/DateTimePicker';
-import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
-import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
-import { Section } from '@/ui/layout/section/components/Section';
-import { FILTER_LEADS } from '@/users/graphql/queries/filterLeads';
-import { useCampaign } from '~/pages/campaigns/CampaignUseContext';
-import { PreviewLeadsData } from '~/pages/campaigns/PreviewLeadsData';
-const StyledCard = styled.div`
- border: 1px solid ${({ theme }) => theme.border.color.medium};
- border-radius: ${({ theme }) => theme.border.radius.sm};
- color: ${({ theme }) => theme.font.color.secondary};
- box-shadow: ${({ theme }) => theme.boxShadow.strong};
+const StyledInputCard = styled.div`
+ align-items: flex-start;
display: flex;
flex-direction: column;
- justify-content: center;
- background: ${({ theme }) => theme.background.primary};
- height: 90%;
- width: 70%;
- margin: auto;
- align-items: center;
- overflow: scroll;
+ height: auto;
+ justify-content: space-evenly;
+ width: 100%;
`;
-const StyledInputCard = styled.div`
- align-items: center;
- color: ${({ theme }) => theme.font.color.secondary};
- display: flex;
- flex-direction: column;
- height: 65%;
- justify-content: space-between;
- width: 70%;
+const StyledButtonContainer = styled.div`
+ display: inline-flex;
+ justify-content: flex-end;
+ margin-top: ${({ theme }) => theme.spacing(2)};
`;
-const StyledTitleCard = styled.div`
- align-items: center;
- color: ${({ theme }) => theme.font.color.secondary};
+const StyledCountContainer = styled.div`
display: flex;
- flex-direction: column;
- height: 10%;
- width: 70%;
+ flex-direction: row;
+ > * + * {
+ margin-left: ${({ theme }) => theme.spacing(10)};
+ }
+ margin-top: ${({ theme }) => theme.spacing(2)};
+ margin-bottom: ${({ theme }) => theme.spacing(6)};
+ height: auto;
justify-content: flex-start;
+ width: 100%;
+ align-items: center;
`;
-const StyledButton = styled.span`
- display: flex;
- justify-content: space-between;
+const StyledTable = styled.table<{ cursorPointer: boolean }>`
width: 100%;
+ border-collapse: collapse;
+ height: 10px;
+ margin-bottom: ${({ theme }) => theme.spacing(6)};
+ background-color: ${({ theme }) => theme.background.primary};
+ cursor: ${({ cursorPointer }) => (cursorPointer ? 'pointer' : 'inherit')};
+ font-family: inherit;
+ font-size: inherit;
+
+ font-weight: ${({ theme }) => theme.font.weight.regular};
+ max-width: 100%;
+ overflow: hidden;
+ text-decoration: inherit;
+
+ text-overflow: ellipsis;
+ white-space: nowrap;
`;
-const StyledAreaLabel = styled.span`
- align-content: center;
- display: flex;
- flex-direction: column;
- background: ${({ theme }) => theme.background.noisy};
- justify-content: center;
- width: 100%;
+const StyledTableRow = styled.tr`
+ &:nth-of-type(odd) {
+ background-color: ${({ theme }) => theme.background.primary};
+ }
`;
-const StyledTitle = styled.h3`
- color: ${({ theme }) => theme.font.color.secondary};
- font-weight: ${({ theme }) => theme.font.weight.medium};
- font-size: ${({ theme }) => theme.font.size.md};
+const StyledTableCell = styled.td`
+ padding: 5px;
+ height: 25px;
+ border: 1px solid ${({ theme }) => theme.border.color.light};
+ font-weight: ${({ theme }) => theme.font.weight.regular};
+ &:hover {
+ background-color: ${({ theme }) => theme.background.tertiary};
+ }
`;
-const TextContainer = styled.div`
- align-items: center;
- background: ${({ theme }) => theme.background.primary};
+const StyledTableHeaderCell = styled.td`
+ padding: 5px;
border: 1px solid ${({ theme }) => theme.border.color.medium};
-
- border-radius: ${({ theme }) => theme.border.radius.md};
- display: flex;
- margin-bottom: ${({ theme }) => theme.spacing(4)};
- margin-top: ${({ theme }) => theme.spacing(4)};
- padding-bottom: ${({ theme }) => theme.spacing(2)};
- padding-left: ${({ theme }) => theme.spacing(5)};
- padding-right: ${({ theme }) => theme.spacing(5)};
- padding-top: ${({ theme }) => theme.spacing(2)};
-`;
-const StyledFilter = styled(Section)`
- margin-left: ${({ theme }) => theme.spacing(2)};
+ height: 25px;
`;
+
const StyledComboInputContainer = styled.div`
display: flex;
- flex-direction: row;
- > * + * {
- margin-left: ${({ theme }) => theme.spacing(4)};
- }
align-items: center;
- justify-content: space-around;
-`;
-
-const StyledComboInputContainer1 = styled.div`
- display: flex;
- flex-direction: row;
> * + * {
- margin-left: ${({ theme }) => theme.spacing(4)};
+ margin-left: ${({ theme }) => theme.spacing(2)};
}
- align-items: center;
`;
-const StyledFilterCard = styled.div`
+
+const StyledContainer = styled.div`
+ align-items: flex-start;
+ align-self: stretch;
display: flex;
- flex-direction: row;
- > * + * {
- margin-left: ${({ theme }) => theme.spacing(4)};
- }
- width: 100%;
- justify-content: space-between;
+ flex-direction: column;
+ justify-content: center;
`;
-const Section2 = styled.div`
- align-items: center;
- display: flex;
- justify-content: space-between;
+
+const StyledLabelContainer = styled.div`
+ color: ${({ theme }) => theme.font.color.tertiary};
+ width: auto;
`;
-export const Lead = () => {
- const {
- setCurrentStep,
- currentStep,
- setLeadData,
- leadData,
- campaignData,
- setCampaignData,
- } = useCampaign();
- const [startDate, setStartDate] = useState(new Date());
- const [endDate, setEndDate] = useState(new Date());
- const [selectedFilterOptions, setSelectedFilterOptions] = useState<
- Record
- >({});
- const [leadSourceValue, setLeadSourceValue] = useState('');
- const [campaignNameValue, setCampaignNameValue] = useState('');
- const [locationValue, setLocationValue] = useState('');
- const [ageValue, setAgeValue] = useState('');
- const [modalOpen, setModalOpen] = useState(false);
-
- const handleLeadSourceChange = (event: any) => {
- setLeadSourceValue(event.target.value);
- };
+export const Leads = ({
+ targetableObject,
+}: {
+ targetableObject: ActivityTargetableObject;
+}) => {
+ const fields = [
+ { name: 'name', icon: IconUser },
+ { name: 'age', icon: IconListNumbers },
+ { name: 'location', icon: IconLocation },
+ { name: 'advertisementSource', icon: IconBrandCampaignmonitor },
+ { name: 'advertisementName', icon: IconDeviceTv },
+ { name: 'campaignName', icon: IconSpeakerphone },
+ { name: 'comments', icon: IconTextCaption },
+ { name: 'createdAt', icon: IconCalendar },
+ ];
- const handleCampaignNameChange = (event: any) => {
- setCampaignNameValue(event.target.value);
- };
+ const [leadsData, setLeadsData] = useState([]);
+ const [totalLeadsCount, setTotalLeadsCount] = useState(0);
+ const [selectedRows, setSelectedRows] = useState<{ [key: string]: boolean }>(
+ {},
+ );
+
+ const [filter, setFilter] = useState('');
+ const [cursor, setCursor] = useState(null);
+ const [loading, setLoading] = useState(false);
+ const lastLeadRef = useRef(null);
- const handleLocationChange = (event: any) => {
- setLocationValue(event.target.value);
- };
+ const [unSelectedRows, setunSelectedRows] = useState<{
+ [key: string]: boolean;
+ }>({});
+ const [masterCheckboxChecked, setMasterCheckboxChecked] = useState(true);
- const handleAgeChange = (event: any) => {
- setAgeValue(event.target.value);
- };
+ const { campaignData, setCampaignData } = useCampaign();
- const [filterleads, { loading, error, data }] = useLazyQuery(FILTER_LEADS, {
+ let [selectedCampaign, { data: selectedCampaignData }] = useLazyQuery(
+ GET_CAMPAIGN_LISTS,
+ {
+ fetchPolicy: 'network-only',
+ },
+ );
+
+ let [selectedCampaignTrigger, { data: selectedCampaignTriggerData }] =
+ useLazyQuery(GET_CAMPAIGN_TRIGGER, {
+ fetchPolicy: 'network-only',
+ });
+
+ let [filterleads, { data: filterLeadsData }] = useLazyQuery(FILTER_LEADS, {
fetchPolicy: 'network-only',
});
- const filterOptions = [
- { id: '1', name: 'Lead Source' },
- { id: '2', name: 'Campaign Name' },
- { id: '3', name: 'Select Date' },
- { id: '4', name: 'Location' },
- { id: '5', name: 'Age' },
- ];
+ const handleCheckboxChange = (leadId: string) => {
+ const updatedSelectedRows = { ...selectedRows };
+ updatedSelectedRows[leadId] = !updatedSelectedRows[leadId];
- const handleSubmit = async () => {
- const filter: Record = {};
- if (selectedFilterOptions['1']) {
- filter['advertisementSource'] = { ilike: `%${leadSourceValue}%` };
- }
- if (selectedFilterOptions['2']) {
- filter['campaignName'] = { ilike: `%${campaignNameValue}%` };
- }
- if (selectedFilterOptions['4']) {
- filter['location'] = { ilike: `%${locationValue}%` };
+ const updatedUnSelectedRows = { ...unSelectedRows };
+ if (!updatedSelectedRows[leadId]) {
+ updatedUnSelectedRows[leadId] = true;
+ delete updatedSelectedRows[leadId];
+ } else {
+ delete updatedUnSelectedRows[leadId];
}
- if (selectedFilterOptions['5']) {
- filter['age'] = { ilike: `%${ageValue}%` };
+
+ const selectedLeadIds = Object.keys(updatedSelectedRows);
+ const unSelectedLeadIds = Object.keys(updatedUnSelectedRows);
+
+ setCampaignData({
+ ...campaignData,
+ selectedId: selectedLeadIds,
+ unSelectedId: unSelectedLeadIds,
+ });
+
+ setSelectedRows(updatedSelectedRows);
+ setunSelectedRows(updatedUnSelectedRows);
+ };
+
+ const handleMasterCheckboxChange = () => {
+ const updatedSelectedRows: { [key: string]: boolean } = {};
+ const updatedUnSelectedRows: { [key: string]: boolean } = {};
+ if (!masterCheckboxChecked) {
+ leadsData?.leads?.edges.forEach((leadEdge: any) => {
+ const lead = leadEdge?.node;
+ updatedSelectedRows[lead.id] = true;
+ });
+ } else {
+ leadsData?.leads?.edges.forEach((leadEdge: any) => {
+ const lead = leadEdge?.node;
+ updatedUnSelectedRows[lead.id] = true;
+ });
}
+
+ const selectedLeadIds = Object.keys(updatedSelectedRows);
+ const unSelectedLeadIds = Object.keys(updatedUnSelectedRows);
+
+ setCampaignData({
+ ...campaignData,
+ selectedId: selectedLeadIds,
+ unSelectedId: unSelectedLeadIds,
+ });
+
+ setSelectedRows(updatedSelectedRows);
+ setunSelectedRows(updatedUnSelectedRows);
+ setMasterCheckboxChecked(!masterCheckboxChecked);
+ };
+ let campaignId = '';
+
+ const fetchLeads = async () => {
try {
- console.log(filter, '----------');
- const data = await filterleads({ variables: { filter: filter } });
- setModalOpen(true);
- console.log('---------=====', data?.data?.leads?.totalCount);
- setCampaignData({
- ...campaignData,
- leads: data?.data?.leads?.totalCount,
+ if (targetableObject.targetObjectNameSingular === 'campaignTrigger') {
+ const data = await selectedCampaignTrigger({
+ variables: {
+ objectRecordId: targetableObject.id,
+ },
+ });
+
+ campaignId = data.data.campaignTrigger.campaignId;
+ console.log(campaignId, 'campaignId');
+ } else if (targetableObject.targetObjectNameSingular === 'campaign') {
+ campaignId = targetableObject.id;
+ }
+
+ const data = await selectedCampaign({
+ variables: {
+ filter: {
+ id: { eq: campaignId },
+ },
+ },
+ });
+
+ const filter = JSON.parse(
+ data.data.campaigns.edges[0].node.segment.filters,
+ );
+ setFilter(filter);
+
+ const result = await filterleads({ variables: filter });
+ const leadsCount = result.data?.leads?.totalCount || 0;
+ setTotalLeadsCount(leadsCount);
+ setLeadsData(result.data.leads.edges);
+
+ const initialSelectedRows: { [key: string]: boolean } = {};
+ result.data.leads.edges.forEach((leadEdge: any) => {
+ const lead = leadEdge?.node;
+ initialSelectedRows[lead.id] = true;
});
+ setSelectedRows(initialSelectedRows);
- if (data) {
- console.log(data);
- setLeadData({ ...leadData, data: data });
+ const currentTime = new Date().toLocaleTimeString([], {
+ hour: '2-digit',
+ minute: '2-digit',
+ });
+ const currentDate = formatToHumanReadableDate(new Date());
+ const querystamp = `${currentDate} ${currentTime}`;
+ setCursor(result.data.leads.pageInfo.endCursor);
+ if (result.data.leads.pageInfo.hasNextPage == true) {
+ setLoading(true);
}
+ setCampaignData({
+ ...campaignData,
+ querystamp: querystamp,
+ });
} catch (error) {
- console.error('Error sending data to API:', error);
+ console.error('Error fetching campaign segment filter:', error);
}
};
- const handleCloseModal = () => {
- setModalOpen(false);
- };
-
- const removeFilterOption = (id: string) => {
- setSelectedFilterOptions((previous) => ({
- ...previous,
- [id]: false,
- }));
- switch (id) {
- case '1':
- setLeadSourceValue('');
- break;
- case '2':
- setCampaignNameValue('');
- break;
- case '4':
- setLocationValue('');
- break;
- case '5':
- setAgeValue('');
- break;
- default:
- break;
+ const loadMore = async () => {
+ if (loading) {
+ const result = await filterleads({
+ variables: {
+ lastCursor: cursor,
+ },
+ });
+ setSelectedRows((prevSelectedRows) => {
+ const newSelectedRows: { [key: string]: boolean } = {
+ ...prevSelectedRows,
+ };
+ result.data.leads.edges.forEach((leadEdge: any) => {
+ const lead = leadEdge?.node;
+ newSelectedRows[lead.id] = true;
+ });
+ return newSelectedRows;
+ });
+ setCursor(result.data.leads.pageInfo.endCursor);
+ const newLeadsData = result.data.leads.edges;
+ console.log(result.data, 'RESULT DATA');
+ setLeadsData([...leadsData, ...newLeadsData]);
}
- };
- const displayFilterSection = () => {
- return filterOptions.map((item) => {
- if (selectedFilterOptions[item.id]) {
- switch (item.id) {
- case '1':
- return (
-
-
-
-
- {' '}
- Lead Source
-
-
- is equal to
-
- handleLeadSourceChange(event)}
- />
-
-
-
- removeFilterOption(item.id)}
- />
-
-
- );
- case '2':
- return (
-
-
-
-
- {' '}
- Campaign Name
-
-
- is equal to
-
- handleCampaignNameChange(event)}
- />
-
-
-
- removeFilterOption(item.id)}
- />
-
-
- );
- case '3':
- return (
-
-
-
-
- Select Date
-
- setStartDate(startDate)}
- minDate={new Date()}
- />
- {/* */}
-
- to
-
-
- setEndDate(endDate)}
- minDate={startDate}
- />
-
-
-
- removeFilterOption(item.id)}
- />
-
-
- );
- case '4':
- return (
-
-
-
-
- Location
-
-
- is equal to
-
- handleLocationChange(event)}
- />
-
-
-
- removeFilterOption(item.id)}
- />
-
-
- );
-
- case '5':
- return (
-
-
-
-
- Age
-
-
- is equal to
-
- handleAgeChange(event)}
- />
-
-
-
- removeFilterOption(item.id)}
- />
-
-
- );
-
- default:
- return null;
- }
- }
- return null;
- });
+ console.log(leadsData, 'new Leads Data');
};
+ useEffect(() => {
+ fetchLeads();
+ }, [targetableObject.id, selectedCampaign]);
+
return (
<>
-
-
-
-
+
+
+
+
-
-
-
-
-
-
- }
- dropdownComponents={
-
- {filterOptions.map((item) => (
-
- setSelectedFilterOptions((previous) => ({
- ...previous,
- [item.id]: checked,
- }))
- }
- avatar={undefined}
- text={item.name}
+ {leadsData[0] && (
+ <>
+
+
+
+ Leads fetched at:
+
+
+
+
+
+ Total Leads:
+
+ {' '}
+
+
+
+
+ Selected Leads:
+
+
+
+
+
+
+ Unselected Leads:
+
+
+
+
+
+
+
+
+
+
+
+
+ {fields.map(({ name, icon: Icon }) => (
+
+
+ {Icon && }
+ {capitalize(name)}
+
+
))}
-
- }
- dropdownHotkeyScope={{
- scope: 'dropdownId',
- }}
- />
-
-
-
-
- {displayFilterSection()}
-
-
- setCurrentStep(currentStep - 1)}
- />
- setCurrentStep(currentStep + 1)}
- />
-
+
+ {leadsData.map((leadEdge: any) => {
+ const lead = leadEdge?.node;
+ return (
+ handleCheckboxChange(lead.id)}
+ >
+
+ handleCheckboxChange(lead.id)}
+ />
+
+ {fields.map(({ name }) => (
+
+
+ {lead[name].toString()}
+
+
+ ))}
+
+ );
+ })}
+
+ End of Table |
+
+ {loading && (
+
+
+
+ )}
+
+
+ >
+ )}
-
-
-
- {!loading && data && }
-
+
>
);
};
+
diff --git a/packages/twenty-front/src/pages/campaigns/PreviewLeadsData.tsx b/packages/twenty-front/src/pages/campaigns/PreviewLeadsData.tsx
index 0b19ea70a0db..8800095812cf 100644
--- a/packages/twenty-front/src/pages/campaigns/PreviewLeadsData.tsx
+++ b/packages/twenty-front/src/pages/campaigns/PreviewLeadsData.tsx
@@ -77,7 +77,7 @@ export const PreviewLeadsData = ({ data }) => {
Advertisement Name
- {data?.leads?.edges.map((leads: any) => (
+ {data.map((leads: any) => (
{leads.node?.name}
diff --git a/packages/twenty-server/src/campaign/get-campaign-trigger-query.ts b/packages/twenty-server/src/campaign/get-campaign-trigger-query.ts
index 30a1fff2006f..b601292507a9 100644
--- a/packages/twenty-server/src/campaign/get-campaign-trigger-query.ts
+++ b/packages/twenty-server/src/campaign/get-campaign-trigger-query.ts
@@ -4,7 +4,7 @@ import { Injectable } from '@nestjs/common';
export class GetCampaignTrigger {
queryCampaignTrigger(id: string) {
const queryCampaignTriggerData = {
- query: `query FindManyCampaignTriggers($filter: CampaignTriggerFilterInput, $orderBy: CampaignTriggerOrderByInput, $lastCursor: String, $limit: Float) {
+ query: `query FindManyCampaignTriggers($filter: CampaignTriggerFilterInput, $orderBy: CampaignTriggerOrderByInput, $lastCursor: String, $limit: Int) {
campaignTriggers(
filter: $filter
orderBy: $orderBy
diff --git a/packages/twenty-server/src/campaign/get-form-template-query.ts b/packages/twenty-server/src/campaign/get-form-template-query.ts
index 2af319615df3..a61f58e0a471 100644
--- a/packages/twenty-server/src/campaign/get-form-template-query.ts
+++ b/packages/twenty-server/src/campaign/get-form-template-query.ts
@@ -4,7 +4,7 @@ import { Injectable } from '@nestjs/common';
export class GetFormTemplate {
queryFormTemplate(id: string) {
const queryFormTemplateExists = {
- query: `query FindManyFormTemplates($filter: FormTemplateFilterInput, $orderBy: FormTemplateOrderByInput, $lastCursor: String, $limit: Float) {
+ query: `query FindManyFormTemplates($filter: FormTemplateFilterInput, $orderBy: FormTemplateOrderByInput, $lastCursor: String, $limit: Int) {
formTemplates(
filter: $filter
orderBy: $orderBy
diff --git a/packages/twenty-server/src/campaign/get-lead-query.ts b/packages/twenty-server/src/campaign/get-lead-query.ts
index d5b6bcb16ce7..025c48192d8c 100644
--- a/packages/twenty-server/src/campaign/get-lead-query.ts
+++ b/packages/twenty-server/src/campaign/get-lead-query.ts
@@ -4,7 +4,7 @@ import { Injectable } from '@nestjs/common';
export class GetLeadData {
queryLeadData(id: string) {
const queryLeadDataExists = {
- query: `query FindManyLeads($filter: LeadFilterInput, $orderBy: LeadOrderByInput, $lastCursor: String, $limit: Float) {
+ query: `query FindManyLeads($filter: LeadFilterInput, $orderBy: LeadOrderByInput, $lastCursor: String, $limit: Int) {
leads(filter: $filter, orderBy: $orderBy, first: $limit, after: $lastCursor) {
edges {
node {
diff --git a/packages/twenty-server/src/campaign/get-opportunity-query.ts b/packages/twenty-server/src/campaign/get-opportunity-query.ts
index d0ac082675af..39b070e8ebbe 100644
--- a/packages/twenty-server/src/campaign/get-opportunity-query.ts
+++ b/packages/twenty-server/src/campaign/get-opportunity-query.ts
@@ -4,7 +4,7 @@ import { Injectable } from '@nestjs/common';
export class GetOpportunityData {
queryOpportunityId(data: any) {
const queryOpportunityIdExists = {
- query: `query FindManyOpportunities($filter: OpportunityFilterInput, $orderBy: OpportunityOrderByInput, $lastCursor: String, $limit: Float) {
+ query: `query FindManyOpportunities($filter: OpportunityFilterInput, $orderBy: OpportunityOrderByInput, $lastCursor: String, $limit: Int) {
opportunities(
filter: $filter
orderBy: $orderBy
From da0b00a8da36116f93370e2b7a7b36feb25dc044 Mon Sep 17 00:00:00 2001
From: Sanjana
Date: Sat, 4 May 2024 09:49:12 +0530
Subject: [PATCH 026/122] Added scroll to leads table
---
.../activities/Leads/components/Leads.tsx | 143 +++---
.../components/ShowPageRightContainer.tsx | 17 +
.../twenty-front/src/pages/campaigns/Lead.tsx | 418 ------------------
3 files changed, 99 insertions(+), 479 deletions(-)
delete mode 100644 packages/twenty-front/src/pages/campaigns/Lead.tsx
diff --git a/packages/twenty-front/src/modules/activities/Leads/components/Leads.tsx b/packages/twenty-front/src/modules/activities/Leads/components/Leads.tsx
index 2bf4dda47112..9dd2a5b1707e 100644
--- a/packages/twenty-front/src/modules/activities/Leads/components/Leads.tsx
+++ b/packages/twenty-front/src/modules/activities/Leads/components/Leads.tsx
@@ -1,4 +1,4 @@
-import { useEffect, useState } from 'react';
+import { useEffect, useRef, useState } from 'react';
import styled from '@emotion/styled';
import { ActivityTargetableObject } from '@/activities/types/ActivityTargetableEntity';
import { GET_CAMPAIGN_LISTS } from '@/users/graphql/queries/getCampaignList';
@@ -10,13 +10,7 @@ import { capitalize } from '~/utils/string/capitalize';
import { useCampaign } from '~/pages/campaigns/CampaignUseContext';
import { formatToHumanReadableDate } from '~/utils';
import { EllipsisDisplay } from '@/ui/field/display/components/EllipsisDisplay';
-import { DateDisplay } from '@/ui/field/display/components/DateDisplay';
import { NumberDisplay } from '@/ui/field/display/components/NumberDisplay';
-import { TextFieldDisplay } from '@/object-record/record-field/meta-types/display/components/TextFieldDisplay';
-import { useGetIsSomeCellInEditModeState } from '@/object-record/record-table/hooks/internal/useGetIsSomeCellInEditMode';
-import { useMoveSoftFocusToCurrentCellOnHover } from '@/object-record/record-table/record-table-cell/hooks/useMoveSoftFocusToCurrentCellOnHover';
-import { isSoftFocusUsingMouseState } from '@/object-record/record-table/states/isSoftFocusUsingMouseState';
-import { useRecoilValue, useSetRecoilState } from 'recoil';
import {
IconRefresh,
IconUser,
@@ -28,9 +22,11 @@ import {
IconTextCaption,
IconCalendar,
IconNumbers,
+ IconLoader,
} from '@tabler/icons-react';
import { IconButton } from '@/ui/input/button/components/IconButton';
import { TextDisplay } from '@/ui/field/display/components/TextDisplay';
+import { Button } from '@/ui/input/button/components/Button';
const StyledInputCard = styled.div`
align-items: flex-start;
@@ -144,8 +140,12 @@ export const Leads = ({
const [selectedRows, setSelectedRows] = useState<{ [key: string]: boolean }>(
{},
);
- const [pageSize, setPageSize] = useState(10);
- const [cursor, setCursor] = useState(null);
+
+ const [filter, setFilter] = useState('');
+ const [cursor, setCursor] = useState(null);
+ const [loading, setLoading] = useState(false);
+ const lastLeadRef = useRef(null);
+
const [unSelectedRows, setunSelectedRows] = useState<{
[key: string]: boolean;
}>({});
@@ -153,38 +153,22 @@ export const Leads = ({
const { campaignData, setCampaignData } = useCampaign();
- let [selectedCampaign, { data: selectedCampaignData }] =
- useLazyQuery(GET_CAMPAIGN_LISTS, {
+ let [selectedCampaign, { data: selectedCampaignData }] = useLazyQuery(
+ GET_CAMPAIGN_LISTS,
+ {
fetchPolicy: 'network-only',
- });
+ },
+ );
- let [selectedCampaignTrigger, { data: selectedCampaignTriggerData }] =
+ let [selectedCampaignTrigger, { data: selectedCampaignTriggerData }] =
useLazyQuery(GET_CAMPAIGN_TRIGGER, {
fetchPolicy: 'network-only',
});
let [filterleads, { data: filterLeadsData }] = useLazyQuery(FILTER_LEADS, {
fetchPolicy: 'network-only',
- onCompleted: (data) => {
- setLeadsData(data);
- },
});
- useEffect(() => {
- if (leadsData.leads && leadsData.leads.edges) {
- const allLeadIds = leadsData.leads.edges.map(
- (leadEdge: any) => leadEdge.node.id,
- );
- const initialSelectedRows: { [key: string]: boolean } = {};
- const initialUnSelectedRows: { [key: string]: boolean } = {};
- allLeadIds.forEach((leadId: string) => {
- initialSelectedRows[leadId] = true;
- });
- setSelectedRows(initialSelectedRows);
- setunSelectedRows(initialUnSelectedRows);
- }
- }, [leadsData]);
-
const handleCheckboxChange = (leadId: string) => {
const updatedSelectedRows = { ...selectedRows };
updatedSelectedRows[leadId] = !updatedSelectedRows[leadId];
@@ -238,22 +222,21 @@ export const Leads = ({
setunSelectedRows(updatedUnSelectedRows);
setMasterCheckboxChecked(!masterCheckboxChecked);
};
- let campaignId = "";
+ let campaignId = '';
const fetchLeads = async () => {
try {
- if(targetableObject.targetObjectNameSingular === 'campaignTrigger'){
+ if (targetableObject.targetObjectNameSingular === 'campaignTrigger') {
const data = await selectedCampaignTrigger({
variables: {
- objectRecordId: targetableObject.id ,
+ objectRecordId: targetableObject.id,
},
});
campaignId = data.data.campaignTrigger.campaignId;
- console.log(campaignId, "campaignId")
- }
- else if(targetableObject.targetObjectNameSingular === 'campaign'){
- campaignId = targetableObject.id
+ console.log(campaignId, 'campaignId');
+ } else if (targetableObject.targetObjectNameSingular === 'campaign') {
+ campaignId = targetableObject.id;
}
const data = await selectedCampaign({
@@ -267,14 +250,30 @@ export const Leads = ({
const filter = JSON.parse(
data.data.campaigns.edges[0].node.segment.filters,
);
+ setFilter(filter);
const result = await filterleads({ variables: filter });
const leadsCount = result.data?.leads?.totalCount || 0;
setTotalLeadsCount(leadsCount);
- setLeadsData(result.data);
- const currentTime = new Date().toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });
+ setLeadsData(result.data.leads.edges);
+
+ const initialSelectedRows: { [key: string]: boolean } = {};
+ result.data.leads.edges.forEach((leadEdge: any) => {
+ const lead = leadEdge?.node;
+ initialSelectedRows[lead.id] = true;
+ });
+ setSelectedRows(initialSelectedRows);
+
+ const currentTime = new Date().toLocaleTimeString([], {
+ hour: '2-digit',
+ minute: '2-digit',
+ });
const currentDate = formatToHumanReadableDate(new Date());
const querystamp = `${currentDate} ${currentTime}`;
+ setCursor(result.data.leads.pageInfo.endCursor);
+ if (result.data.leads.pageInfo.hasNextPage == true) {
+ setLoading(true);
+ }
setCampaignData({
...campaignData,
querystamp: querystamp,
@@ -284,18 +283,36 @@ export const Leads = ({
}
};
+ const loadMore = async () => {
+ if (loading) {
+ const result = await filterleads({
+ variables: {
+ lastCursor: cursor,
+ },
+ });
+ setSelectedRows((prevSelectedRows) => {
+ const newSelectedRows: { [key: string]: boolean } = {
+ ...prevSelectedRows,
+ };
+ result.data.leads.edges.forEach((leadEdge: any) => {
+ const lead = leadEdge?.node;
+ newSelectedRows[lead.id] = true;
+ });
+ return newSelectedRows;
+ });
+ setCursor(result.data.leads.pageInfo.endCursor);
+ const newLeadsData = result.data.leads.edges;
+ console.log(result.data, 'RESULT DATA');
+ setLeadsData([...leadsData, ...newLeadsData]);
+ }
+
+ console.log(leadsData, 'new Leads Data');
+ };
+
useEffect(() => {
fetchLeads();
}, [targetableObject.id, selectedCampaign]);
- const handleLoadMore = () => {
- if (
- leadsData?.leads?.pageInfo?.hasNextPage &&
- leadsData?.leads?.pageInfo?.endCursor
- ) {
- setCursor(leadsData.leads.pageInfo.endCursor);
- }
- };
return (
<>
@@ -304,20 +321,10 @@ export const Leads = ({
Icon={IconRefresh}
onClick={fetchLeads}
/>
-
- {leadsData?.leads?.pageInfo?.hasNextPage && (
-
-
-
- )}
- {leadsData?.leads?.edges[0] && (
+ {leadsData[0] && (
<>
@@ -367,7 +374,7 @@ export const Leads = ({
))}
- {leadsData?.leads?.edges.map((leadEdge: any) => {
+ {leadsData.map((leadEdge: any) => {
const lead = leadEdge?.node;
return (
);
})}
+
+ End of Table |
+
+ {loading && (
+
+
+
+ )}
>
@@ -398,4 +419,4 @@ export const Leads = ({
>
);
-};
+};
\ No newline at end of file
diff --git a/packages/twenty-front/src/modules/ui/layout/show-page/components/ShowPageRightContainer.tsx b/packages/twenty-front/src/modules/ui/layout/show-page/components/ShowPageRightContainer.tsx
index aebb0cf6c124..1d7f4ce963e2 100644
--- a/packages/twenty-front/src/modules/ui/layout/show-page/components/ShowPageRightContainer.tsx
+++ b/packages/twenty-front/src/modules/ui/layout/show-page/components/ShowPageRightContainer.tsx
@@ -37,6 +37,23 @@ const StyledShowPageRightContainer = styled.div`
justify-content: start;
overflow: ${() => (useIsMobile() ? 'none' : 'hidden')};
width: calc(100% + 4px);
+ overflow-y: scroll;
+ scrollbar-color: ${({ theme }) => theme.border.color.strong};
+ scrollbar-width: thin;
+
+ *::-webkit-scrollbar {
+ height: 8px;
+ width: 8px;
+ }
+
+ *::-webkit-scrollbar-corner {
+ background-color: transparent;
+ }
+
+ *::-webkit-scrollbar-thumb {
+ background-color: ${({ theme }) => theme.border.color.strong};
+ border-radius: ${({ theme }) => theme.border.radius.sm};
+ }
`;
const StyledTabListContainer = styled.div`
diff --git a/packages/twenty-front/src/pages/campaigns/Lead.tsx b/packages/twenty-front/src/pages/campaigns/Lead.tsx
deleted file mode 100644
index 89d5022ca1b5..000000000000
--- a/packages/twenty-front/src/pages/campaigns/Lead.tsx
+++ /dev/null
@@ -1,418 +0,0 @@
-import { useEffect, useRef, useState } from 'react';
-import styled from '@emotion/styled';
-import { ActivityTargetableObject } from '@/activities/types/ActivityTargetableEntity';
-import { GET_CAMPAIGN_LISTS } from '@/users/graphql/queries/getCampaignList';
-import { GET_CAMPAIGN_TRIGGER } from '@/users/graphql/queries/getOneCampaignTrigger';
-import { useLazyQuery } from '@apollo/client';
-import { FILTER_LEADS } from '@/users/graphql/queries/filterLeads';
-import { Checkbox } from '@/ui/input/components/Checkbox';
-import { capitalize } from '~/utils/string/capitalize';
-import { useCampaign } from '~/pages/campaigns/CampaignUseContext';
-import { formatToHumanReadableDate } from '~/utils';
-import { EllipsisDisplay } from '@/ui/field/display/components/EllipsisDisplay';
-import { NumberDisplay } from '@/ui/field/display/components/NumberDisplay';
-import {
- IconRefresh,
- IconUser,
- IconListNumbers,
- IconLocation,
- IconBrandCampaignmonitor,
- IconDeviceTv,
- IconSpeakerphone,
- IconTextCaption,
- IconCalendar,
- IconLoader,
-} from '@tabler/icons-react';
-import { IconButton } from '@/ui/input/button/components/IconButton';
-import { TextDisplay } from '@/ui/field/display/components/TextDisplay';
-import { Button } from '@/ui/input/button/components/Button';
-
-const StyledInputCard = styled.div`
- align-items: flex-start;
- display: flex;
- flex-direction: column;
- height: auto;
- justify-content: space-evenly;
- width: 100%;
-`;
-
-const StyledButtonContainer = styled.div`
- display: inline-flex;
- justify-content: flex-end;
- margin-top: ${({ theme }) => theme.spacing(2)};
-`;
-
-const StyledCountContainer = styled.div`
- display: flex;
- flex-direction: row;
- > * + * {
- margin-left: ${({ theme }) => theme.spacing(10)};
- }
- margin-top: ${({ theme }) => theme.spacing(2)};
- margin-bottom: ${({ theme }) => theme.spacing(6)};
- height: auto;
- justify-content: flex-start;
- width: 100%;
- align-items: center;
-`;
-
-const StyledTable = styled.table<{ cursorPointer: boolean }>`
- width: 100%;
- border-collapse: collapse;
- height: 10px;
- margin-bottom: ${({ theme }) => theme.spacing(6)};
- background-color: ${({ theme }) => theme.background.primary};
- cursor: ${({ cursorPointer }) => (cursorPointer ? 'pointer' : 'inherit')};
- font-family: inherit;
- font-size: inherit;
-
- font-weight: ${({ theme }) => theme.font.weight.regular};
- max-width: 100%;
- overflow: hidden;
- text-decoration: inherit;
-
- text-overflow: ellipsis;
- white-space: nowrap;
-`;
-
-const StyledTableRow = styled.tr`
- &:nth-of-type(odd) {
- background-color: ${({ theme }) => theme.background.primary};
- }
-`;
-
-const StyledTableCell = styled.td`
- padding: 5px;
- height: 25px;
- border: 1px solid ${({ theme }) => theme.border.color.light};
- font-weight: ${({ theme }) => theme.font.weight.regular};
- &:hover {
- background-color: ${({ theme }) => theme.background.tertiary};
- }
-`;
-
-const StyledTableHeaderCell = styled.td`
- padding: 5px;
- border: 1px solid ${({ theme }) => theme.border.color.medium};
- height: 25px;
-`;
-
-const StyledComboInputContainer = styled.div`
- display: flex;
- align-items: center;
- > * + * {
- margin-left: ${({ theme }) => theme.spacing(2)};
- }
-`;
-
-const StyledContainer = styled.div`
- align-items: flex-start;
- align-self: stretch;
- display: flex;
- flex-direction: column;
- justify-content: center;
-`;
-
-const StyledLabelContainer = styled.div`
- color: ${({ theme }) => theme.font.color.tertiary};
- width: auto;
-`;
-
-export const Leads = ({
- targetableObject,
-}: {
- targetableObject: ActivityTargetableObject;
-}) => {
- const fields = [
- { name: 'name', icon: IconUser },
- { name: 'age', icon: IconListNumbers },
- { name: 'location', icon: IconLocation },
- { name: 'advertisementSource', icon: IconBrandCampaignmonitor },
- { name: 'advertisementName', icon: IconDeviceTv },
- { name: 'campaignName', icon: IconSpeakerphone },
- { name: 'comments', icon: IconTextCaption },
- { name: 'createdAt', icon: IconCalendar },
- ];
-
- const [leadsData, setLeadsData] = useState([]);
- const [totalLeadsCount, setTotalLeadsCount] = useState(0);
- const [selectedRows, setSelectedRows] = useState<{ [key: string]: boolean }>(
- {},
- );
-
- const [filter, setFilter] = useState('');
- const [cursor, setCursor] = useState(null);
- const [loading, setLoading] = useState(false);
- const lastLeadRef = useRef(null);
-
- const [unSelectedRows, setunSelectedRows] = useState<{
- [key: string]: boolean;
- }>({});
- const [masterCheckboxChecked, setMasterCheckboxChecked] = useState(true);
-
- const { campaignData, setCampaignData } = useCampaign();
-
- let [selectedCampaign, { data: selectedCampaignData }] = useLazyQuery(
- GET_CAMPAIGN_LISTS,
- {
- fetchPolicy: 'network-only',
- },
- );
-
- let [selectedCampaignTrigger, { data: selectedCampaignTriggerData }] =
- useLazyQuery(GET_CAMPAIGN_TRIGGER, {
- fetchPolicy: 'network-only',
- });
-
- let [filterleads, { data: filterLeadsData }] = useLazyQuery(FILTER_LEADS, {
- fetchPolicy: 'network-only',
- });
-
- const handleCheckboxChange = (leadId: string) => {
- const updatedSelectedRows = { ...selectedRows };
- updatedSelectedRows[leadId] = !updatedSelectedRows[leadId];
-
- const updatedUnSelectedRows = { ...unSelectedRows };
- if (!updatedSelectedRows[leadId]) {
- updatedUnSelectedRows[leadId] = true;
- delete updatedSelectedRows[leadId];
- } else {
- delete updatedUnSelectedRows[leadId];
- }
-
- const selectedLeadIds = Object.keys(updatedSelectedRows);
- const unSelectedLeadIds = Object.keys(updatedUnSelectedRows);
-
- setCampaignData({
- ...campaignData,
- selectedId: selectedLeadIds,
- unSelectedId: unSelectedLeadIds,
- });
-
- setSelectedRows(updatedSelectedRows);
- setunSelectedRows(updatedUnSelectedRows);
- };
-
- const handleMasterCheckboxChange = () => {
- const updatedSelectedRows: { [key: string]: boolean } = {};
- const updatedUnSelectedRows: { [key: string]: boolean } = {};
- if (!masterCheckboxChecked) {
- leadsData?.leads?.edges.forEach((leadEdge: any) => {
- const lead = leadEdge?.node;
- updatedSelectedRows[lead.id] = true;
- });
- } else {
- leadsData?.leads?.edges.forEach((leadEdge: any) => {
- const lead = leadEdge?.node;
- updatedUnSelectedRows[lead.id] = true;
- });
- }
-
- const selectedLeadIds = Object.keys(updatedSelectedRows);
- const unSelectedLeadIds = Object.keys(updatedUnSelectedRows);
-
- setCampaignData({
- ...campaignData,
- selectedId: selectedLeadIds,
- unSelectedId: unSelectedLeadIds,
- });
-
- setSelectedRows(updatedSelectedRows);
- setunSelectedRows(updatedUnSelectedRows);
- setMasterCheckboxChecked(!masterCheckboxChecked);
- };
- let campaignId = '';
-
- const fetchLeads = async () => {
- try {
- if (targetableObject.targetObjectNameSingular === 'campaignTrigger') {
- const data = await selectedCampaignTrigger({
- variables: {
- objectRecordId: targetableObject.id,
- },
- });
-
- campaignId = data.data.campaignTrigger.campaignId;
- console.log(campaignId, 'campaignId');
- } else if (targetableObject.targetObjectNameSingular === 'campaign') {
- campaignId = targetableObject.id;
- }
-
- const data = await selectedCampaign({
- variables: {
- filter: {
- id: { eq: campaignId },
- },
- },
- });
-
- const filter = JSON.parse(
- data.data.campaigns.edges[0].node.segment.filters,
- );
- setFilter(filter);
-
- const result = await filterleads({ variables: filter });
- const leadsCount = result.data?.leads?.totalCount || 0;
- setTotalLeadsCount(leadsCount);
- setLeadsData(result.data.leads.edges);
-
- const initialSelectedRows: { [key: string]: boolean } = {};
- result.data.leads.edges.forEach((leadEdge: any) => {
- const lead = leadEdge?.node;
- initialSelectedRows[lead.id] = true;
- });
- setSelectedRows(initialSelectedRows);
-
- const currentTime = new Date().toLocaleTimeString([], {
- hour: '2-digit',
- minute: '2-digit',
- });
- const currentDate = formatToHumanReadableDate(new Date());
- const querystamp = `${currentDate} ${currentTime}`;
- setCursor(result.data.leads.pageInfo.endCursor);
- if (result.data.leads.pageInfo.hasNextPage == true) {
- setLoading(true);
- }
- setCampaignData({
- ...campaignData,
- querystamp: querystamp,
- });
- } catch (error) {
- console.error('Error fetching campaign segment filter:', error);
- }
- };
-
- const loadMore = async () => {
- if (loading) {
- const result = await filterleads({
- variables: {
- lastCursor: cursor,
- },
- });
- setSelectedRows((prevSelectedRows) => {
- const newSelectedRows: { [key: string]: boolean } = {
- ...prevSelectedRows,
- };
- result.data.leads.edges.forEach((leadEdge: any) => {
- const lead = leadEdge?.node;
- newSelectedRows[lead.id] = true;
- });
- return newSelectedRows;
- });
- setCursor(result.data.leads.pageInfo.endCursor);
- const newLeadsData = result.data.leads.edges;
- console.log(result.data, 'RESULT DATA');
- setLeadsData([...leadsData, ...newLeadsData]);
- }
-
- console.log(leadsData, 'new Leads Data');
- };
-
- useEffect(() => {
- fetchLeads();
- }, [targetableObject.id, selectedCampaign]);
-
- return (
- <>
-
-
-
-
-
- {leadsData[0] && (
- <>
-
-
-
- Leads fetched at:
-
-
-
-
-
- Total Leads:
-
- {' '}
-
-
-
-
- Selected Leads:
-
-
-
-
-
-
- Unselected Leads:
-
-
-
-
-
-
-
-
-
-
-
-
- {fields.map(({ name, icon: Icon }) => (
-
-
- {Icon && }
- {capitalize(name)}
-
-
- ))}
-
- {leadsData.map((leadEdge: any) => {
- const lead = leadEdge?.node;
- return (
- handleCheckboxChange(lead.id)}
- >
-
- handleCheckboxChange(lead.id)}
- />
-
- {fields.map(({ name }) => (
-
-
- {lead[name].toString()}
-
-
- ))}
-
- );
- })}
-
- End of Table |
-
- {loading && (
-
-
-
- )}
-
-
- >
- )}
-
-
- >
- );
-};
-
From 6529c243fbfa4896e0378429cb7d30ff90971bc9 Mon Sep 17 00:00:00 2001
From: Sanjana
Date: Mon, 6 May 2024 17:32:01 +0530
Subject: [PATCH 027/122] updated form ui
---
.../activities/Leads/components/Leads.tsx | 281 ++++++++++++-----
.../src/pages/campaigns/CampaignForm.tsx | 39 ++-
.../src/pages/campaigns/CampaignForm2.tsx | 198 ++++++------
.../src/pages/campaigns/CampaignForm3.tsx | 296 ++++++++----------
.../src/pages/campaigns/Form1.tsx | 6 +
.../src/pages/campaigns/Form2.tsx | 7 +
.../src/pages/campaigns/Form3.tsx | 290 ++++++++---------
.../pages/object-record/RecordShowPage.tsx | 15 +-
8 files changed, 606 insertions(+), 526 deletions(-)
diff --git a/packages/twenty-front/src/modules/activities/Leads/components/Leads.tsx b/packages/twenty-front/src/modules/activities/Leads/components/Leads.tsx
index 9dd2a5b1707e..52c5e143c7c3 100644
--- a/packages/twenty-front/src/modules/activities/Leads/components/Leads.tsx
+++ b/packages/twenty-front/src/modules/activities/Leads/components/Leads.tsx
@@ -27,6 +27,9 @@ import {
import { IconButton } from '@/ui/input/button/components/IconButton';
import { TextDisplay } from '@/ui/field/display/components/TextDisplay';
import { Button } from '@/ui/input/button/components/Button';
+import { formatNumber } from '~/utils/format/number';
+import { DateTimeDisplay } from '@/ui/field/display/components/DateTimeDisplay';
+import { boolean } from 'zod';
const StyledInputCard = styled.div`
align-items: flex-start;
@@ -118,7 +121,9 @@ const StyledLabelContainer = styled.div`
color: ${({ theme }) => theme.font.color.tertiary};
width: auto;
`;
-
+interface CheckboxState {
+ [key: string]: boolean;
+}
export const Leads = ({
targetableObject,
}: {
@@ -140,17 +145,20 @@ export const Leads = ({
const [selectedRows, setSelectedRows] = useState<{ [key: string]: boolean }>(
{},
);
-
+
const [filter, setFilter] = useState('');
const [cursor, setCursor] = useState(null);
const [loading, setLoading] = useState(false);
const lastLeadRef = useRef(null);
+ const [selectedID, setSelectedID] = useState(new Set());
+ const [unselectedID, setUnselectedID] = useState(new Set());
const [unSelectedRows, setunSelectedRows] = useState<{
[key: string]: boolean;
}>({});
const [masterCheckboxChecked, setMasterCheckboxChecked] = useState(true);
-
+ const [isChecked, setIsChecked] = useState(true);
+ const [checkbox,setCheckbox]=useState({});
const { campaignData, setCampaignData } = useCampaign();
let [selectedCampaign, { data: selectedCampaignData }] = useLazyQuery(
@@ -169,59 +177,120 @@ export const Leads = ({
fetchPolicy: 'network-only',
});
- const handleCheckboxChange = (leadId: string) => {
- const updatedSelectedRows = { ...selectedRows };
- updatedSelectedRows[leadId] = !updatedSelectedRows[leadId];
-
- const updatedUnSelectedRows = { ...unSelectedRows };
- if (!updatedSelectedRows[leadId]) {
- updatedUnSelectedRows[leadId] = true;
- delete updatedSelectedRows[leadId];
+ // const handleCheckboxChange = (leadId: string) => {
+ // const updatedSelectedRows = { ...selectedRows };
+ // updatedSelectedRows[leadId] = !updatedSelectedRows[leadId];
+
+ // const updatedUnSelectedRows = { ...unSelectedRows };
+ // if (!updatedSelectedRows[leadId]) {
+ // updatedUnSelectedRows[leadId] = true;
+ // delete updatedSelectedRows[leadId];
+ // } else {
+ // delete updatedUnSelectedRows[leadId];
+ // }
+
+ // const selectedLeadIds = Object.keys(updatedSelectedRows);
+ // const unSelectedLeadIds = Object.keys(updatedUnSelectedRows);
+
+ // setCampaignData({
+ // ...campaignData,
+ // selectedId: selectedLeadIds,
+ // unSelectedId: unSelectedLeadIds,
+ // });
+
+ // setSelectedRows(updatedSelectedRows);
+ // setunSelectedRows(updatedUnSelectedRows);
+ // };
+
+ // const handleMasterCheckboxChange = () => {
+ // const updatedSelectedRows = { ...selectedRows };
+ // const updatedUnSelectedRows = { ...unSelectedRows };
+ // let allSelected = true;
+
+ // leadsData?.leads?.edges.forEach((leadEdge: any) => {
+ // const lead = leadEdge?.node;
+ // if (!masterCheckboxChecked) {
+ // updatedSelectedRows[lead.id] = true;
+ // delete updatedUnSelectedRows[lead.id];
+ // } else {
+ // // Check if the lead is currently unselected
+ // if (!updatedSelectedRows[lead.id]) allSelected = false;
+ // // Update both selected and unselected rows
+ // updatedSelectedRows[lead.id] = !updatedSelectedRows[lead.id];
+ // updatedUnSelectedRows[lead.id] = !updatedUnSelectedRows[lead.id];
+ // }
+ // if(masterCheckboxChecked){
+ // allSelected = true;
+ // }
+ // });
+
+ // const selectedLeadIds = Object.keys(updatedSelectedRows);
+ // const unSelectedLeadIds = Object.keys(updatedUnSelectedRows);
+
+ // setCampaignData({
+ // ...campaignData,
+ // selectedId: selectedLeadIds,
+ // unSelectedId: unSelectedLeadIds,
+ // });
+
+ // // If all were selected, now deselect all, else select all
+ // setSelectedRows(allSelected ? {} : updatedSelectedRows);
+ // setunSelectedRows(allSelected ? {} : updatedUnSelectedRows);
+ // setMasterCheckboxChecked(!masterCheckboxChecked);
+ // };
+
+ const handleCheckboxChange = (event: any, leadId: string): boolean => {
+ const { checked } = event.target;
+ if (checked) {
+ setSelectedID(selectedID.add(leadId));
+ unselectedID.delete(leadId);
+ setUnselectedID(unselectedID);
+ setCheckbox({
+ ...checkbox,
+ leadId:true
+ })
+ return true;
} else {
- delete updatedUnSelectedRows[leadId];
+ selectedID.delete(leadId);
+ setSelectedID(selectedID);
+ setUnselectedID(unselectedID.add(leadId));
+ setCheckbox({
+ ...checkbox,
+ leadId:false
+ })
}
+ setIsChecked(checked)
+ console.log(selectedID)
+ return false;
- const selectedLeadIds = Object.keys(updatedSelectedRows);
- const unSelectedLeadIds = Object.keys(updatedUnSelectedRows);
-
- setCampaignData({
- ...campaignData,
- selectedId: selectedLeadIds,
- unSelectedId: unSelectedLeadIds,
- });
-
- setSelectedRows(updatedSelectedRows);
- setunSelectedRows(updatedUnSelectedRows);
};
-
- const handleMasterCheckboxChange = () => {
- const updatedSelectedRows: { [key: string]: boolean } = {};
- const updatedUnSelectedRows: { [key: string]: boolean } = {};
- if (!masterCheckboxChecked) {
- leadsData?.leads?.edges.forEach((leadEdge: any) => {
- const lead = leadEdge?.node;
- updatedSelectedRows[lead.id] = true;
- });
+ const handleMasterCheckboxChange = (event: any) => {
+ const { checked } = event.target;
+ if (checked) {
+ for (const id of unselectedID.keys()) {
+ setSelectedID(selectedID.add(id));
+ unselectedID.delete(id);
+ setUnselectedID(unselectedID);
+ setCheckbox({
+ ...checkbox,
+ leadId:true
+ })
+ }
} else {
- leadsData?.leads?.edges.forEach((leadEdge: any) => {
- const lead = leadEdge?.node;
- updatedUnSelectedRows[lead.id] = true;
- });
+ for (const id of selectedID.keys()) {
+ selectedID.delete(id);
+ setSelectedID(selectedID);
+ setUnselectedID(unselectedID.add(id));
+ setCheckbox({
+ ...checkbox,
+ leadId:false
+ })
+ }
}
+ console.log(selectedID, 'selectedID');
- const selectedLeadIds = Object.keys(updatedSelectedRows);
- const unSelectedLeadIds = Object.keys(updatedUnSelectedRows);
-
- setCampaignData({
- ...campaignData,
- selectedId: selectedLeadIds,
- unSelectedId: unSelectedLeadIds,
- });
-
- setSelectedRows(updatedSelectedRows);
- setunSelectedRows(updatedUnSelectedRows);
- setMasterCheckboxChecked(!masterCheckboxChecked);
};
+
let campaignId = '';
const fetchLeads = async () => {
@@ -257,19 +326,23 @@ export const Leads = ({
setTotalLeadsCount(leadsCount);
setLeadsData(result.data.leads.edges);
- const initialSelectedRows: { [key: string]: boolean } = {};
+ // const initialSelectedRows: { [key: string]: boolean } = {};
+ // result.data.leads.edges.forEach((leadEdge: any) => {
+ // const lead = leadEdge?.node;
+ // initialSelectedRows[lead.id] = true;
+ // });
+ // setSelectedRows(initialSelectedRows);
result.data.leads.edges.forEach((leadEdge: any) => {
const lead = leadEdge?.node;
- initialSelectedRows[lead.id] = true;
- });
- setSelectedRows(initialSelectedRows);
-
- const currentTime = new Date().toLocaleTimeString([], {
- hour: '2-digit',
- minute: '2-digit',
+ setSelectedID(selectedID.add(lead.id));
+ const leadId=lead.id
+ setCheckbox({
+ ...checkbox,
+ leadId:true
+ })
});
- const currentDate = formatToHumanReadableDate(new Date());
- const querystamp = `${currentDate} ${currentTime}`;
+ console.log(selectedID, 'selectedID');
+ const querystamp = new Date().toISOString();
setCursor(result.data.leads.pageInfo.endCursor);
if (result.data.leads.pageInfo.hasNextPage == true) {
setLoading(true);
@@ -290,16 +363,21 @@ export const Leads = ({
lastCursor: cursor,
},
});
- setSelectedRows((prevSelectedRows) => {
- const newSelectedRows: { [key: string]: boolean } = {
- ...prevSelectedRows,
- };
- result.data.leads.edges.forEach((leadEdge: any) => {
- const lead = leadEdge?.node;
- newSelectedRows[lead.id] = true;
- });
- return newSelectedRows;
+ // setSelectedRows((prevSelectedRows) => {
+ // const newSelectedRows: { [key: string]: boolean } = {
+ // ...prevSelectedRows,
+ // };
+ result.data.leads.edges.forEach((leadEdge: any) => {
+ const lead = leadEdge?.node;
+ setSelectedID(selectedID.add(lead.id));
+ const leadId=lead.id
+ setCheckbox({
+ ...checkbox,
+ leadId:true
+ })
});
+ // return newSelectedRows;
+ // });
setCursor(result.data.leads.pageInfo.endCursor);
const newLeadsData = result.data.leads.edges;
console.log(result.data, 'RESULT DATA');
@@ -310,8 +388,40 @@ export const Leads = ({
};
useEffect(() => {
+ if (unselectedID.size > 0) {
+ setMasterCheckboxChecked(false);
+ } else {
+ setMasterCheckboxChecked(true);
+ }
fetchLeads();
- }, [targetableObject.id, selectedCampaign]);
+ }, [targetableObject.id, selectedCampaign,unselectedID,selectedID]);
+
+ const date = new Date(campaignData.querystamp.toString());
+ console.log(date, 'formated date');
+
+ const onIntersection = async (entries: any) => {
+ const firstEntry = entries[0];
+
+ if (firstEntry.isIntersecting && cursor) {
+ loadMore();
+ }
+ };
+ const handleCheck=(leadId: string | number)=>{
+ return checkbox[leadId];
+ }
+
+ useEffect(() => {
+ const observer = new IntersectionObserver(onIntersection);
+ if (observer && lastLeadRef.current) {
+ observer.observe(lastLeadRef.current);
+ }
+
+ return () => {
+ if (observer) {
+ observer.disconnect();
+ }
+ };
+ }, [leadsData]);
return (
<>
@@ -331,7 +441,7 @@ export const Leads = ({
Leads fetched at:
-
+
@@ -361,7 +471,7 @@ export const Leads = ({
(handleMasterCheckboxChange(event))}
/>
@@ -379,12 +489,18 @@ export const Leads = ({
return (
handleCheckboxChange(lead.id)}
+ onClick={(event) =>
+ {handleCheckboxChange(event, lead.id);
+ }
+ }
+ // checked={() => handleCheckboxChange(event, lead.id)}
>
handleCheckboxChange(lead.id)}
+ checked={checkbox[lead.id]}
+ onChange={() =>
+ handleCheckboxChange(event, lead.id)
+ }
/>
{fields.map(({ name }) => (
@@ -397,19 +513,10 @@ export const Leads = ({
);
})}
-
- End of Table |
-
- {loading && (
-
-
-
+ {cursor && (
+
+ Loading more... |
+
)}
@@ -419,4 +526,4 @@ export const Leads = ({
>
);
-};
\ No newline at end of file
+};
diff --git a/packages/twenty-front/src/pages/campaigns/CampaignForm.tsx b/packages/twenty-front/src/pages/campaigns/CampaignForm.tsx
index 7cf0839d0703..3a0c5cba2027 100644
--- a/packages/twenty-front/src/pages/campaigns/CampaignForm.tsx
+++ b/packages/twenty-front/src/pages/campaigns/CampaignForm.tsx
@@ -1,8 +1,6 @@
import { useEffect, useState } from 'react';
import styled from '@emotion/styled';
-import { Section } from '@react-email/components';
import { Button } from '@/ui/input/button/components/Button';
-import base64 from 'base64-js';
import { H2Title } from '@/ui/display/typography/components/H2Title';
import { useNavigate, useParams } from 'react-router-dom';
import AnimatedPlaceholder from '@/ui/layout/animated-placeholder/components/AnimatedPlaceholder';
@@ -10,7 +8,6 @@ import {
AnimatedPlaceholderErrorContainer,
AnimatedPlaceholderErrorTitle,
} from '@/ui/layout/animated-placeholder/components/ErrorPlaceholderStyled';
-import { addTracingExtensions } from '@sentry/react';
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
import axios from 'axios';
import { AppPath } from '@/types/AppPath';
@@ -19,6 +16,35 @@ import { Select } from '@/ui/input/components/Select';
import { TextArea } from '@/ui/input/components/TextArea';
import { TextInput } from '@/ui/input/components/TextInput';
import { AnimatedPlaceholderEmptyTextContainer } from '@/ui/layout/animated-placeholder/components/EmptyPlaceholderStyled';
+import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile';
+
+
+const StyledDiv = styled.div`
+display: flex;
+flex: 1 0 0;
+flex-direction: column;
+justify-content: start;
+align-items: center;
+overflow: ${() => (useIsMobile() ? 'none' : 'hidden')};
+width: calc(100% + 4px);
+overflow-y: scroll;
+scrollbar-color: ${({ theme }) => theme.border.color.strong};
+scrollbar-width: thin;
+
+ *::-webkit-scrollbar {
+ height: 8px;
+ width: 8px;
+}
+
+*::-webkit-scrollbar-corner {
+ background-color: transparent;
+}
+
+*::-webkit-scrollbar-thumb {
+ background-color: ${({ theme }) => theme.border.color.strong};
+ border-radius: ${({ theme }) => theme.border.radius.sm};
+}
+`;
const StyledInputCard = styled.div`
color: ${({ theme }) => theme.font.color.secondary};
@@ -26,10 +52,9 @@ const StyledInputCard = styled.div`
flex-direction: column;
justify-content: center;
align-items: center;
- width:100%;
-`;
-const StyledDiv = styled.div`
+ width:70%;
`;
+
const StyledSection = styled.div`
margin-bottom: ${({ theme }) => theme.spacing(6)};
`;
@@ -201,6 +226,7 @@ if (loading && errorType === 'formexpired') {
return (
//div id - save id in form
+
Campaign Form
@@ -325,5 +351,6 @@ if (loading && errorType === 'formexpired') {
+
);
};
diff --git a/packages/twenty-front/src/pages/campaigns/CampaignForm2.tsx b/packages/twenty-front/src/pages/campaigns/CampaignForm2.tsx
index 326b615d9d96..302706f4744a 100644
--- a/packages/twenty-front/src/pages/campaigns/CampaignForm2.tsx
+++ b/packages/twenty-front/src/pages/campaigns/CampaignForm2.tsx
@@ -1,33 +1,50 @@
import { useEffect, useState } from 'react';
import { useParams } from 'react-router-dom';
import styled from '@emotion/styled';
-import { Section } from '@react-email/components';
import { Button } from '@/ui/input/button/components/Button';
-
import { H2Title } from '@/ui/display/typography/components/H2Title';
import { Checkbox } from '@/ui/input/components/Checkbox';
import { TextInput } from '@/ui/input/components/TextInput';
+import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile';
+
+const StyledDiv = styled.div`
+display: flex;
+flex: 1 0 0;
+flex-direction: column;
+justify-content: start;
+align-items: center;
+overflow: ${() => (useIsMobile() ? 'none' : 'hidden')};
+width: calc(100% + 4px);
+overflow-y: scroll;
+scrollbar-color: ${({ theme }) => theme.border.color.strong};
+scrollbar-width: thin;
+
+ *::-webkit-scrollbar {
+ height: 8px;
+ width: 8px;
+}
-const StyledCard = styled.div`
- border: 1px solid ${({ theme }) => theme.border.color.medium};
+*::-webkit-scrollbar-corner {
+ background-color: transparent;
+}
+
+*::-webkit-scrollbar-thumb {
+ background-color: ${({ theme }) => theme.border.color.strong};
border-radius: ${({ theme }) => theme.border.radius.sm};
+}
+`;
+
+const StyledInputCard = styled.div`
color: ${({ theme }) => theme.font.color.secondary};
- box-shadow: ${({ theme }) => theme.boxShadow.strong};
display: flex;
flex-direction: column;
justify-content: center;
- background: ${({ theme }) => theme.background.primary};
- height: 95%;
- width: 70%;
- margin: auto;
align-items: center;
- margin-bottom: ${({ theme }) => theme.spacing(2)};
- overflow-y: scroll;
+ width:70%;
`;
-const StyledFormTitle = styled.h3`
- color: ${({ theme }) => theme.font.color.primary};
- font-weight: ${({ theme }) => theme.font.weight.semiBold};
+const StyledSection = styled.div`
+ margin-bottom: ${({ theme }) => theme.spacing(6)};
`;
const StyledTitleContainer = styled.div`
@@ -42,22 +59,10 @@ const StyledTitle = styled.h2`
font-weight: ${({ theme }) => theme.font.weight.semiBold};
padding: ${({ theme }) => theme.spacing(6)};
`;
-const StyledInputCard = styled.div`
- color: ${({ theme }) => theme.font.color.secondary};
- display: flex;
- flex-direction: column;
- justify-content: center;
- height: 100%;
- justify-content: space-between;
- width: 70%;
- align-items: center;
- overflow-y: scroll;
-`;
+
const StyledCheckboxInput = styled.div`
- display: flex;
- align-items: center;
- margin-top: ${({ theme }) => theme.spacing(1)};
+ margin-top: ${({ theme }) => theme.spacing(4)};
`;
const StyledAreaLabel = styled.span`
@@ -71,6 +76,8 @@ const StyledButton = styled.span`
display: flex;
justify-content: space-between;
width: 100%;
+ margin-bottom: ${({ theme }) => theme.spacing(6)};
+ margin-top: ${({ theme }) => theme.spacing(6)};
`;
const StyledCheckboxLabel = styled.span`
@@ -84,7 +91,6 @@ const StyledComboInputContainer = styled.div`
margin-left: ${({ theme }) => theme.spacing(4)};
}
`;
-
export const CampaignForm2 = () => {
const [firstName, setFirstName] = useState('');
const [lastName, setLastName] = useState('');
@@ -152,13 +158,14 @@ export const CampaignForm2 = () => {
};
return (
- <>
-
+
+
Health Screening Form
-
+
+
{
fullWidth
onChange={(e) => setFirstName(e)}
/>
-
-
+
+
+
+
{
fullWidth
onChange={(e) => setLastName(e)}
/>
-
-
+
+
+
+
{
fullWidth
onChange={(e) => setEmail(e)}
/>
-
-
+
+
+
+
{
fullWidth
onChange={(e) => setContact(e)}
/>
-
+
+
+
-
+
{
fullWidth
onChange={(e) => setAge(e)}
/>
-
-
-
+
+
{
fullWidth
onChange={(e) => setBloodType(e)}
/>
-
-
+
+
-
-
-
- handleSymptomCheckboxChange('fever')}
- />
- Fever
-
-
- handleSymptomCheckboxChange('cough')}
- />
- Cough
-
-
- handleSymptomCheckboxChange('fatigue')}
- />
- Fatigue
-
-
- handleSymptomCheckboxChange('headache')}
- />
- Headache
-
-
+
+
+ Fever
+
+ Cough
+
+ Fatigue
+
+ Headache
+
+
-
-
-
-
-
- handleTravelHistoryCheckboxChange('withinCountry')
- }
- />
- Within Country
-
-
-
- handleTravelHistoryCheckboxChange('international')
- }
- />
- International
-
-
+
+
+
+
+ Within Country
+
+ International
+
+
-
{
/>
Yes, I have
+
+
-
- >
+
+
);
};
\ No newline at end of file
diff --git a/packages/twenty-front/src/pages/campaigns/CampaignForm3.tsx b/packages/twenty-front/src/pages/campaigns/CampaignForm3.tsx
index 7e0ba3ae4993..d1ba308cbc40 100644
--- a/packages/twenty-front/src/pages/campaigns/CampaignForm3.tsx
+++ b/packages/twenty-front/src/pages/campaigns/CampaignForm3.tsx
@@ -7,27 +7,43 @@ import { Button } from '@/ui/input/button/components/Button';
import { H2Title } from '@/ui/display/typography/components/H2Title';
import { Checkbox, CheckboxVariant, CheckboxSize, CheckboxShape } from '@/ui/input/components/Checkbox';
import { TextInput } from '@/ui/input/components/TextInput';
+import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile';
-const StyledCard = styled.div`
- border: 1px solid ${({ theme }) => theme.border.color.medium};
- border-radius: ${({ theme }) => theme.border.radius.sm};
- color: ${({ theme }) => theme.font.color.secondary};
- box-shadow: ${({ theme }) => theme.boxShadow.strong};
- display: flex;
- flex-direction: column;
- justify-content: center;
- background: ${({ theme }) => theme.background.primary};
- height: 95%;
- width: 70%;
- margin: auto;
- align-items: center;
- margin-bottom: ${({ theme }) => theme.spacing(2)}
- overflow-y: scroll;
+
+const StyledDiv = styled.div`
+display: flex;
+flex: 1 0 0;
+flex-direction: column;
+justify-content: start;
+align-items: center;
+overflow: ${() => (useIsMobile() ? 'none' : 'hidden')};
+width: calc(100% + 4px);
+overflow-y: scroll;
+scrollbar-color: ${({ theme }) => theme.border.color.strong};
+scrollbar-width: thin;
+
+ *::-webkit-scrollbar {
+ height: 8px;
+ width: 8px;
+}
+
+*::-webkit-scrollbar-corner {
+ background-color: transparent;
+}
+
+*::-webkit-scrollbar-thumb {
+ background-color: ${({ theme }) => theme.border.color.strong};
+ border-radius: ${({ theme }) => theme.border.radius.sm};
+}
`;
-const StyledFormTitle = styled.h3`
- color: ${({ theme }) => theme.font.color.primary};
- font-weight: ${({ theme }) => theme.font.weight.semiBold};
+const StyledInputCard = styled.div`
+ color: ${({ theme }) => theme.font.color.secondary};
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ width:70%;
`;
const StyledTitleContainer = styled.div`
@@ -42,36 +58,11 @@ const StyledTitle = styled.h2`
font-weight: ${({ theme }) => theme.font.weight.semiBold};
padding: ${({ theme }) => theme.spacing(6)};
`;
-const StyledInputCard = styled.div`
- color: ${({ theme }) => theme.font.color.secondary};
- display: flex;
- flex-direction: column;
- justify-content: center;
- height: 1005%;
- justify-content: space-between;
- width: 70%;
- align-items: center;
-`;
const StyledCheckboxInput = styled.div`
margin-top: ${({ theme }) => theme.spacing(4)};
`;
-interface PreexistingConditions {
- diabetes: boolean;
- asthma: boolean;
- seizures: boolean;
- bloodpressure: boolean;
-}
-
-interface PreexistingDiseases {
- cardiovascular: boolean;
- respiratory: boolean;
- genitourinary: boolean;
- cns: boolean;
- other: boolean;
-}
-
const StyledAreaLabel = styled.span`
align-content: flex-start;
display: flex;
@@ -97,6 +88,26 @@ const StyledComboInputContainer = styled.div`
}
`;
+const StyledSection = styled.div`
+ margin-bottom: ${({ theme }) => theme.spacing(6)};
+`;
+
+interface PreexistingConditions {
+ diabetes: boolean;
+ asthma: boolean;
+ seizures: boolean;
+ bloodpressure: boolean;
+}
+
+interface PreexistingDiseases {
+ cardiovascular: boolean;
+ respiratory: boolean;
+ genitourinary: boolean;
+ cns: boolean;
+ other: boolean;
+}
+
+
export const CampaignForm3 = () => {
const [firstName, setFirstName] = useState('');
const [lastName, setLastName] = useState('');
@@ -173,13 +184,13 @@ export const CampaignForm3 = () => {
};
return (
- <>
-
+
+
Medical Fitness Form
-
-
+
+
{
fullWidth
onChange={(e) => setFirstName(e)}
/>
-
-
+
+
+
+
{
fullWidth
onChange={(e) => setLastName(e)}
/>
-
-
+
+
+
+
{
fullWidth
onChange={(e) => setEmail(e)}
/>
-
-
+
+
+
+
{
fullWidth
onChange={(e) => setContact(e)}
/>
-
-
-
+
+
-
+
{
fullWidth
onChange={(e) => setHeight(e)}
/>
-
+
-
+
{
fullWidth
onChange={(e) => setWeight(e)}
/>
-
+
-
-
- handleConditionCheckboxChange('diabetes')}
- />
- Diabetes
-
-
- handleConditionCheckboxChange('asthma')}
- />
- Asthma
-
-
- handleConditionCheckboxChange('seizures')}
- />
- Seizures
-
-
- handleConditionCheckboxChange('bloodpressure')}
- />
- BloodPressure
-
-
+
+
+
+
+ Diabetes
+
+ Asthma
+
+ Seizures
+
+ BloodPressure
+
+
+
-
-
-
- handleDiseaseCheckboxChange('cardiovascular')}
- />
- Cardiovascular
-
-
- handleDiseaseCheckboxChange('respiratory')}
- />
- Respiratory
-
-
- handleDiseaseCheckboxChange('genitourinary')}
- />
- Genitourinary
-
-
- handleDiseaseCheckboxChange('cns')}
- />
-
- CNS (Central Nervous System)
-
-
-
- handleDiseaseCheckboxChange('other')}
- />
- Other
-
-
+
+
+
-
-
+
+
+ Hypertension
+
+
+ Arthritis
+
+
+ Genitourinary
+
+
+ Diabetes
+
+ Other
+
+
+
+
+
-
-
-
-
- I agree to the terms and conditions.
-
-
+
+
+
+ I agree to the terms and conditions.
+
+
+
-
-
- >
+
+
);
};
diff --git a/packages/twenty-front/src/pages/campaigns/Form1.tsx b/packages/twenty-front/src/pages/campaigns/Form1.tsx
index c9a87e0c7e01..cf7e62973c9d 100644
--- a/packages/twenty-front/src/pages/campaigns/Form1.tsx
+++ b/packages/twenty-front/src/pages/campaigns/Form1.tsx
@@ -112,6 +112,7 @@ export const Form1 = () => {
name="firstName"
required
fullWidth
+ disabled
/>
@@ -122,6 +123,7 @@ export const Form1 = () => {
name="lastName"
required
fullWidth
+ disabled
/>
@@ -132,6 +134,7 @@ export const Form1 = () => {
name="email"
required
fullWidth
+ disabled
/>
@@ -145,6 +148,7 @@ export const Form1 = () => {
name="contact"
required
fullWidth
+ disabled
/>
@@ -156,6 +160,7 @@ export const Form1 = () => {
name="age"
required
fullWidth
+ disabled
/>
@@ -167,6 +172,7 @@ export const Form1 = () => {
name="bloodType"
required
fullWidth
+ disabled
/>
diff --git a/packages/twenty-front/src/pages/campaigns/Form2.tsx b/packages/twenty-front/src/pages/campaigns/Form2.tsx
index 3c11a44208af..f8ef2a2a2385 100644
--- a/packages/twenty-front/src/pages/campaigns/Form2.tsx
+++ b/packages/twenty-front/src/pages/campaigns/Form2.tsx
@@ -111,6 +111,7 @@ export const Form2 = () => {
name="firstName"
required
fullWidth
+ disabled
/>
@@ -121,6 +122,7 @@ export const Form2 = () => {
name="lastName"
required
fullWidth
+ disabled
/>
@@ -131,6 +133,7 @@ export const Form2 = () => {
name="email"
required
fullWidth
+ disabled
/>
@@ -145,6 +148,7 @@ export const Form2 = () => {
name="contact"
required
fullWidth
+ disabled
/>
@@ -156,6 +160,7 @@ export const Form2 = () => {
value={'comments'}
placeholder={'State the reason for the apppointment'}
minRows={5}
+ disabled
/>
@@ -169,6 +174,7 @@ export const Form2 = () => {
dropdownId={'appointmentType'}
value={'apptType'}
options={apptTypeOptions}
+ disabled
/>
@@ -181,6 +187,7 @@ export const Form2 = () => {
dropdownId={'appointmentLocation'}
value={'location'}
options={locationOptions}
+ disabled
/>
diff --git a/packages/twenty-front/src/pages/campaigns/Form3.tsx b/packages/twenty-front/src/pages/campaigns/Form3.tsx
index ad52b167b136..3aae311c8981 100644
--- a/packages/twenty-front/src/pages/campaigns/Form3.tsx
+++ b/packages/twenty-front/src/pages/campaigns/Form3.tsx
@@ -1,9 +1,13 @@
import { useState } from 'react';
import styled from '@emotion/styled';
-
import { H2Title } from '@/ui/display/typography/components/H2Title';
-import { Checkbox, CheckboxVariant, CheckboxSize, CheckboxShape } from '@/ui/input/components/Checkbox';
+import {
+ Checkbox,
+ CheckboxVariant,
+ CheckboxSize,
+ CheckboxShape,
+} from '@/ui/input/components/Checkbox';
import { TextInput } from '@/ui/input/components/TextInput';
const StyledDiv = styled.div``;
@@ -38,7 +42,6 @@ const StyledTitle = styled.h2`
padding: ${({ theme }) => theme.spacing(6)};
`;
-
const StyledInputCard = styled.div`
color: ${({ theme }) => theme.font.color.secondary};
display: flex;
@@ -50,7 +53,6 @@ const StyledInputCard = styled.div`
align-items: center;
`;
-
const StyledAreaLabel = styled.span`
align-content: flex-start;
display: flex;
@@ -100,11 +102,7 @@ interface PreexistingDiseases {
other: boolean;
}
-
-
-
export const Form3 = () => {
-
const [preexistingConditions, setPreexistingConditions] =
useState({
diabetes: false,
@@ -122,91 +120,92 @@ export const Form3 = () => {
other: false,
});
-
return (
-
Medical Fitness Form
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
- Male
-
+
+
+
- Female
-
+
+
+
- Others
-
-
-
+
+
+
+
+
+
+
+
+
+
+ Male
+
+ Female
+
+ Others
+
+
+
{
/>
@@ -227,93 +227,73 @@ export const Form3 = () => {
/>
-
-
-
-
- Diabetes
-
- Asthma
-
- Seizures
-
- BloodPressure
-
-
+
+
+
+
+ Diabetes
+
+ Asthma
+
+ Seizures
+
+ BloodPressure
+
+
-
-
-
-
-
-
- Hypertension
-
-
- Arthritis
-
-
- Genitourinary
-
-
-
- Diabetes
-
-
- Other
-
-
+
+
+
+
+
+ Hypertension
+
+
+ Arthritis
+
+
+ Genitourinary
+
+
+ Diabetes
+
+ Other
+
+
-
-
-
- I agree to the terms and conditions.
-
-
+
+
+
+ I agree to the terms and conditions.
+
+
diff --git a/packages/twenty-front/src/pages/object-record/RecordShowPage.tsx b/packages/twenty-front/src/pages/object-record/RecordShowPage.tsx
index 96e49471a61f..0e0445eaa909 100644
--- a/packages/twenty-front/src/pages/object-record/RecordShowPage.tsx
+++ b/packages/twenty-front/src/pages/object-record/RecordShowPage.tsx
@@ -2,7 +2,6 @@ import { useEffect, useState } from 'react';
import { useNavigate, useParams } from 'react-router-dom';
import { useSetRecoilState } from 'recoil';
import { useIcons } from 'twenty-ui';
-
import { useFavorites } from '@/favorites/hooks/useFavorites';
import { useLabelIdentifierFieldMetadataItem } from '@/object-metadata/hooks/useLabelIdentifierFieldMetadataItem';
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
@@ -25,7 +24,6 @@ import { ADD_TRIGGER_CAMPAIGN_RECORD } from '@/users/graphql/queries/addTriggerC
import { GET_CAMPAIGN_LISTS } from '@/users/graphql/queries/getCampaignList';
import { useLazyQuery, useMutation } from '@apollo/client';
import { useCampaign } from '~/pages/campaigns/CampaignUseContext';
-import { ConfirmationModal } from '@/ui/layout/modal/components/ConfirmationModal';
import { RunCampaignButton } from '@/ui/layout/page/RunCampaignButton';
import { useDialogManager } from '@/ui/feedback/dialog-manager/hooks/useDialogManager';
@@ -121,7 +119,6 @@ const [addTriggerCampaignRecord] = useMutation(ADD_TRIGGER_CAMPAIGN_RECORD);
const { enqueueSnackBar } = useSnackBar();
const navigate = useNavigate();
const { enqueueDialog } = useDialogManager();
-const [isConfirmModalOpen, setIsConfirmModalOpen] = useState(false);
const handleConfirmRun = async () => {
try {
@@ -137,10 +134,6 @@ const handleConfirmRun = async () => {
},
});
- console.log(
- 'Response from ADD_TRIGGER_CAMPAIGN_RECORD:',
- addTriggerData.createCampaignTrigger.id,
- );
let requestBody: {
campaignId: string;
@@ -174,14 +167,14 @@ const handleConfirmRun = async () => {
const data = await response.json();
console.log('Response from the API:', data);
- enqueueSnackBar('Campaign added successfully', {
+ enqueueSnackBar('Campaign running successfully', {
variant: 'success',
});
- navigate('/objects/campaignTriggers');
- window.location.reload();
+
+ navigate(`/object/campaignTrigger/${addTriggerData?.createCampaignTrigger?.id}`);
} catch (error) {
console.error('Error in running campaign:', error);
- enqueueSnackBar('Campaign added successfully', {
+ enqueueSnackBar('Failed to run Campaign', {
variant: 'error',
});
}
From 6bbd5b9bdf38235a3a50e595fff23915974933ed Mon Sep 17 00:00:00 2001
From: Sanjana
Date: Tue, 7 May 2024 12:52:19 +0530
Subject: [PATCH 028/122] Disabled Checkbox in forms and updated select all in
leads
---
.../activities/Leads/components/Leads.tsx | 170 +++++------------
.../formTemplate/components/formTemplate.tsx | 3 -
.../components/messageTemplate.tsx | 3 -
.../components/ObjectMetadataNavItems.tsx | 16 +-
.../modules/ui/input/components/Checkbox.tsx | 5 +
.../src/pages/Segment/Segment.tsx | 179 ++++++++++++++++--
.../src/pages/campaigns/Form1.tsx | 14 +-
.../src/pages/campaigns/Form2.tsx | 7 +-
.../src/pages/campaigns/Form3.tsx | 46 ++---
9 files changed, 251 insertions(+), 192 deletions(-)
diff --git a/packages/twenty-front/src/modules/activities/Leads/components/Leads.tsx b/packages/twenty-front/src/modules/activities/Leads/components/Leads.tsx
index 52c5e143c7c3..81f1db630c45 100644
--- a/packages/twenty-front/src/modules/activities/Leads/components/Leads.tsx
+++ b/packages/twenty-front/src/modules/activities/Leads/components/Leads.tsx
@@ -8,7 +8,6 @@ import { FILTER_LEADS } from '@/users/graphql/queries/filterLeads';
import { Checkbox } from '@/ui/input/components/Checkbox';
import { capitalize } from '~/utils/string/capitalize';
import { useCampaign } from '~/pages/campaigns/CampaignUseContext';
-import { formatToHumanReadableDate } from '~/utils';
import { EllipsisDisplay } from '@/ui/field/display/components/EllipsisDisplay';
import { NumberDisplay } from '@/ui/field/display/components/NumberDisplay';
import {
@@ -21,15 +20,9 @@ import {
IconSpeakerphone,
IconTextCaption,
IconCalendar,
- IconNumbers,
- IconLoader,
} from '@tabler/icons-react';
import { IconButton } from '@/ui/input/button/components/IconButton';
-import { TextDisplay } from '@/ui/field/display/components/TextDisplay';
-import { Button } from '@/ui/input/button/components/Button';
-import { formatNumber } from '~/utils/format/number';
import { DateTimeDisplay } from '@/ui/field/display/components/DateTimeDisplay';
-import { boolean } from 'zod';
const StyledInputCard = styled.div`
align-items: flex-start;
@@ -160,7 +153,7 @@ export const Leads = ({
const [isChecked, setIsChecked] = useState(true);
const [checkbox,setCheckbox]=useState({});
const { campaignData, setCampaignData } = useCampaign();
-
+ const allLeadId={}
let [selectedCampaign, { data: selectedCampaignData }] = useLazyQuery(
GET_CAMPAIGN_LISTS,
{
@@ -177,67 +170,6 @@ export const Leads = ({
fetchPolicy: 'network-only',
});
- // const handleCheckboxChange = (leadId: string) => {
- // const updatedSelectedRows = { ...selectedRows };
- // updatedSelectedRows[leadId] = !updatedSelectedRows[leadId];
-
- // const updatedUnSelectedRows = { ...unSelectedRows };
- // if (!updatedSelectedRows[leadId]) {
- // updatedUnSelectedRows[leadId] = true;
- // delete updatedSelectedRows[leadId];
- // } else {
- // delete updatedUnSelectedRows[leadId];
- // }
-
- // const selectedLeadIds = Object.keys(updatedSelectedRows);
- // const unSelectedLeadIds = Object.keys(updatedUnSelectedRows);
-
- // setCampaignData({
- // ...campaignData,
- // selectedId: selectedLeadIds,
- // unSelectedId: unSelectedLeadIds,
- // });
-
- // setSelectedRows(updatedSelectedRows);
- // setunSelectedRows(updatedUnSelectedRows);
- // };
-
- // const handleMasterCheckboxChange = () => {
- // const updatedSelectedRows = { ...selectedRows };
- // const updatedUnSelectedRows = { ...unSelectedRows };
- // let allSelected = true;
-
- // leadsData?.leads?.edges.forEach((leadEdge: any) => {
- // const lead = leadEdge?.node;
- // if (!masterCheckboxChecked) {
- // updatedSelectedRows[lead.id] = true;
- // delete updatedUnSelectedRows[lead.id];
- // } else {
- // // Check if the lead is currently unselected
- // if (!updatedSelectedRows[lead.id]) allSelected = false;
- // // Update both selected and unselected rows
- // updatedSelectedRows[lead.id] = !updatedSelectedRows[lead.id];
- // updatedUnSelectedRows[lead.id] = !updatedUnSelectedRows[lead.id];
- // }
- // if(masterCheckboxChecked){
- // allSelected = true;
- // }
- // });
-
- // const selectedLeadIds = Object.keys(updatedSelectedRows);
- // const unSelectedLeadIds = Object.keys(updatedUnSelectedRows);
-
- // setCampaignData({
- // ...campaignData,
- // selectedId: selectedLeadIds,
- // unSelectedId: unSelectedLeadIds,
- // });
-
- // // If all were selected, now deselect all, else select all
- // setSelectedRows(allSelected ? {} : updatedSelectedRows);
- // setunSelectedRows(allSelected ? {} : updatedUnSelectedRows);
- // setMasterCheckboxChecked(!masterCheckboxChecked);
- // };
const handleCheckboxChange = (event: any, leadId: string): boolean => {
const { checked } = event.target;
@@ -245,49 +177,57 @@ export const Leads = ({
setSelectedID(selectedID.add(leadId));
unselectedID.delete(leadId);
setUnselectedID(unselectedID);
+ // allLeadId[leadId]=true
setCheckbox({
...checkbox,
- leadId:true
+ [leadId]:true,
})
return true;
} else {
selectedID.delete(leadId);
setSelectedID(selectedID);
setUnselectedID(unselectedID.add(leadId));
+ // allLeadId[leadId]=false
setCheckbox({
...checkbox,
- leadId:false
+ [leadId]:false
})
}
+
setIsChecked(checked)
- console.log(selectedID)
+
return false;
};
const handleMasterCheckboxChange = (event: any) => {
const { checked } = event.target;
if (checked) {
+
for (const id of unselectedID.keys()) {
setSelectedID(selectedID.add(id));
unselectedID.delete(id);
setUnselectedID(unselectedID);
- setCheckbox({
- ...checkbox,
- leadId:true
- })
}
+ for (const id of selectedID .keys()) {
+ allLeadId[id]=true
+ }
+
} else {
for (const id of selectedID.keys()) {
selectedID.delete(id);
setSelectedID(selectedID);
setUnselectedID(unselectedID.add(id));
- setCheckbox({
- ...checkbox,
- leadId:false
- })
}
+ for (const id of unselectedID.keys()) {
+ allLeadId[id]=false
+ }
+
}
- console.log(selectedID, 'selectedID');
+
+ setCheckbox({
+ ...checkbox,
+ ...allLeadId
+ })
};
@@ -303,7 +243,6 @@ export const Leads = ({
});
campaignId = data.data.campaignTrigger.campaignId;
- console.log(campaignId, 'campaignId');
} else if (targetableObject.targetObjectNameSingular === 'campaign') {
campaignId = targetableObject.id;
}
@@ -325,23 +264,20 @@ export const Leads = ({
const leadsCount = result.data?.leads?.totalCount || 0;
setTotalLeadsCount(leadsCount);
setLeadsData(result.data.leads.edges);
-
- // const initialSelectedRows: { [key: string]: boolean } = {};
- // result.data.leads.edges.forEach((leadEdge: any) => {
- // const lead = leadEdge?.node;
- // initialSelectedRows[lead.id] = true;
- // });
- // setSelectedRows(initialSelectedRows);
result.data.leads.edges.forEach((leadEdge: any) => {
const lead = leadEdge?.node;
setSelectedID(selectedID.add(lead.id));
- const leadId=lead.id
- setCheckbox({
- ...checkbox,
- leadId:true
- })
+ let leadId=lead.id
});
- console.log(selectedID, 'selectedID');
+
+ for (const id of selectedID.keys()) {
+ allLeadId[id]=true
+ }
+ setCheckbox({
+ ...checkbox,
+ ...allLeadId
+ })
+
const querystamp = new Date().toISOString();
setCursor(result.data.leads.pageInfo.endCursor);
if (result.data.leads.pageInfo.hasNextPage == true) {
@@ -363,41 +299,34 @@ export const Leads = ({
lastCursor: cursor,
},
});
- // setSelectedRows((prevSelectedRows) => {
- // const newSelectedRows: { [key: string]: boolean } = {
- // ...prevSelectedRows,
- // };
result.data.leads.edges.forEach((leadEdge: any) => {
const lead = leadEdge?.node;
setSelectedID(selectedID.add(lead.id));
const leadId=lead.id
- setCheckbox({
- ...checkbox,
- leadId:true
- })
+ allLeadId[leadId]=true
+
});
- // return newSelectedRows;
- // });
+ setCheckbox({
+ ...checkbox,
+ ...allLeadId
+ })
+
+
setCursor(result.data.leads.pageInfo.endCursor);
const newLeadsData = result.data.leads.edges;
- console.log(result.data, 'RESULT DATA');
setLeadsData([...leadsData, ...newLeadsData]);
}
- console.log(leadsData, 'new Leads Data');
};
+
useEffect(() => {
- if (unselectedID.size > 0) {
- setMasterCheckboxChecked(false);
- } else {
- setMasterCheckboxChecked(true);
- }
+
+
fetchLeads();
- }, [targetableObject.id, selectedCampaign,unselectedID,selectedID]);
+ }, [targetableObject.id, selectedCampaign,]);
const date = new Date(campaignData.querystamp.toString());
- console.log(date, 'formated date');
const onIntersection = async (entries: any) => {
const firstEntry = entries[0];
@@ -454,14 +383,14 @@ export const Leads = ({
Selected Leads:
-
+
Unselected Leads:
-
+
@@ -470,7 +399,7 @@ export const Leads = ({
(handleMasterCheckboxChange(event))}
/>
@@ -489,11 +418,6 @@ export const Leads = ({
return (
- {handleCheckboxChange(event, lead.id);
- }
- }
- // checked={() => handleCheckboxChange(event, lead.id)}
>
>
);
-};
+};
\ No newline at end of file
diff --git a/packages/twenty-front/src/modules/activities/formTemplate/components/formTemplate.tsx b/packages/twenty-front/src/modules/activities/formTemplate/components/formTemplate.tsx
index 3fc06648327f..057982557c9a 100644
--- a/packages/twenty-front/src/modules/activities/formTemplate/components/formTemplate.tsx
+++ b/packages/twenty-front/src/modules/activities/formTemplate/components/formTemplate.tsx
@@ -35,7 +35,6 @@ export const FormTemplate = ({
}: {
targetableObject: ActivityTargetableObject;
}) => {
- console.log(targetableObject, 'targetableobject');
let [selectedCampaign, { data: selectedCampaignData }] =
useLazyQuery(GET_CAMPAIGN_LISTS);
let [selectedCampaignTrigger, { data: selectedCampaignTriggerData }] =
@@ -62,7 +61,6 @@ export const FormTemplate = ({
});
campaignId = data.data.campaignTrigger.campaignId;
- console.log(campaignId, 'campaignId');
} else if (targetableObject.targetObjectNameSingular === 'campaign') {
campaignId = targetableObject.id;
}
@@ -87,7 +85,6 @@ export const FormTemplate = ({
status:
data?.data?.campaigns?.edges[0]?.node?.formTemplate?.status || '',
});
- console.log(formTemplateName, 'formTemplateName');
} catch (error) {
console.error('Error fetching form template:', error);
}
diff --git a/packages/twenty-front/src/modules/activities/messageTemplate/components/messageTemplate.tsx b/packages/twenty-front/src/modules/activities/messageTemplate/components/messageTemplate.tsx
index 693f5f9a8b5b..6432ea3793c5 100644
--- a/packages/twenty-front/src/modules/activities/messageTemplate/components/messageTemplate.tsx
+++ b/packages/twenty-front/src/modules/activities/messageTemplate/components/messageTemplate.tsx
@@ -61,7 +61,6 @@ export const MessageTemplate = ({
});
campaignId = data.data.campaignTrigger.campaignId;
- console.log(campaignId, 'campaignId');
} else if (targetableObject.targetObjectNameSingular === 'campaign') {
campaignId = targetableObject.id;
}
@@ -75,7 +74,6 @@ export const MessageTemplate = ({
setMessageTemplate([
data?.data?.campaigns?.edges[0]?.node?.messageTemplate,
]);
- console.log(messageTemplate, 'Message Template Details');
} catch (error) {
console.error('Error fetching message template:', error);
}
@@ -85,7 +83,6 @@ export const MessageTemplate = ({
messageTeamplateDetails();
}, [targetableObject.id, selectedCampaign]);
- console.log(messageTemplate[0]?.name, 'messageTemplate?.name');
return (
<>
diff --git a/packages/twenty-front/src/modules/object-metadata/components/ObjectMetadataNavItems.tsx b/packages/twenty-front/src/modules/object-metadata/components/ObjectMetadataNavItems.tsx
index 69a68c2fb422..fb9b81bcd347 100644
--- a/packages/twenty-front/src/modules/object-metadata/components/ObjectMetadataNavItems.tsx
+++ b/packages/twenty-front/src/modules/object-metadata/components/ObjectMetadataNavItems.tsx
@@ -57,7 +57,8 @@ export const ObjectMetadataNavItems = () => {
}`;
return (
-
+ {objectMetadataItem.namePlural!=='campaignTriggers' && {
onClick={() => {
navigate(navigationPath);
}}
- />
+ />}
+ {objectMetadataItem.namePlural==='campaignTriggers' && {
+ navigate(navigationPath);
+ }}
+ />}
+ >
);
})}
>
diff --git a/packages/twenty-front/src/modules/ui/input/components/Checkbox.tsx b/packages/twenty-front/src/modules/ui/input/components/Checkbox.tsx
index f3d6df936988..ae2f107c3d7e 100644
--- a/packages/twenty-front/src/modules/ui/input/components/Checkbox.tsx
+++ b/packages/twenty-front/src/modules/ui/input/components/Checkbox.tsx
@@ -28,6 +28,7 @@ type CheckboxProps = {
size?: CheckboxSize;
shape?: CheckboxShape;
className?: string;
+ disabled?: boolean;
};
const StyledInputContainer = styled.div`
@@ -107,6 +108,7 @@ const StyledInput = styled.input`
top: var(--padding);
width: var(--size);
}
+
`;
export const Checkbox = ({
@@ -118,6 +120,7 @@ export const Checkbox = ({
size = CheckboxSize.Small,
shape = CheckboxShape.Squared,
className,
+ disabled,
}: CheckboxProps) => {
const [isInternalChecked, setIsInternalChecked] =
React.useState(false);
@@ -149,7 +152,9 @@ export const Checkbox = ({
shape={shape}
isChecked={isInternalChecked}
onChange={handleChange}
+ disabled={disabled}
/>
+