mirror of
https://github.com/koodiklinikka/koodiklinikka.fi.git
synced 2026-01-26 03:14:08 +00:00
213 lines
5.1 KiB
TypeScript
213 lines
5.1 KiB
TypeScript
import request from "axios";
|
|
import React from "react";
|
|
import classSet from "classnames";
|
|
import api from "../api";
|
|
import Loader from "../Loader";
|
|
|
|
type Props = {
|
|
onSignupSuccess: () => void;
|
|
};
|
|
|
|
type State = {
|
|
error: boolean;
|
|
errors: string[];
|
|
fields: {
|
|
name: string;
|
|
email: string;
|
|
handle: string;
|
|
address: string;
|
|
postcode: string;
|
|
city: string;
|
|
};
|
|
sending: boolean;
|
|
pristineFields: string[];
|
|
};
|
|
|
|
const fieldNameTranslations = {
|
|
address: { fi: "Osoite" },
|
|
city: { fi: "Paikkakunta" },
|
|
email: { fi: "Sähköpostiosoite" },
|
|
handle: { fi: "Slack-käyttäjätunnus " },
|
|
name: { fi: "Koko nimi " },
|
|
postcode: { fi: "Postinumero" },
|
|
};
|
|
|
|
const mailValidateRe =
|
|
/^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
|
|
|
|
function validateEmail(email) {
|
|
return mailValidateRe.test(email);
|
|
}
|
|
|
|
function getUserInfo(state) {
|
|
return state.fields;
|
|
}
|
|
|
|
export default class MembershipInfoForm extends React.Component<Props, State> {
|
|
constructor(props: Props) {
|
|
super(props);
|
|
this.setState({
|
|
fields: {
|
|
address: "",
|
|
city: "",
|
|
email: "",
|
|
handle: "",
|
|
name: "",
|
|
postcode: "",
|
|
},
|
|
sending: false,
|
|
pristineFields: Object.keys(this.state.fields),
|
|
});
|
|
}
|
|
|
|
onSubmit = async () => {
|
|
this.setState({
|
|
sending: true,
|
|
error: null,
|
|
});
|
|
|
|
try {
|
|
await request.post(api("membership"), {
|
|
userInfo: getUserInfo(this.state),
|
|
});
|
|
this.setState({ sending: false });
|
|
this.props.onSignupSuccess();
|
|
} catch (err) {
|
|
this.setState({ error: err, sending: false });
|
|
}
|
|
};
|
|
|
|
onChange = (e) => {
|
|
const name = e.target.name;
|
|
if (e.target.value === this.state[name]) {
|
|
return;
|
|
}
|
|
|
|
this.setState({
|
|
fields: {
|
|
...this.state.fields,
|
|
[name]: e.target.value,
|
|
},
|
|
pristineFields: this.state.pristineFields.filter(
|
|
(fieldName) => fieldName !== name
|
|
),
|
|
errors: [],
|
|
});
|
|
};
|
|
|
|
getDataErrors = () => {
|
|
const foundErrors = [];
|
|
|
|
Object.keys(this.state.fields).forEach((fieldName) => {
|
|
if (!this.state[fieldName]) {
|
|
foundErrors.push({ field: fieldName, type: "missing" });
|
|
}
|
|
});
|
|
|
|
if (this.state.fields.email && !validateEmail(this.state.fields.email)) {
|
|
foundErrors.push({ field: "email", type: "invalid" });
|
|
}
|
|
|
|
return foundErrors;
|
|
};
|
|
|
|
render() {
|
|
const inputErrors = this.getDataErrors();
|
|
|
|
const formClasses = classSet({
|
|
form: true,
|
|
"membership-form": true,
|
|
"has-error": inputErrors.length !== 0 || this.state.error,
|
|
sending: this.state.sending,
|
|
});
|
|
|
|
function getErrorMessage(err) {
|
|
let feedbackText;
|
|
|
|
const fieldName = fieldNameTranslations[err.field].fi;
|
|
if (err.type === "missing") {
|
|
feedbackText = `${fieldName} on pakollinen.`;
|
|
} else if (err.type === "invalid") {
|
|
feedbackText = `${fieldName} on virheellinen.`;
|
|
}
|
|
|
|
return (
|
|
<div key={err.field} className="form--message">
|
|
{feedbackText}
|
|
</div>
|
|
);
|
|
}
|
|
|
|
/* generate error messages */
|
|
const visibleErrors = inputErrors.filter(
|
|
(error) => this.state.pristineFields.indexOf(error.field) === -1
|
|
);
|
|
|
|
const fieldsWithErrors = visibleErrors.map(({ field }) => field);
|
|
|
|
const inputFields = Object.keys(this.state.fields).map((fieldName) => {
|
|
const inputClasses = classSet({
|
|
input: true,
|
|
"has-error": fieldsWithErrors.includes(fieldName),
|
|
half: fieldName === "city" || fieldName === "postcode",
|
|
left: fieldName === "postcode",
|
|
});
|
|
|
|
function showsErrorFor(field) {
|
|
if (fieldName === "city") {
|
|
return false;
|
|
}
|
|
|
|
return (
|
|
field === fieldName || (fieldName === "postcode" && field === "city")
|
|
);
|
|
}
|
|
|
|
return (
|
|
<span key={fieldName}>
|
|
<input
|
|
className={inputClasses}
|
|
type={fieldName === "email" ? "email" : "text"}
|
|
name={fieldName}
|
|
placeholder={fieldNameTranslations[fieldName].fi}
|
|
value={this.state[fieldName]}
|
|
onChange={this.onChange}
|
|
/>
|
|
{visibleErrors
|
|
.filter(({ field }) => showsErrorFor(field))
|
|
.map(getErrorMessage)}
|
|
</span>
|
|
);
|
|
});
|
|
if (this.state.sending) {
|
|
return (
|
|
<div className="membership-form__loader">
|
|
<Loader />
|
|
</div>
|
|
);
|
|
}
|
|
return (
|
|
<div>
|
|
<h3>Liity jäseneksi</h3>
|
|
<form className={formClasses}>
|
|
{inputFields}
|
|
{this.state.error && (
|
|
<div className="form--message">
|
|
Jotain meni pieleen! Ota yhteyttä info@koodiklinikka.fi
|
|
</div>
|
|
)}
|
|
<br />
|
|
<button
|
|
type="button"
|
|
disabled={inputErrors.length !== 0}
|
|
className="btn btn__submit"
|
|
onClick={this.onSubmit}
|
|
>
|
|
Liity jäseneksi
|
|
</button>
|
|
</form>
|
|
</div>
|
|
);
|
|
}
|
|
}
|