first commit

This commit is contained in:
2025-04-24 13:11:28 +08:00
commit ff9c54d5e4
5960 changed files with 834111 additions and 0 deletions

View File

@@ -0,0 +1,87 @@
import PropTypes from 'prop-types'
import { postJSON } from '../../../../../frontend/js/infrastructure/fetch-json'
function RegisterForm({
setRegistrationSuccess,
setEmails,
setRegisterError,
setFailedEmails,
}) {
function handleRegister(event) {
event.preventDefault()
const formData = new FormData(event.target)
const formDataAsEntries = formData.entries()
const formDataAsObject = Object.fromEntries(formDataAsEntries)
const emailString = formDataAsObject.email
setRegistrationSuccess(false)
setRegisterError(false)
setEmails([])
registerGivenUsers(parseEmails(emailString))
}
async function registerGivenUsers(emails) {
const registeredEmails = []
const failingEmails = []
for (const email of emails) {
try {
const result = await registerUser(email)
registeredEmails.push(result)
} catch {
failingEmails.push(email)
}
}
if (registeredEmails.length > 0) setRegistrationSuccess(true)
if (failingEmails.length > 0) {
setRegisterError(true)
setFailedEmails(failingEmails)
}
setEmails(registeredEmails)
}
function registerUser(email) {
const options = { email }
const url = `/admin/register`
return postJSON(url, { body: options })
}
return (
<form onSubmit={handleRegister}>
<div className="row">
<div className="col-md-4 col-xs-8">
<input
className="form-control"
name="email"
type="text"
placeholder="jane@example.com, joe@example.com"
aria-label="emails to register"
aria-describedby="input-details"
/>
<p id="input-details" className="sr-only">
Enter the emails you would like to register and separate them using
commas
</p>
</div>
<div className="col-md-8 col-xs-4">
<button className="btn btn-primary">Register</button>
</div>
</div>
</form>
)
}
function parseEmails(emailsText) {
const regexBySpaceOrComma = /[\s,]+/
let emails = emailsText.split(regexBySpaceOrComma)
emails.map(email => email.trim())
emails = emails.filter(email => email.indexOf('@') !== -1)
return emails
}
RegisterForm.propTypes = {
setRegistrationSuccess: PropTypes.func,
setEmails: PropTypes.func,
setRegisterError: PropTypes.func,
setFailedEmails: PropTypes.func,
}
export default RegisterForm

View File

@@ -0,0 +1,92 @@
import { useState } from 'react'
import PropTypes from 'prop-types'
import RegisterForm from './register-form'
function UserActivateRegister() {
const [emails, setEmails] = useState([])
const [failedEmails, setFailedEmails] = useState([])
const [registerError, setRegisterError] = useState(false)
const [registrationSuccess, setRegistrationSuccess] = useState(false)
return (
<div className="row">
<div className="col-md-12">
<div className="card">
<div className="page-header">
<h1> Register New Users</h1>
</div>
<RegisterForm
setRegistrationSuccess={setRegistrationSuccess}
setEmails={setEmails}
setRegisterError={setRegisterError}
setFailedEmails={setFailedEmails}
/>
{registerError ? (
<UserActivateError failedEmails={failedEmails} />
) : null}
{registrationSuccess ? (
<>
<SuccessfulRegistrationMessage />
<hr />
<DisplayEmailsList emails={emails} />
</>
) : null}
</div>
</div>
</div>
)
}
function UserActivateError({ failedEmails }) {
return (
<div className="row-spaced text-danger">
<p>Sorry, an error occured, failed to register these emails.</p>
{failedEmails.map(email => (
<p key={email}>{email}</p>
))}
</div>
)
}
function SuccessfulRegistrationMessage() {
return (
<div className="row-spaced text-success">
<p>We've sent out welcome emails to the registered users.</p>
<p>
You can also manually send them URLs below to allow them to reset their
password and log in for the first time.
</p>
<p>
(Password reset tokens will expire after one week and the user will need
registering again).
</p>
</div>
)
}
function DisplayEmailsList({ emails }) {
return (
<table className="table table-striped ">
<tbody>
<tr>
<th>Email</th>
<th>Set Password Url</th>
</tr>
{emails.map(user => (
<tr key={user.email}>
<td>{user.email}</td>
<td style={{ wordBreak: 'break-all' }}>{user.setNewPasswordUrl}</td>
</tr>
))}
</tbody>
</table>
)
}
DisplayEmailsList.propTypes = {
emails: PropTypes.array,
}
UserActivateError.propTypes = {
failedEmails: PropTypes.array,
}
export default UserActivateRegister