Compare commits

..
13 changed files with 738 additions and 351 deletions
+282 -326
View File
File diff suppressed because it is too large Load Diff
+14 -14
View File
@@ -13,19 +13,19 @@
"private": true,
"dependencies": {
"@popperjs/core": "^2.11.8",
"@types/node": "^25.3.2",
"@types/node": "^25.5.0",
"@types/react-dom": "^19.2.3",
"@vitejs/plugin-react": "^5.1.4",
"bootstrap": "^5.3.8",
"dompurify": "^3.3.1",
"i18next": "^25.8.13",
"dompurify": "^3.3.3",
"i18next": "^25.8.18",
"react": "^19.2.4",
"react-bootstrap": "^2.10.10",
"react-bootstrap-icons": "^1.11.6",
"react-charts": "^3.0.0-beta.57",
"react-datepicker": "^9.1.0",
"react-dom": "^19.2.4",
"react-i18next": "^16.5.4",
"react-i18next": "^16.5.8",
"react-markdown": "^10.1.0",
"react-router": "^7.13.1",
"react-router-bootstrap": "^0.26.3",
@@ -62,30 +62,30 @@
]
},
"devDependencies": {
"@eslint/compat": "^2.0.2",
"@eslint/eslintrc": "^3.3.4",
"@eslint/compat": "^2.0.3",
"@eslint/eslintrc": "^3.3.5",
"@eslint/js": "^9.39.2",
"@stylistic/eslint-plugin": "^5.9.0",
"@stylistic/eslint-plugin": "^5.10.0",
"@testing-library/jest-dom": "^6.9.1",
"@testing-library/react": "^16.3.2",
"@testing-library/user-event": "^14.6.1",
"@types/jest": "^30.0.0",
"@types/react": "^19.2.14",
"@types/react-router-bootstrap": "^0.26.8",
"@vitest/coverage-v8": "^4.0.18",
"@vitest/coverage-v8": "^4.1.0",
"eslint": "^9.39.2",
"eslint-config-prettier": "^10.1.8",
"eslint-plugin-import": "^2.32.0",
"eslint-plugin-jsdoc": "^62.7.1",
"eslint-plugin-jsdoc": "^62.8.0",
"eslint-plugin-n": "^17.24.0",
"eslint-plugin-promise": "^7.2.1",
"eslint-plugin-react": "^7.37.5",
"globals": "^17.3.0",
"jsdom": "^28.1.0",
"globals": "^17.4.0",
"jsdom": "^29.0.0",
"prettier": "^3.8.1",
"sass": "^1.97.3",
"sass": "^1.98.0",
"source-map-support": "^0.5.21",
"typescript-eslint": "^8.56.1",
"vitest": "^4.0.18"
"typescript-eslint": "^8.57.1",
"vitest": "^4.1.0"
}
}
+110
View File
@@ -0,0 +1,110 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Email Changed</title>
<style>
body {
margin: 0;
padding: 0;
background-color: #f4f6f8;
font-family: Arial, Helvetica, sans-serif;
color: #1f2937;
}
.wrapper {
width: 100%;
table-layout: fixed;
background-color: #f4f6f8;
padding: 24px 12px;
}
.card {
width: 100%;
max-width: 600px;
margin: 0 auto;
background: #ffffff;
border: 1px solid #e5e7eb;
border-radius: 10px;
overflow: hidden;
}
.header {
padding: 20px 24px;
background: #111827;
color: #ffffff;
font-size: 20px;
font-weight: 700;
}
.content {
padding: 24px;
font-size: 16px;
line-height: 1.5;
}
.change-box {
margin: 16px 0;
padding: 14px;
border: 1px solid #d1d5db;
border-radius: 8px;
background: #f9fafb;
font-size: 14px;
line-height: 1.6;
}
.label {
color: #4b5563;
font-weight: 700;
}
.value {
color: #111827;
word-break: break-word;
}
.footer {
padding: 18px 24px 24px;
font-size: 13px;
line-height: 1.5;
color: #6b7280;
}
@media only screen and (max-width: 600px) {
.wrapper {
padding: 16px 8px;
}
.header,
.content,
.footer {
padding-left: 16px;
padding-right: 16px;
}
}
</style>
</head>
<body>
<div class="wrapper">
<div class="card">
<div class="header">Your email was changed</div>
<div class="content">
<p>Hello,</p>
<p>We are confirming that the email address on your account was updated.</p>
<div class="change-box">
<div><span class="label">Old email:</span> <span class="value">{{ EMAIL_FROM }}</span></div>
<div><span class="label">New email:</span> <span class="value">{{ EMAIL_TO }}</span></div>
</div>
<p>If you made this change, no further action is needed.</p>
<p>If you did not make this change, please secure your account immediately and contact support at <a href="mailto:ricardompcampos@gmail.com">ricardompcampos@gmail.com</a>.</p>
</div>
<div class="footer">
This is an automatic notification, please do not reply.
</div>
</div>
</div>
</body>
</html>
@@ -0,0 +1,97 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Password Changed</title>
<style>
body {
margin: 0;
padding: 0;
background-color: #f4f6f8;
font-family: Arial, Helvetica, sans-serif;
color: #1f2937;
}
.wrapper {
width: 100%;
table-layout: fixed;
background-color: #f4f6f8;
padding: 24px 12px;
}
.card {
width: 100%;
max-width: 600px;
margin: 0 auto;
background: #ffffff;
border: 1px solid #e5e7eb;
border-radius: 10px;
overflow: hidden;
}
.header {
padding: 20px 24px;
background: #111827;
color: #ffffff;
font-size: 20px;
font-weight: 700;
}
.content {
padding: 24px;
font-size: 16px;
line-height: 1.5;
}
.notice {
margin: 16px 0;
padding: 14px;
border: 1px solid #d1d5db;
border-radius: 8px;
background: #f9fafb;
font-size: 14px;
line-height: 1.6;
}
.footer {
padding: 18px 24px 24px;
font-size: 13px;
line-height: 1.5;
color: #6b7280;
}
@media only screen and (max-width: 600px) {
.wrapper {
padding: 16px 8px;
}
.header,
.content,
.footer {
padding-left: 16px;
padding-right: 16px;
}
}
</style>
</head>
<body>
<div class="wrapper">
<div class="card">
<div class="header">Your password was changed</div>
<div class="content">
<p>Hello,</p>
<p>This is a confirmation that your account password was successfully changed.</p>
<div class="notice">
If you made this change, no further action is needed. If you did not make this change,
secure your account immediately and contact support at <a href="mailto:ricardompcampos@gmail.com">ricardompcampos@gmail.com</a>.
</div>
<p>Thank you.</p>
</div>
<div class="footer">This is an automatic message, please do not reply.</div>
</div>
</div>
</body>
</html>
+110
View File
@@ -0,0 +1,110 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Reset Your Password</title>
<style>
body {
margin: 0;
padding: 0;
background-color: #f4f6f8;
font-family: Arial, Helvetica, sans-serif;
color: #1f2937;
}
.wrapper {
width: 100%;
table-layout: fixed;
background-color: #f4f6f8;
padding: 24px 12px;
}
.card {
width: 100%;
max-width: 600px;
margin: 0 auto;
background: #ffffff;
border: 1px solid #e5e7eb;
border-radius: 10px;
overflow: hidden;
}
.header {
padding: 20px 24px;
background: #111827;
color: #ffffff;
font-size: 20px;
font-weight: 700;
}
.content {
padding: 24px;
font-size: 16px;
line-height: 1.5;
}
.button-wrap {
margin: 24px 0;
text-align: center;
}
.button {
display: inline-block;
padding: 12px 20px;
background: #b91c1c;
color: #ffffff;
text-decoration: none;
border-radius: 8px;
font-weight: 700;
font-size: 15px;
}
.fallback-link {
margin-top: 8px;
font-size: 13px;
color: #4b5563;
word-break: break-all;
}
.footer {
padding: 18px 24px 24px;
font-size: 13px;
line-height: 1.5;
color: #6b7280;
}
@media only screen and (max-width: 600px) {
.wrapper {
padding: 16px 8px;
}
.header,
.content,
.footer {
padding-left: 16px;
padding-right: 16px;
}
}
</style>
</head>
<body>
<div class="wrapper">
<div class="card">
<div class="header">Reset your password</div>
<div class="content">
<p>Hello,</p>
<p>We received a request to reset your password. Click the button below to continue.</p>
<div class="button-wrap">
<a class="button" href="{{ RESET_LINK }}" target="_blank" rel="noopener noreferrer">Reset Password</a>
<div class="fallback-link">If the button does not work, open this link: {{ RESET_LINK }}</div>
</div>
<p>If you did not request this, you can ignore this email.</p>
</div>
<div class="footer">This is an automatic message, please do not reply.</div>
</div>
</div>
</body>
</html>
+114
View File
@@ -0,0 +1,114 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Confirm Your Account</title>
<style>
body {
margin: 0;
padding: 0;
background-color: #f4f6f8;
font-family: Arial, Helvetica, sans-serif;
color: #1f2937;
}
.wrapper {
width: 100%;
table-layout: fixed;
background-color: #f4f6f8;
padding: 24px 12px;
}
.card {
width: 100%;
max-width: 600px;
margin: 0 auto;
background: #ffffff;
border: 1px solid #e5e7eb;
border-radius: 10px;
overflow: hidden;
}
.header {
padding: 20px 24px;
background: #111827;
color: #ffffff;
font-size: 20px;
font-weight: 700;
}
.content {
padding: 24px;
font-size: 16px;
line-height: 1.5;
}
.button-wrap {
margin: 24px 0;
text-align: center;
}
.button {
display: inline-block;
padding: 12px 20px;
background: #0f766e;
color: #ffffff;
text-decoration: none;
border-radius: 8px;
font-weight: 700;
font-size: 15px;
}
.fallback-link {
margin-top: 8px;
font-size: 13px;
color: #4b5563;
word-break: break-all;
}
.footer {
padding: 18px 24px 24px;
font-size: 13px;
line-height: 1.5;
color: #6b7280;
}
@media only screen and (max-width: 600px) {
.wrapper {
padding: 16px 8px;
}
.header,
.content,
.footer {
padding-left: 16px;
padding-right: 16px;
}
}
</style>
</head>
<body>
<div class="wrapper">
<div class="card">
<div class="header">Confirm your account</div>
<div class="content">
<p>Hello,</p>
<p>Thank you for signing up. Please confirm your account by clicking the button below.</p>
<div class="button-wrap">
<a class="button" href="{{ CONFIRMATION_LINK }}" target="_blank" rel="noopener noreferrer">
Confirm Account
</a>
<div class="fallback-link">If the button does not work, open this link: {{ CONFIRMATION_LINK }}</div>
</div>
<p>If you did not create this account, you can ignore this email.</p>
</div>
<div class="footer">
This is an automatic message, please do not reply.
</div>
</div>
</div>
</body>
</html>
+4 -4
View File
@@ -11,7 +11,7 @@
<groupId>br.com.tasknoteapp</groupId>
<artifactId>server</artifactId>
<version>11</version>
<version>14</version>
<name>tasknote-api</name>
<description>Java backend REST API to serve TaskNote frontend client</description>
@@ -181,7 +181,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<version>3.5.4</version>
<version>3.5.5</version>
<executions>
<execution>
<id>integration-tests</id>
@@ -203,7 +203,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.5.4</version>
<version>3.5.5</version>
<configuration>
<argLine>@{argLine} -Xmx1024m</argLine>
<skipTests>${skip.unit.tests}</skipTests>
@@ -329,7 +329,7 @@
<dependency>
<groupId>com.puppycrawl.tools</groupId>
<artifactId>checkstyle</artifactId>
<version>12.1.1</version>
<version>13.3.0</version>
</dependency>
</dependencies>
<configuration>
@@ -7,7 +7,7 @@ import java.util.Optional;
/** This class represents a template for the email change workflow. */
public class MailgunTemplateEmailChanged implements MailgunTemplate {
private String templateName = "email changed";
private String templateName = "email_changed";
private String carbonCopy;
private final Map<String, Object> props;
@@ -6,7 +6,7 @@ import java.util.Map;
/** This class represents a template for the password reset workflow. */
public class MailgunTemplateResetPwd implements MailgunTemplate {
private String templateName = "password reset";
private String templateName = "password_reset";
private final Map<String, Object> props;
public MailgunTemplateResetPwd() {
@@ -6,7 +6,7 @@ import java.util.Map;
/** This class represents a template for the password reset confirmation workflow. */
public class MailgunTemplateResetPwdConfirm implements MailgunTemplate {
private String templateName = "password change confirmation";
private String templateName = "password_change_confirmation";
private final Map<String, Object> props;
public MailgunTemplateResetPwdConfirm() {
@@ -6,7 +6,7 @@ import java.util.Map;
/** This class represents a template for the sign up workflow. */
public class MailgunTemplateSignUp implements MailgunTemplate {
private String templateName = "sign up confirmation";
private String templateName = "sign_up_confirmation";
private final Map<String, Object> props;
public MailgunTemplateSignUp() {
+2 -2
View File
@@ -13,8 +13,8 @@ logging:
mailgun:
api-key: ${MAILGUN_APIKEY:abc123456}
domain: tasknoteapp.dev.br
sender-email: no-reply@tasknoteapp.dev.br
domain: tasknote.darkroasted.vps-kinghost.net
sender-email: no-reply@tasknote.darkroasted.vps-kinghost.net
server:
port: 8585
@@ -45,7 +45,7 @@ class MailgunTemplateTest {
MailgunTemplateEmailChanged emailChanged = new MailgunTemplateEmailChanged();
Assertions.assertNotNull(emailChanged.getName());
Assertions.assertEquals("email changed", emailChanged.getName());
Assertions.assertEquals("email_changed", emailChanged.getName());
Assertions.assertNotNull(emailChanged.getVariables());
Assertions.assertNotNull(emailChanged.getVariableValuesJson());
Assertions.assertFalse(emailChanged.getVariableValuesJson().isBlank());