Skip to content

Commit

Permalink
v0.5.0
Browse files Browse the repository at this point in the history
# Release Notes - TPET v0.5.0

## New Features

- Users can input Reply to 
- Users can input BCC
- Users can input CC 
- Users can input Local part
  • Loading branch information
chungchihhan authored Aug 3, 2024
1 parent 7c4ccce commit 3a00334
Show file tree
Hide file tree
Showing 3 changed files with 168 additions and 11 deletions.
82 changes: 82 additions & 0 deletions src/app/ui/email-input.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
"use client";
import React, { useState, useEffect, KeyboardEvent, MouseEvent } from "react";

interface EmailInputProps {
allowMultiple?: boolean;
onEmailsChange: (emails: string[]) => void;
}

export default function EmailInput({
allowMultiple = true,
onEmailsChange,
}: EmailInputProps) {
const [email, setEmail] = useState("");
const [emails, setEmails] = useState<string[]>([]);

useEffect(() => {
onEmailsChange(emails);
}, [emails, onEmailsChange]);

const handleKeyPress = (e: KeyboardEvent<HTMLInputElement>) => {
if ((e.key === "Tab" || e.key === "Enter") && email.trim()) {
e.preventDefault(); // Prevent default tab/enter behavior
if (validateEmail(email.trim())) {
if (allowMultiple || emails.length === 0) {
setEmails((prevEmails) => [...prevEmails, email.trim()]);
} else {
setEmails([email.trim()]);
}
setEmail("");
} else {
alert("Please enter a valid email address");
}
}
};

const removeEmail = (e: MouseEvent<HTMLButtonElement>, index: number) => {
e.preventDefault();
setEmails((prevEmails) => {
const updatedEmails = prevEmails.filter((_, i) => i !== index);
onEmailsChange(updatedEmails); // Notify parent of the change
return updatedEmails;
});
};

const validateEmail = (email: string) => {
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return emailRegex.test(email);
};

return (
<div className="">
<div className="bg-white rounded-md shadow-sm flex items-center flex-wrap border border-gray-200 p-2 gap-2 focus-within:border-blue-500 focus-within:outline-none focus-within:ring-1 focus-within:ring-blue-500">
{emails.map((email, index) => (
<div
key={index}
className="flex items-center bg-neutral-400 bg-opacity-50 hover:bg-opacity-70 px-2 rounded-md"
>
<span className="mr-2 text-sm">{email}</span>
<button
onClick={(e) => removeEmail(e, index)}
className="text-black-500 hover:text-red-700"
>
&times;
</button>
</div>
))}
<input
type="text"
value={email}
onChange={(e) => setEmail(e.target.value)}
onKeyDown={handleKeyPress}
placeholder={
!allowMultiple && emails.length > 0
? "Edit the existing email and press tab"
: "Type an email and press tab"
}
className="flex-grow p-2 outline-none border-none focus:ring-0 text-sm rounded-md"
/>
</div>
</div>
);
}
91 changes: 81 additions & 10 deletions src/app/ui/send-email-form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@ import SelectDropdown from "@/app/ui/select-dropdown";
import AttachDropdown from "./attach-dropdown";
import FileUpload from "@/app/ui/file-upload";
import IframePreview from "@/app/ui/iframe-preview";
import EmailInput from "@/app/ui/email-input";
import { useEffect } from "react";
import { useRouter } from "next/navigation";
import { access } from "fs";
import { ChevronDown } from "lucide-react";

interface SubmitResponse {
status: string;
Expand Down Expand Up @@ -36,6 +37,11 @@ export default function SendEmailForm() {
const [isGenerateCertificate, setIsGenerateCertificate] =
useState<boolean>(false);

const [replyToEmail, setReplyToEmail] = useState<string>("");
const [bccEmails, setBccEmails] = useState<string[]>([]);
const [ccEmails, setCcEmails] = useState<string[]>([]);
const [localPart, setLocalPart] = useState<string>("");

const router = useRouter();

const isTokenExpired = () => {
Expand All @@ -48,7 +54,6 @@ export default function SendEmailForm() {
console.log("checkLoginStatus function called");
const access_token = localStorage.getItem("access_token");
if (!access_token || isTokenExpired()) {
// alert("Session expired. Please login again.");
router.push("/login");
}
}, []);
Expand All @@ -67,7 +72,12 @@ export default function SendEmailForm() {
spreadsheet_file_id: selectedXlsxFile,
attachment_file_ids: attachment_file_ids,
is_generate_certificate: isGenerateCertificate,
reply_to: replyToEmail,
sender_local_part: localPart,
bcc: bccEmails,
cc: ccEmails,
};
console.log("form data", formData);

setIsSubmitting(true);
try {
Expand Down Expand Up @@ -149,25 +159,33 @@ export default function SendEmailForm() {
setPreviewXlsx(false);
};

// const handleCertificateChange = (
// event: React.ChangeEvent<HTMLInputElement>
// ) => {
// setIsGenerateCertificate(event.target.value === "yes");
// };
const handleReplyToEmailChange = (emails: string[]) => {
setReplyToEmail(emails[0] || "");
};

const handleBccEmailsChange = (emails: string[]) => {
setBccEmails(emails);
};

const handleCcEmailsChange = (emails: string[]) => {
setCcEmails(emails);
};

return (
<>
<div className="flex flex-col justify-center items-start">
<p className="text-4xl font-bold pt-2">Send Emails</p>
<div className="flex justify-between items-center w-full pb-4">
<div className="flex justify-between items-center w-full">
<p className="text-gray-500 italic">
Enter your <strong>subject</strong> and{" "}
<strong>display name</strong>.
</p>
<div className="h-10"></div>
</div>
</div>
<hr className="h-px my-2 bg-gray-200 border-0 dark:bg-gray-700"></hr>
<form onSubmit={onSubmit} ref={ref}>
<p className="text-2xl font-bold py-2">Required</p>
<div className="rounded-md bg-neutral-100 p-4">
<div className="m-3">
<label className="mb-2 block text-sm font-medium">
Expand Down Expand Up @@ -383,6 +401,60 @@ export default function SendEmailForm() {
</p>
)}
</div>
</div>
<p className="text-2xl font-bold py-2 flex items-center gap-1">
Optional
{/* <ChevronDown size={24} /> */}
</p>
<div className="rounded-md bg-neutral-100 p-4">
{/* Sender Local Part */}
<div className="m-3">
<label className="mb-2 block text-sm font-medium">
Sender Local Part:
</label>
<div className="flex items-center bg-neutral-300 rounded-md">
<input
id="sender_local_part"
name="sender_local_part"
type="text"
value={localPart}
onChange={(e) => setLocalPart(e.target.value)}
placeholder="Enter the local part of email"
disabled={isSubmitting}
className={`rounded-l-md border py-2 pl-4 text-sm outline-2 placeholder:text-gray-500 w-full ${
errors.sender_local_part
? "border-red-500"
: "border-gray-200"
}`}
/>
<div className="w-44 text-center text-sm">@aws-educate.tw</div>
</div>
</div>
{/* Reply To */}
<div className="m-3">
<label className="mb-2 block text-sm font-medium">Reply To:</label>
<EmailInput
allowMultiple={false}
onEmailsChange={handleReplyToEmailChange}
/>
</div>
{/* BCC */}
<div className="m-3">
<label className="mb-2 block text-sm font-medium">BCC:</label>
<EmailInput
allowMultiple={true}
onEmailsChange={handleBccEmailsChange}
/>
</div>
{/* CC */}
<div className="m-3">
<label className="mb-2 block text-sm font-medium">CC:</label>
<EmailInput
allowMultiple={true}
onEmailsChange={handleCcEmailsChange}
/>
</div>
{/* Attach files */}
<div className="m-3">
<label className="mb-2 block text-sm font-medium">
Attach files:
Expand Down Expand Up @@ -421,6 +493,7 @@ export default function SendEmailForm() {
)}
</div>
</div>
{/* Generate certificate */}
<div className="my-5 mx-3">
<label className="mb-2 block text-sm font-medium">
Provide a certification of participation?
Expand Down Expand Up @@ -479,8 +552,6 @@ export default function SendEmailForm() {
</button>
)}
</div>
{/* <div>template : {selectedHtmlFile}</div> */}
{/* <div>sheet : {selectedXlsxFile}</div> */}
</form>
</>
);
Expand Down
6 changes: 5 additions & 1 deletion src/lib/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ const formSchema = z.object({
spreadsheet_file_id: z.string().min(1, "Spreadsheet file ID is required"),
attachment_file_ids: z.array(z.string()),
is_generate_certificate: z.boolean(),
reply_to: z.string().email("Invalid email address"),
sender_local_part: z.string(),
bcc: z.array(z.string().email("Invalid email address")),
cc: z.array(z.string().email("Invalid email address")),
});

const loginSchema = z.object({
Expand Down Expand Up @@ -36,7 +40,7 @@ export async function submitForm(data: string, access_token: string) {
}

try {
// console.log("data", validation.data);
console.log("data", validation.data);
const base_url = process.env.NEXT_PUBLIC_API_ENDPOINT;
const url = new URL(`${base_url}/send-email`);
const response = await fetch(
Expand Down

0 comments on commit 3a00334

Please sign in to comment.