chessh/front/src/routes/keys.jsx

205 lines
4.6 KiB
JavaScript

import Modal from "react-modal";
import { useEffect, useState, useCallback } from "react";
import { useAuthContext } from "../context/auth_context";
Modal.setAppElement("#root");
const MINIMIZE_KEY_LEN = 40;
const minimizeKey = (key) => {
const n = key.length;
if (n >= MINIMIZE_KEY_LEN) {
const half = Math.floor(MINIMIZE_KEY_LEN / 2);
return key.substring(0, half) + "..." + key.substring(n - half, n);
}
return key;
};
const KeyCard = ({ onDelete, props }) => {
const { id, name, key } = props;
const deleteThisKey = () => {
if (
window.confirm(
"Are you sure? This will close all your current ssh sessions."
)
) {
fetch(`/api/keys/${id}`, {
credentials: "same-origin",
method: "DELETE",
})
.then((r) => r.json())
.then((d) => d.success && onDelete && onDelete());
}
};
return (
<div className="key-card">
<h4 style={{ flex: 1 }}>{name}</h4>
<p style={{ flex: 4 }}>{minimizeKey(key)}</p>
<button
style={{ flex: 0 }}
className="button red"
onClick={deleteThisKey}
>
Delete
</button>
</div>
);
};
const AddKeyButton = ({ onSave }) => {
const [open, setOpen] = useState(false);
const [name, setName] = useState("");
const [key, setKey] = useState("");
const [errors, setErrors] = useState(null);
const setDefaults = () => {
setName("");
setKey("");
setErrors(null);
};
const close = () => {
setDefaults();
setOpen(false);
};
const createKey = () => {
fetch(`/api/player/keys`, {
credentials: "same-origin",
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
key: key.trim(),
name: name.trim(),
}),
})
.then((r) => r.json())
.then((d) => {
if (d.success) {
if (onSave) {
onSave();
}
close();
} else if (d.errors) {
if (typeof d.errors === "object") {
setErrors(
Object.keys(d.errors).map(
(field) => `${field}: ${d.errors[field].join(",")}`
)
);
} else {
setErrors([d.errors]);
}
}
});
};
return (
<div>
<button className="button" onClick={() => setOpen(true)}>
+ Add Key
</button>
<Modal
isOpen={open}
onRequestClose={close}
className="modal"
contentLabel="Add Key"
>
<div>
<h3>Add SSH Key</h3>
<p>
Not sure about this? Check{" "}
<a
href="https://www.ssh.com/academy/ssh/keygen"
target="_blank"
rel="noreferrer"
>
here
</a>{" "}
for help!
</p>
<hr />
<p>Key Name *</p>
<input
value={name}
onChange={(e) => setName(e.target.value)}
required
/>
</div>
<div>
<p>SSH Key *</p>
<textarea
cols={40}
rows={5}
value={key}
onChange={(e) => setKey(e.target.value)}
required
/>
</div>
<div>
{errors && (
<div style={{ color: "red" }}>
{errors.map((error, i) => (
<p key={i}>{error}</p>
))}
</div>
)}
</div>
<div className="flex-end-row">
<button className="button" onClick={createKey}>
Add
</button>
<button className="button red" onClick={close}>
Cancel
</button>
</div>
</Modal>
</div>
);
};
export const Keys = () => {
const {
player: { id: userId },
} = useAuthContext();
const [keys, setKeys] = useState(null);
const refreshKeys = useCallback(
() =>
fetch(`/api/player/${userId}/keys`)
.then((r) => r.json())
.then((keys) => setKeys(keys)),
[userId]
);
useEffect(() => {
if (userId) {
refreshKeys();
}
}, [userId, refreshKeys]);
if (!keys) return <p>Loading...</p>;
if (Array.isArray(keys)) {
return (
<>
<h2>My Keys</h2>
<AddKeyButton onSave={refreshKeys} />
<div className="key-card-collection">
{keys.length ? (
keys.map((key) => (
<KeyCard key={key.id} onDelete={refreshKeys} props={key} />
))
) : (
<p>Looks like you've got no keys, try adding some!</p>
)}
</div>
</>
);
}
};