Fix autocomplete, create new timer

This commit is contained in:
Elizabeth Hunt 2023-04-04 14:07:05 -06:00
parent ea279b7295
commit a862ad4d3b
Signed by: simponic
GPG Key ID: 52B3774857EB24B1
6 changed files with 176 additions and 23 deletions

View File

@ -11,6 +11,7 @@
"chota": "^0.9.2",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-mentions": "^4.4.7",
"react-modal": "^3.16.1",
"react-router-dom": "^6.10.0",
"socket.io-client": "^4.6.1"
@ -330,6 +331,14 @@
"@babel/core": "^7.0.0-0"
}
},
"node_modules/@babel/runtime": {
"version": "7.4.5",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.4.5.tgz",
"integrity": "sha512-TuI4qpWZP6lGOGIuGWtp9sPluqYICmbk8T/1vpSysqJxRPkudh/ofFWyqdcMsDf2s7KvDL4/YHgKyvcS3g9CJQ==",
"dependencies": {
"regenerator-runtime": "^0.13.2"
}
},
"node_modules/@babel/template": {
"version": "7.20.7",
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.20.7.tgz",
@ -1109,6 +1118,14 @@
"node": ">=4"
}
},
"node_modules/invariant": {
"version": "2.2.4",
"resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz",
"integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==",
"dependencies": {
"loose-envify": "^1.0.0"
}
},
"node_modules/is-core-module": {
"version": "2.11.0",
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz",
@ -1298,6 +1315,21 @@
"resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz",
"integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA=="
},
"node_modules/react-mentions": {
"version": "4.4.7",
"resolved": "https://registry.npmjs.org/react-mentions/-/react-mentions-4.4.7.tgz",
"integrity": "sha512-VNriu2h/uOB+RS0mwZgPG2Vf+UtdDvRh5zbXa2TNc1WqacKuNDgTdhlbo9LEOZRBxRzIeTUYQmYJ7p9M9rDHqQ==",
"dependencies": {
"@babel/runtime": "7.4.5",
"invariant": "^2.2.4",
"prop-types": "^15.5.8",
"substyle": "^9.1.0"
},
"peerDependencies": {
"react": ">=16.8.3",
"react-dom": ">=16.8.3"
}
},
"node_modules/react-modal": {
"version": "3.16.1",
"resolved": "https://registry.npmjs.org/react-modal/-/react-modal-3.16.1.tgz",
@ -1355,6 +1387,11 @@
"react-dom": ">=16.8"
}
},
"node_modules/regenerator-runtime": {
"version": "0.13.11",
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz",
"integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg=="
},
"node_modules/resolve": {
"version": "1.22.1",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz",
@ -1440,6 +1477,18 @@
"node": ">=0.10.0"
}
},
"node_modules/substyle": {
"version": "9.4.1",
"resolved": "https://registry.npmjs.org/substyle/-/substyle-9.4.1.tgz",
"integrity": "sha512-VOngeq/W1/UkxiGzeqVvDbGDPM8XgUyJVWjrqeh+GgKqspEPiLYndK+XRcsKUHM5Muz/++1ctJ1QCF/OqRiKWA==",
"dependencies": {
"@babel/runtime": "^7.3.4",
"invariant": "^2.2.4"
},
"peerDependencies": {
"react": ">=16.8.3"
}
},
"node_modules/supports-color": {
"version": "5.5.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",

View File

@ -12,6 +12,7 @@
"chota": "^0.9.2",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-mentions": "^4.4.7",
"react-modal": "^3.16.1",
"react-router-dom": "^6.10.0",
"socket.io-client": "^4.6.1"

View File

@ -1,36 +1,55 @@
import Modal from "react-modal";
import { useEffect, useState } from "react";
import { Mention, MentionsInput } from "react-mentions";
import { useAuthContext } from "../context/authContext";
const customStyles = {
content: {
top: "50%",
left: "50%",
right: "auto",
bottom: "auto",
marginRight: "-50%",
transform: "translate(-50%, -50%)",
width: "40vw",
maxWidth: "800px",
},
};
import mentionStyles from "../styles/mention";
import modalStyles from "../styles/modal";
Modal.setAppElement("#root");
export default function TimerHeader({ friends, selected, onSelect }) {
const [modalOpen, setModalOpen] = useState(false);
const [newTimerName, setNewTimerName] = useState("");
const [errors, setErrors] = useState([]);
const { friendName, setSignedIn } = useAuthContext();
const logout = () => {
fetch("/api/auth/logout").then(() => setSignedIn(false));
};
const createTimer = (e) => {
e.preventDefault();
fetch("/api/timers", {
method: "POST",
body: JSON.stringify({
name: newTimerName.replaceAll(
/\[@[\w\d\s]+\]\((\@<\d+>)\)/g,
(_match, atId) => atId
),
}),
headers: {
"Content-Type": "application/json",
},
})
.then((r) => r.json())
.then((r) => {
if (r.message) {
setErrors([r.message]);
return;
}
setNewTimerName("");
setErrors([]);
setModalOpen(false);
});
};
return (
<>
<Modal
isOpen={modalOpen}
onRequestClose={() => setModalOpen(false)}
style={customStyles}
style={modalStyles}
>
<div id="createTimerModal">
<div>
@ -42,13 +61,35 @@ export default function TimerHeader({ friends, selected, onSelect }) {
marginBottom: "1rem",
}}
>
<span>New Timer</span>
<h4 style={{ margin: "none" }}>New Timer</h4>
<a onClick={() => setModalOpen(false)} className="button outline">
&times;
</a>
</div>
<div>
<form>
<form onSubmit={createTimer}>
<MentionsInput
style={mentionStyles}
value={newTimerName}
onChange={(e) => setNewTimerName(e.target.value)}
>
<Mention
data={friends.map(({ id, name }) => ({
id: `@<${id}>`,
display: `@${name}`,
}))}
/>
</MentionsInput>
{errors.length ? (
errors.map((error, i) => (
<div key={i} className="text-error">
{error}
</div>
))
) : (
<></>
)}
<button type="submit">Add</button>
</form>
</div>

View File

@ -31,9 +31,11 @@ export default function Login() {
const getTokenFormSubmission = async (e) => {
e.preventDefault();
const { error, token } = await requestTokenSubmit(e.target.name.value);
if (error) {
setErrors([error]);
const { error, message, token } = await requestTokenSubmit(
e.target.name.value
);
if (error && message) {
setErrors([message]);
return;
}
setErrors([]);
@ -42,9 +44,8 @@ export default function Login() {
const signTokenFormSubmission = async (e) => {
e.preventDefault();
const { error, token, expiration, friend } = await submitSignedToken(
e.target.signature.value
);
const { error, message, token, expiration, friend } =
await submitSignedToken(e.target.signature.value);
if (token) {
setSignedIn(true);
@ -55,7 +56,9 @@ export default function Login() {
return;
}
setErrors([error]);
if (error & message) {
setErrors([message]);
}
};
if (signedIn) {

View File

@ -0,0 +1,47 @@
export default {
control: {
backgroundColor: "#fff",
fontSize: 16,
// fontWeight: 'normal',
},
"&multiLine": {
control: {
fontFamily: "monospace",
minHeight: 63,
},
highlighter: {
padding: 9,
border: "1px solid transparent",
},
input: {
padding: 9,
border: "1px solid silver",
},
},
"&singleLine": {
display: "inline-block",
width: 180,
highlighter: {
padding: 1,
border: "2px inset transparent",
},
input: {
padding: 1,
border: "2px inset",
},
},
suggestions: {
list: {
backgroundColor: "white",
border: "1px solid rgba(0,0,0,0.15)",
fontSize: 16,
},
item: {
padding: "5px 15px",
borderBottom: "1px solid rgba(0,0,0,0.15)",
"&focused": {
backgroundColor: "#cee4e5",
},
},
},
};

View File

@ -0,0 +1,12 @@
export default {
content: {
top: "50%",
left: "50%",
right: "auto",
bottom: "auto",
marginRight: "-50%",
transform: "translate(-50%, -50%)",
width: "40vw",
maxWidth: "800px",
},
};