initial commit

This commit is contained in:
Mahesh C. Regmi 2023-03-31 19:56:02 +05:45
commit f0e51571ed
13 changed files with 2796 additions and 0 deletions

148
.gitignore vendored Normal file
View File

@ -0,0 +1,148 @@
# Created by https://www.toptal.com/developers/gitignore/api/node
# Edit at https://www.toptal.com/developers/gitignore?templates=node
### Node ###
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
lerna-debug.log*
.pnpm-debug.log*
# Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
# Runtime data
pids
*.pid
*.seed
*.pid.lock
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
*.lcov
# nyc test coverage
.nyc_output
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# Bower dependency directory (https://bower.io/)
bower_components
# node-waf configuration
.lock-wscript
# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release
# Dependency directories
node_modules/
jspm_packages/
# Snowpack dependency directory (https://snowpack.dev/)
web_modules/
# TypeScript cache
*.tsbuildinfo
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Optional stylelint cache
.stylelintcache
# Microbundle cache
.rpt2_cache/
.rts2_cache_cjs/
.rts2_cache_es/
.rts2_cache_umd/
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# dotenv environment variable files
.env
.env.development.local
.env.test.local
.env.production.local
.env.local
# parcel-bundler cache (https://parceljs.org/)
.cache
.parcel-cache
# Next.js build output
.next
out
# Nuxt.js build / generate output
.nuxt
dist
# Gatsby files
.cache/
# Comment in the public line in if your project uses Gatsby and not Next.js
# https://nextjs.org/blog/next-9-1#public-directory-support
# public
# vuepress build output
.vuepress/dist
# vuepress v2.x temp and cache directory
.temp
# Docusaurus cache and generated files
.docusaurus
# Serverless directories
.serverless/
# FuseBox cache
.fusebox/
# DynamoDB Local files
.dynamodb/
# TernJS port file
.tern-port
# Stores VSCode versions used for testing VSCode extensions
.vscode-test
# yarn v2
.yarn/cache
.yarn/unplugged
.yarn/build-state.yml
.yarn/install-state.gz
.pnp.*
### Node Patch ###
# Serverless Webpack directories
.webpack/
# Optional stylelint cache
# SvelteKit build / generate output
.svelte-kit
# End of https://www.toptal.com/developers/gitignore/api/node
*.csv
.vite

16
client/index.html Normal file
View File

@ -0,0 +1,16 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<link rel="shortcut icon" type="image/ico" href="/src/assets/favicon.ico" />
<title>Solid App</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<script src="/src/index.tsx" type="module"></script>
</body>
</html>

28
client/package.json Normal file
View File

@ -0,0 +1,28 @@
{
"name": "vite-template-solid",
"version": "0.0.0",
"description": "",
"type": "module",
"scripts": {
"start": "vite",
"dev": "vite",
"build": "vite build",
"serve": "vite preview",
"test": "vitest"
},
"license": "MIT",
"devDependencies": {
"@solidjs/testing-library": "^0.6.0",
"@testing-library/jest-dom": "^5.16.5",
"@types/testing-library__jest-dom": "^5.14.5",
"jsdom": "^21.1.0",
"typescript": "^4.9.5",
"vite": "^4.1.1",
"vite-plugin-solid": "^2.5.0",
"vitest": "^0.28.4"
},
"dependencies": {
"@solidjs/router": "^0.8.2",
"solid-js": "^1.6.10"
}
}

12
client/src/Navbar.tsx Normal file
View File

@ -0,0 +1,12 @@
import { A } from "@solidjs/router";
export const Navbar = () => {
return (
<nav>
{" "}
<A href="/"> Home </A>{" "}
<A href="/mail">Mail Management</A>{" "}
<A href="/template">Template Management</A>{" "}
</nav>
);
};

19
client/src/app.tsx Normal file
View File

@ -0,0 +1,19 @@
import { Router, Routes, Route } from "@solidjs/router";
import { TemplateManagement } from "./createTemplate";
import { HomePage } from "./homePage";
import { Navbar } from "./Navbar";
import { MailManagement } from "./sendMail";
export const App = () => {
return (
<Router>
<Navbar />
<Routes>
<Route path="/" component={HomePage} />
<Route path="/mail" component={MailManagement} />
<Route path="/template" component={TemplateManagement} />
</Routes>
</Router>
);
};

View File

@ -0,0 +1,73 @@
import { createEffect, createSignal, For } from "solid-js";
export const TemplateManagement = () => {
const [htmlBody, setHtmlBody] = createSignal("");
const [subject, setSubject] = createSignal("");
const [templateName, setTemplateName] = createSignal("");
const [templates, setTemplates] = createSignal<string[]>([]);
const submitForm = (e: Event) => {
e.preventDefault();
};
createEffect(() => {
setTemplates(["template1", "template2", "template3"]);
}, [templates]);
return (
<div>
<h1>Template Management Page</h1>
<hr />
<form onsubmit={submitForm}>
<h2>Create Template </h2>
<div>
HTML Template: <br />
<textarea
value={htmlBody()}
onInput={(e) => setHtmlBody(e.target.value)}
/>
</div>
<div>
Subject: <br />
<input
type="text"
value={subject()}
onInput={(e) => setSubject(e.target.value)}
/>
</div>
<div>
Template Name: <br />
<input
type="text"
value={templateName()}
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>
</div>
);
};

7
client/src/homePage.tsx Normal file
View File

@ -0,0 +1,7 @@
export const HomePage = () => {
return (
<div>
<h1> Welcome to the SES utility software. </h1>
</div>
);
};

14
client/src/index.tsx Normal file
View File

@ -0,0 +1,14 @@
import { render } from 'solid-js/web';
import { Router } from '@solidjs/router';
import { App } from './app';
const root = document.getElementById('root');
if (import.meta.env.DEV && !(root instanceof HTMLElement)) {
throw new Error(
'Root element not found. Did you forget to add it to your index.html? Or maybe the id attribute got mispelled?',
);
}
render(() => <App />, root!);

131
client/src/sendMail.tsx Normal file
View File

@ -0,0 +1,131 @@
import { createSignal, For } from "solid-js";
type TemplateList = Array<Record<string, string>>;
export const MailManagement = () => {
const [templateList, setTemplateList] = createSignal<TemplateList>([]);
const [receiverKey, setReceiverKey] = createSignal("");
const [variables, setVariables] = createSignal<string[]>([]);
const [rawCsv, setRawCsv] = createSignal("");
const onCsvSubmit = (e: Event) => {
const target = e.target as HTMLInputElement;
const input = target.files?.[0];
if (!input) {
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);
}
setTemplateList(templates);
};
reader.readAsText(input);
};
const sendMail = (e: Event) => {
e.preventDefault();
console.log(templateList());
const receivers = templateList().map((template) => template[receiverKey()]);
console.log(receivers);
};
const onChangeReceiverColumn = (e: Event) => {
const el = e.target as HTMLSelectElement;
const value = el.value;
setReceiverKey(value);
};
return (
<div>
<h1>Mail Management Page</h1>
<form onsubmit={sendMail}>
<div>
Sender: <br />
<input type="text" />
</div>
<div>
Template Name: <br />
<input type="text" />
</div>
<div>
Recipient List (CSV Only Accepted): <br />
<input type="file" accept=".csv" onChange={onCsvSubmit} />
</div>
{variables().length > 0 && (
<>
<div>
Receiver Email Column: <br />
<select onchange={onChangeReceiverColumn}>
<For each={variables()}>
{(variable) => <option value={variable}>{variable}</option>}
</For>
</select>
</div>
<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>
);
};

View File

@ -0,0 +1,37 @@
import { render, fireEvent } from '@solidjs/testing-library';
import { TodoList } from './todo-list';
describe('<TodoList />', () => {
test('it will render an text input and a button', () => {
const { getByPlaceholderText, getByText } = render(() => <TodoList />);
expect(getByPlaceholderText('new todo here')).toBeInTheDocument();
expect(getByText('Add Todo')).toBeInTheDocument();
});
test('it will add a new todo', async () => {
const { getByPlaceholderText, getByText } = render(() => <TodoList />);
const input = getByPlaceholderText('new todo here') as HTMLInputElement;
const button = getByText('Add Todo');
input.value = 'test new todo';
fireEvent.click(button as HTMLInputElement);
expect(input.value).toBe('');
expect(getByText(/test new todo/)).toBeInTheDocument();
});
test('it will mark a todo as completed', async () => {
const { getByPlaceholderText, findByRole, getByText } = render(() => (
<TodoList />
));
const input = getByPlaceholderText('new todo here') as HTMLInputElement;
const button = getByText('Add Todo') as HTMLButtonElement;
input.value = 'mark new todo as completed';
fireEvent.click(button);
const completed = (await findByRole('checkbox')) as HTMLInputElement;
expect(completed?.checked).toBe(false);
fireEvent.click(completed);
expect(completed?.checked).toBe(true);
const text = getByText('mark new todo as completed') as HTMLSpanElement;
expect(text).toHaveStyle({ 'text-decoration': 'line-through' });
});
});

13
client/tsconfig.json Normal file
View File

@ -0,0 +1,13 @@
{
"compilerOptions": {
"strict": true,
"target": "ESNext",
"module": "ESNext",
"moduleResolution": "node",
"allowSyntheticDefaultImports": true,
"esModuleInterop": true,
"jsx": "preserve",
"jsxImportSource": "solid-js",
"types": ["vite/client", "@testing-library/jest-dom"]
}
}

30
client/vite.config.ts Normal file
View File

@ -0,0 +1,30 @@
/// <reference types="vitest" />
/// <reference types="vite/client" />
import { defineConfig } from 'vite';
import solidPlugin from 'vite-plugin-solid';
export default defineConfig({
plugins: [solidPlugin()],
server: {
port: 3000,
},
test: {
environment: 'jsdom',
globals: true,
transformMode: { web: [/\.[jt]sx?$/] },
setupFiles: ['node_modules/@testing-library/jest-dom/extend-expect.js'],
// otherwise, solid would be loaded twice:
deps: { registerNodeLoader: true },
// if you have few tests, try commenting one
// or both out to improve performance:
threads: false,
isolate: false,
},
build: {
target: 'esnext',
},
resolve: {
conditions: ['development', 'browser'],
},
});

2268
client/yarn.lock Normal file

File diff suppressed because it is too large Load Diff