Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature:- Create Campaign Page #7

Open
wants to merge 7 commits into
base: feature/sender-identity-page
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1,375 changes: 1,375 additions & 0 deletions package-lock.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
"dependencies": {
"@headlessui/react": "^1.7.15",
"@heroicons/react": "^2.0.18",
"@nextui-org/react": "^1.0.0-beta.13",
"@types/node": "20.3.1",
"@types/react": "18.2.12",
"@types/react-dom": "18.2.5",
Expand Down
11 changes: 11 additions & 0 deletions src/apis/campaign.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,18 @@
import api from '@/utils/api';
import { toast } from 'react-toastify';

export const getCampaigns = async () => {
const response = await api.get('/api/campaign');
const data = await response.data;
return data;
};

export const createCampaign = async (data: any) => {
try {
const response = await api.post('/api/campaign', data);
const responseData = await response.data;
return responseData;
} catch (error: any) {
toast.error(error.response.data.message);
}
};
93 changes: 93 additions & 0 deletions src/app/(auth)/campaign/create/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
'use client';

import {
AtSymbolIcon,
InformationCircleIcon,
} from '@heroicons/react/24/outline';
import { useFormik } from 'formik';
import { createCampaign } from '@/apis/campaign';
import { getSenderIdentities } from '@/apis/SenderIdentity';
import { getTags } from '@/apis/tag';
import { Tooltip, Grid } from '@nextui-org/react';
import { useEffect, useState } from 'react';
import { toast } from 'react-toastify';
import { useRouter } from 'next/navigation';
import Campaign from '@/components/Forms/Campaign';
import { campaignValidation } from '@/validations/campaign';

const Page = () => {
const router = useRouter();
const [tags, setTags] = useState('');
const [senderIdentity, setSenderIdentity] = useState('');
const onSubmit = async (values: any) => {
try {
await createCampaign(values);
toast.success('Sender Identity created successfully');
router.back();
} catch (error: any) {
toast.error(error.response.data.message);
}
};

useEffect(() => {
const fetchTags = async () => {
setTags(await getTags());
};
const fetchSenderIdentities = async () => {
setSenderIdentity(await getSenderIdentities());
};
fetchTags();
fetchSenderIdentities();
}, []);

const formik = useFormik({
initialValues: {
email_subject: '',
sender_identity_id: '',
subscription_list_id: '',
email_body: 'Email Body', // We need ot add this field in the form when we are implementing the wisywig editor
},
onSubmit: onSubmit,
validationSchema: campaignValidation,
});

return (
<div className="flex flex-col">
<div>
<h2 className="mb-7 flex">
<AtSymbolIcon className="h-9 w-9" />
<span className="ml-1 text-3xl">Create Campaign</span>
<Grid xs={3} justify="flex-start">
<Tooltip
color="invert"
content={
<>
Campaigns only go to the valid and subscribed users in the
selected list. <br /> <br />
Use following snippets to create dynamic email template:{' '}
<br /> <br />
<ul>
<li>User Name: |*USERNAME*|</li>
</ul>{' '}
<br />
For example: Dear |*USERNAME*|
</>
}
placement="rightStart"
>
<InformationCircleIcon className="h-9 w-9" />
</Tooltip>
</Grid>
</h2>
</div>
<Campaign
formik={formik}
senderidentityOptions={senderIdentity.data || []}
tagsOptions={tags.data || []}
btnName="Create Campaign"
/>
</div>
);
};

export default Page;
11 changes: 6 additions & 5 deletions src/app/(auth)/campaign/page.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
'use client';

import { getCampaigns } from '@/apis/campaign';
import Button from '@/components/Button';
import Table from '@/components/Table';
import { Campaign, CampaignResource, TableData } from '@/utils/types';
import { EnvelopeIcon } from '@heroicons/react/24/outline';
import { PencilSquareIcon, TrashIcon } from '@heroicons/react/24/solid';
import moment from 'moment';
import { useEffect, useState } from 'react';
// import Input from '@/components/Input';
import Link from 'next/link';

const Page = () => {
const [campaigns, setCampaigns] = useState<CampaignResource | undefined>(
Expand Down Expand Up @@ -41,7 +40,6 @@ const Page = () => {
</div>
</>,
<>
{console.log(campaign, '-->campaign')}
{/* <div>{campaign.sender_identity.name}</div> */}
<div className="text-gray-500">
{/* {campaign.sender_identity.email} */}
Expand Down Expand Up @@ -79,9 +77,12 @@ const Page = () => {
)}
</h2>
<div>
<Button onClick={() => console.log('new campaign')}>
<Link
className="flex rounded-lg bg-indigo-700 px-4 py-2 text-white hover:bg-indigo-800"
href="/campaign/create"
>
New Campaign
</Button>
</Link>
</div>
</div>
<Table data={tableData} />
Expand Down
57 changes: 57 additions & 0 deletions src/components/Forms/Campaign.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import Input from '@/components/Input';
import Button from '@/components/Button';
import Select from '@/components/Select';

const Subscriber = ({
formik,
senderidentityOptions,
tagsOptions,
btnName,
}: {
formik: any;
senderidentityOptions: any;
tagsOptions: any;
btnName: string;
}) => {
return (
<>
<form onSubmit={formik.handleSubmit}>
<div className="grid grid-cols-2 gap-2">
<Select
options={senderidentityOptions}
value={formik.values.sender_identity_id}
onChange={formik.handleChange}
name="sender_identity_id"
label="Sender Identity"
required={formik.errors.sender_identity_id}
/>
<Select
options={tagsOptions}
value={formik.values.subscription_list_id}
onChange={formik.handleChange}
name="subscription_list_id"
label="Select List"
required={formik.errors.subscription_list_id}
/>
</div>
<Input
type="text"
name="email_subject"
label="Subject"
placeholder="Enter Subject"
value={formik.values.email_subject}
onChange={formik.handleChange}
required={formik.errors.email_subject}
/>
<Button
className="btn rounded-3 font-golas-600 fs-16 w-203 btn-curious-blue py-2 text-center text-white"
type="submit"
>
{btnName}
</Button>
</form>
</>
);
};

export default Subscriber;
7 changes: 7 additions & 0 deletions src/components/Select.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,15 @@ const Select = ({
className,
name,
label,
required,
}: {
options: [];
value: any;
onChange: any;
className?: string;
name: string;
label: string;
required?: string;
}) => {
return (
<div className={`mb-4 flex flex-col ${className}`}>
Expand All @@ -36,6 +38,11 @@ const Select = ({
</option>
))}
</select>
{required && (
<div className="text-sm font-semibold italic text-red-500">
{required}
</div>
)}
</div>
);
};
Expand Down
2 changes: 1 addition & 1 deletion src/components/Sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ const Sidebar = () => {
return (
<nav className="sticky top-14 flex w-full flex-col px-2 py-10">
{routes.map((route, index) => {
const isActive = pathname === route.href;
const isActive = pathname.startsWith(route.href);
return (
<Link
key={index}
Expand Down
2 changes: 2 additions & 0 deletions src/utils/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ export interface Users {
}

export interface Tag {
data: any;
total: ReactNode;
name: string;
}

Expand Down
7 changes: 7 additions & 0 deletions src/validations/campaign.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import * as yup from 'yup';

export const campaignValidation = yup.object({
sender_identity_id: yup.string().required('Sender Identity is required'),
subscription_list_id: yup.string().required('Subscription is required'),
email_subject: yup.string().required('Email Subject is required'),
});