mirror of
https://github.com/regmicmahesh/ses-mailer.git
synced 2024-08-14 22:57:18 +00:00
initial commit
This commit is contained in:
parent
f0e51571ed
commit
cdf7a087e3
11 changed files with 8817 additions and 1738 deletions
6953
client/package-lock.json
generated
Normal file
6953
client/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load diff
|
@ -1,12 +1,14 @@
|
||||||
|
import "../src/styles/Navbar.css";
|
||||||
import { A } from "@solidjs/router";
|
import { A } from "@solidjs/router";
|
||||||
|
|
||||||
export const Navbar = () => {
|
export const Navbar = () => {
|
||||||
return (
|
return (
|
||||||
<nav>
|
<nav>
|
||||||
{" "}
|
<ul class="nav-list">
|
||||||
<A href="/"> Home </A>{" "}
|
<A href="/" class="nav-link"> Home </A>
|
||||||
<A href="/mail">Mail Management</A>{" "}
|
<A href="/mail" class="nav-link">Mail Management</A>
|
||||||
<A href="/template">Template Management</A>{" "}
|
<A href="/template" class="nav-link active">Template Management</A>
|
||||||
</nav>
|
</ul>
|
||||||
);
|
</nav>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import "./styles/index.css";
|
||||||
import { Router, Routes, Route } from "@solidjs/router";
|
import { Router, Routes, Route } from "@solidjs/router";
|
||||||
import { TemplateManagement } from "./createTemplate";
|
import { TemplateManagement } from "./createTemplate";
|
||||||
import { HomePage } from "./homePage";
|
import { HomePage } from "./homePage";
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
import "../src/styles/TemplateManagement.css";
|
||||||
|
import "../src/styles/sendMail.css";
|
||||||
import { createEffect, createSignal, For } from "solid-js";
|
import { createEffect, createSignal, For } from "solid-js";
|
||||||
|
|
||||||
export const TemplateManagement = () => {
|
export const TemplateManagement = () => {
|
||||||
|
@ -16,58 +18,51 @@ export const TemplateManagement = () => {
|
||||||
}, [templates]);
|
}, [templates]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<main class="template-page">
|
||||||
<h1>Template Management Page</h1>
|
<section class="form-container2">
|
||||||
|
<h1>Template Management Page</h1>
|
||||||
|
|
||||||
<hr />
|
<form onsubmit={submitForm}>
|
||||||
|
<div class="create-template">Create Template </div>
|
||||||
|
<div>
|
||||||
|
<div>HTML Template:</div>
|
||||||
|
<textarea
|
||||||
|
value={htmlBody()}
|
||||||
|
class="textarea"
|
||||||
|
onInput={(e) => setHtmlBody(e.target.value)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
<form onsubmit={submitForm}>
|
<label>
|
||||||
<h2>Create Template </h2>
|
<div>Subject:</div>
|
||||||
<div>
|
<input
|
||||||
HTML Template: <br />
|
type="text"
|
||||||
<textarea
|
value={subject()}
|
||||||
value={htmlBody()}
|
onInput={(e) => setSubject(e.target.value)}
|
||||||
onInput={(e) => setHtmlBody(e.target.value)}
|
/>
|
||||||
/>
|
</label>
|
||||||
</div>
|
|
||||||
|
|
||||||
<div>
|
<label>
|
||||||
Subject: <br />
|
<div>Template Name:</div>
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
value={subject()}
|
value={templateName()}
|
||||||
onInput={(e) => setSubject(e.target.value)}
|
onInput={(e) => setTemplateName(e.target.value)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</label>
|
||||||
|
|
||||||
<div>
|
<input class="btn" type="submit" value="Submit" />
|
||||||
Template Name: <br />
|
</form>
|
||||||
<input
|
</section>
|
||||||
type="text"
|
<section class="template-list">
|
||||||
value={templateName()}
|
<h2>Templates</h2>
|
||||||
onInput={(e) => setTemplateName(e.target.value)}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<input type="submit" value="Submit" />
|
|
||||||
</form>
|
|
||||||
|
|
||||||
<hr />
|
|
||||||
|
|
||||||
<h2>Templates</h2>
|
|
||||||
|
|
||||||
|
|
||||||
<ul>
|
|
||||||
<For each={templates()}>{
|
|
||||||
|
|
||||||
(template) => <li>{template}</li>
|
|
||||||
}</For>
|
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<For each={templates()}>
|
||||||
|
{(template) => <li>{template}</li>}
|
||||||
|
</For>
|
||||||
</ul>
|
</ul>
|
||||||
|
</section>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
|
|
||||||
export const HomePage = () => {
|
export const HomePage = () => {
|
||||||
return (
|
return (
|
||||||
<div>
|
<section class="homepage">
|
||||||
<h1> Welcome to the SES utility software. </h1>
|
<h1> Welcome to the SES utility software. </h1>
|
||||||
</div>
|
</section>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,131 +1,149 @@
|
||||||
import { createSignal, For } from "solid-js";
|
import { createSignal, For } from "solid-js";
|
||||||
|
import "../src/styles/sendMail.css";
|
||||||
|
|
||||||
type TemplateList = Array<Record<string, string>>;
|
type TemplateList = Array<Record<string, string>>;
|
||||||
|
|
||||||
export const MailManagement = () => {
|
export const MailManagement = () => {
|
||||||
const [templateList, setTemplateList] = createSignal<TemplateList>([]);
|
const [templateList, setTemplateList] = createSignal<TemplateList>([]);
|
||||||
|
|
||||||
const [receiverKey, setReceiverKey] = createSignal("");
|
const [receiverKey, setReceiverKey] = createSignal("");
|
||||||
|
|
||||||
const [variables, setVariables] = createSignal<string[]>([]);
|
const [variables, setVariables] = createSignal<string[]>([]);
|
||||||
|
|
||||||
const [rawCsv, setRawCsv] = createSignal("");
|
const [rawCsv, setRawCsv] = createSignal("");
|
||||||
|
|
||||||
const onCsvSubmit = (e: Event) => {
|
const onCsvSubmit = (e: Event) => {
|
||||||
const target = e.target as HTMLInputElement;
|
const target = e.target as HTMLInputElement;
|
||||||
|
|
||||||
const input = target.files?.[0];
|
const input = target.files?.[0];
|
||||||
|
|
||||||
if (!input) {
|
if (!input) {
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
const reader = new FileReader();
|
|
||||||
|
|
||||||
reader.onload = (e) => {
|
|
||||||
const text = e.target?.result as string;
|
|
||||||
const lines = text.split("\n");
|
|
||||||
|
|
||||||
const header = lines[0].split(",").map((header) => header.trim());
|
|
||||||
setRawCsv(text);
|
|
||||||
setVariables(header);
|
|
||||||
|
|
||||||
const templates = [];
|
|
||||||
|
|
||||||
for (let i of lines.slice(1)) {
|
|
||||||
if (i.length === 0) continue;
|
|
||||||
|
|
||||||
const row = i.split(",").map((row) => row.trim());
|
|
||||||
const obj: Record<string, string> = {};
|
|
||||||
|
|
||||||
for (let j = 0; j < header.length; j++) {
|
|
||||||
obj[header[j]] = row[j];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
templates.push(obj);
|
const reader = new FileReader();
|
||||||
}
|
|
||||||
|
|
||||||
setTemplateList(templates);
|
reader.onload = (e) => {
|
||||||
|
const text = e.target?.result as string;
|
||||||
|
const lines = text.split("\n");
|
||||||
|
|
||||||
|
const header = lines[0].split(",").map((header) => header.trim());
|
||||||
|
setRawCsv(text);
|
||||||
|
setVariables(header);
|
||||||
|
|
||||||
|
const templates = [];
|
||||||
|
|
||||||
|
for (let i of lines.slice(1)) {
|
||||||
|
if (i.length === 0) continue;
|
||||||
|
|
||||||
|
const row = i.split(",").map((row) => row.trim());
|
||||||
|
const obj: Record<string, string> = {};
|
||||||
|
|
||||||
|
for (let j = 0; j < header.length; j++) {
|
||||||
|
obj[header[j]] = row[j];
|
||||||
|
}
|
||||||
|
|
||||||
|
templates.push(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
setTemplateList(templates);
|
||||||
|
};
|
||||||
|
|
||||||
|
reader.readAsText(input);
|
||||||
};
|
};
|
||||||
|
|
||||||
reader.readAsText(input);
|
const sendMail = (e: Event) => {
|
||||||
};
|
e.preventDefault();
|
||||||
|
|
||||||
const sendMail = (e: Event) => {
|
console.log(templateList());
|
||||||
e.preventDefault();
|
|
||||||
|
|
||||||
console.log(templateList());
|
const receivers = templateList().map(
|
||||||
|
(template) => template[receiverKey()]
|
||||||
|
);
|
||||||
|
|
||||||
const receivers = templateList().map((template) => template[receiverKey()]);
|
console.log(receivers);
|
||||||
|
};
|
||||||
|
|
||||||
console.log(receivers);
|
const onChangeReceiverColumn = (e: Event) => {
|
||||||
};
|
const el = e.target as HTMLSelectElement;
|
||||||
|
|
||||||
const onChangeReceiverColumn = (e: Event) => {
|
const value = el.value;
|
||||||
const el = e.target as HTMLSelectElement;
|
|
||||||
|
|
||||||
const value = el.value;
|
setReceiverKey(value);
|
||||||
|
};
|
||||||
|
|
||||||
setReceiverKey(value);
|
return (
|
||||||
};
|
<main class="mail-management-page">
|
||||||
|
<section class="form-container">
|
||||||
|
<h1>Mail Management Page</h1>
|
||||||
|
|
||||||
return (
|
<form onsubmit={sendMail} class="mail-management-form">
|
||||||
<div>
|
<label>
|
||||||
<h1>Mail Management Page</h1>
|
<div>Sender</div>
|
||||||
|
<input type="text" />
|
||||||
|
</label>
|
||||||
|
|
||||||
<form onsubmit={sendMail}>
|
<label>
|
||||||
<div>
|
<div>Template Name:</div>
|
||||||
Sender: <br />
|
<input type="text" />
|
||||||
<input type="text" />
|
</label>
|
||||||
</div>
|
|
||||||
|
|
||||||
<div>
|
<div>Recipient List (CSV Only Accepted):</div>
|
||||||
Template Name: <br />
|
<label class="input-file-label">
|
||||||
<input type="text" />
|
{/* <div>Enter .csv file here</div> */}
|
||||||
</div>
|
<input
|
||||||
|
type="file"
|
||||||
|
accept=".csv"
|
||||||
|
onChange={onCsvSubmit}
|
||||||
|
class="input-file"
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
|
||||||
<div>
|
{variables().length > 0 && (
|
||||||
Recipient List (CSV Only Accepted): <br />
|
<>
|
||||||
<input type="file" accept=".csv" onChange={onCsvSubmit} />
|
<div>
|
||||||
</div>
|
Receiver Email Column: <br />
|
||||||
|
<select onchange={onChangeReceiverColumn}>
|
||||||
|
<For each={variables()}>
|
||||||
|
{(variable) => (
|
||||||
|
<option value={variable}>
|
||||||
|
{variable}
|
||||||
|
</option>
|
||||||
|
)}
|
||||||
|
</For>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
|
||||||
{variables().length > 0 && (
|
<input type="submit" value="Send" class="btn btn-send" />
|
||||||
<>
|
</form>
|
||||||
|
</section>
|
||||||
<div>
|
<div>
|
||||||
Receiver Email Column: <br />
|
<section>
|
||||||
<select onchange={onChangeReceiverColumn}>
|
<table border={1} class="the-table">
|
||||||
<For each={variables()}>
|
<thead>
|
||||||
{(variable) => <option value={variable}>{variable}</option>}
|
<tr>
|
||||||
</For>
|
<For each={variables()}>
|
||||||
</select>
|
{(variable) => <th>{variable}</th>}
|
||||||
|
</For>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
|
||||||
|
<tbody>
|
||||||
|
{templateList().map((template) => (
|
||||||
|
<tr>
|
||||||
|
<For each={variables()}>
|
||||||
|
{(variable) => (
|
||||||
|
<td>{template[variable]}</td>
|
||||||
|
)}
|
||||||
|
</For>
|
||||||
|
</tr>
|
||||||
|
))}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</section>
|
||||||
</div>
|
</div>
|
||||||
|
</main>
|
||||||
<div>
|
);
|
||||||
<table border={1}>
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<For each={variables()}>
|
|
||||||
{(variable) => <th>{variable}</th>}
|
|
||||||
</For>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
|
|
||||||
<tbody>
|
|
||||||
{templateList().map((template) => (
|
|
||||||
<tr>
|
|
||||||
<For each={variables()}>
|
|
||||||
{(variable) => <td>{template[variable]}</td>}
|
|
||||||
</For>
|
|
||||||
</tr>
|
|
||||||
))}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<input type="submit" value="Send" />
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
38
client/src/styles/Navbar.css
Normal file
38
client/src/styles/Navbar.css
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
nav {
|
||||||
|
height: 64px;
|
||||||
|
border-bottom: 1px solid #c5c5c5;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
/* -------testing--------- */
|
||||||
|
/* position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0; */
|
||||||
|
/* -------testing--------- */
|
||||||
|
}
|
||||||
|
main {
|
||||||
|
/* margin-top: 64px; */
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-list {
|
||||||
|
display: flex;
|
||||||
|
gap: 3rem;
|
||||||
|
}
|
||||||
|
.nav-link {
|
||||||
|
cursor: pointer;
|
||||||
|
/* border: 2px solid purple; */
|
||||||
|
padding: 0.5em 1em;
|
||||||
|
border-radius: 0.4em;
|
||||||
|
color: purple;
|
||||||
|
}
|
||||||
|
.nav-link:hover {
|
||||||
|
background-color: purple;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.active {
|
||||||
|
border: 2px solid purple;
|
||||||
|
}
|
15
client/src/styles/TemplateManagement.css
Normal file
15
client/src/styles/TemplateManagement.css
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
.template-list {
|
||||||
|
border: 2px solid red;
|
||||||
|
margin: 1rem;
|
||||||
|
align-self: center;
|
||||||
|
min-width: 350px;
|
||||||
|
}
|
||||||
|
.template-page {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 2rem;
|
||||||
|
}
|
||||||
|
.form-container {
|
||||||
|
flex: 1;
|
||||||
|
}
|
112
client/src/styles/index.css
Normal file
112
client/src/styles/index.css
Normal file
|
@ -0,0 +1,112 @@
|
||||||
|
@import url("https://fonts.googleapis.com/css2?family=Roboto:ital,wght@0,100;0,300;0,400;0,500;0,700;0,900;1,100;1,300;1,400;1,500;1,700;1,900&display=swap");
|
||||||
|
* {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
list-style-type: none;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
font-family: "Roboto", sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -----------Homepage----------------- */
|
||||||
|
|
||||||
|
.homepage{
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* -----------Homepage----------------- */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
input,
|
||||||
|
.textarea {
|
||||||
|
margin: 0.2rem 0 0.7rem 0;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
border-radius: 0.3rem;
|
||||||
|
border: none;
|
||||||
|
outline: 2px solid grey;
|
||||||
|
background-color: transparent;
|
||||||
|
padding: 0.5rem;
|
||||||
|
}
|
||||||
|
input {
|
||||||
|
transition: 0.5s;
|
||||||
|
}
|
||||||
|
|
||||||
|
input:focus {
|
||||||
|
outline: 2px solid purple;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn {
|
||||||
|
padding: 0.5rem 1rem;
|
||||||
|
background-color: purple;
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
outline-color: transparent;
|
||||||
|
border-radius: 0.4rem;
|
||||||
|
|
||||||
|
margin: 0.5rem 0;
|
||||||
|
font-size: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.textarea {
|
||||||
|
width: 100%;
|
||||||
|
max-width: 600px;
|
||||||
|
max-height: 300px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------Select styling------------------ */
|
||||||
|
select {
|
||||||
|
/* appearance: none; */
|
||||||
|
background-color: transparent;
|
||||||
|
border: none;
|
||||||
|
padding: 0 1em 0 0;
|
||||||
|
margin: 0.5rem;
|
||||||
|
width: 20%;
|
||||||
|
font-family: inherit;
|
||||||
|
font-size: inherit;
|
||||||
|
cursor: inherit;
|
||||||
|
line-height: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------Table styling------------------ */
|
||||||
|
|
||||||
|
table {
|
||||||
|
margin-top: 1rem;
|
||||||
|
color: #333;
|
||||||
|
background: white;
|
||||||
|
border: 1px solid grey;
|
||||||
|
/* font-size: 12pt; */
|
||||||
|
border-collapse: collapse;
|
||||||
|
min-width: 400px;
|
||||||
|
max-width: 600px;
|
||||||
|
/* overflow: scroll; */
|
||||||
|
}
|
||||||
|
table thead th,
|
||||||
|
table tfoot th {
|
||||||
|
color: #777;
|
||||||
|
background: rgba(0, 0, 0, 0.1);
|
||||||
|
}
|
||||||
|
table caption {
|
||||||
|
padding: 0.5em;
|
||||||
|
}
|
||||||
|
table th,
|
||||||
|
table td {
|
||||||
|
padding: 0.5em;
|
||||||
|
border: 1px solid lightgrey;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------Table styling------------------ */
|
45
client/src/styles/sendMail.css
Normal file
45
client/src/styles/sendMail.css
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
main {
|
||||||
|
min-height: 90vh;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.form-container {
|
||||||
|
min-width: 400px;
|
||||||
|
max-width: 900px;
|
||||||
|
border-radius: 0.3rem;
|
||||||
|
padding: 1.5rem;
|
||||||
|
|
||||||
|
box-shadow: 2px 0px 16px 4px rgba(7, 7, 7, 0.3);
|
||||||
|
-webkit-box-shadow: 2px 0px 16px 4px rgba(7, 7, 7, 0.3);
|
||||||
|
-moz-box-shadow: 2px 0px 16px 4px rgba(7, 7, 7, 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
label {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
margin-block: 0.5rem;
|
||||||
|
/* gap: 1rem; */
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-file {
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
display: inline-block;
|
||||||
|
padding: 6px 12px;
|
||||||
|
|
||||||
|
outline: none;
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.input-file-label {
|
||||||
|
outline: 2px solid grey;
|
||||||
|
height: 100px;
|
||||||
|
cursor: pointer;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
flex-direction: column;
|
||||||
|
border-radius: 0.5rem;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
3061
client/yarn.lock
3061
client/yarn.lock
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue