166 lines
3.5 KiB
JavaScript
166 lines
3.5 KiB
JavaScript
import React, { useEffect } from "react";
|
|
import PropTypes from "prop-types";
|
|
import { useDispatch, useSelector } from "react-redux";
|
|
import { UAParser } from "ua-parser-js";
|
|
import { format } from "timeago.js";
|
|
|
|
import { getUserTokens, deleteUserToken } from "../../actions/users";
|
|
|
|
export const UserTokens = () => {
|
|
const dispatch = useDispatch();
|
|
const tokens = useSelector((state) => state.user.tokens);
|
|
|
|
useEffect(() => {
|
|
dispatch(getUserTokens());
|
|
}, [dispatch]);
|
|
|
|
return (
|
|
<div className="row">
|
|
<div className="col-12">
|
|
{tokens.map((token, index) => (
|
|
<Token key={index} token={token} />
|
|
))}
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
const Token = ({ token }) => {
|
|
const ua = UAParser(token.user_agent);
|
|
const lastUsed = new Date(token.last_used);
|
|
const createdAt = new Date(token.created_at);
|
|
|
|
return (
|
|
<div className="card mt-3">
|
|
<div className="card-header">
|
|
<h4>
|
|
<Logo {...ua} />
|
|
<span className="ml-3">{token.description}</span>
|
|
<Actions token={token.token} />
|
|
</h4>
|
|
</div>
|
|
<div className="card-body row">
|
|
<div className="col-12 col-md-6">
|
|
<p>Last IP: {token.ip}</p>
|
|
<p>Last used: {isNaN(lastUsed) ? "-" : format(lastUsed)}</p>
|
|
<p>Created: {isNaN(createdAt) ? "-" : format(createdAt)}</p>
|
|
</div>
|
|
<div className="col-12 col-md-6">
|
|
<p>
|
|
Device: <Device {...ua.device} />
|
|
</p>
|
|
<p>
|
|
OS: <OS {...ua.os} />
|
|
</p>
|
|
<p>
|
|
Browser: <Browser {...ua.browser} />
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|
|
Token.propTypes = {
|
|
token: PropTypes.object.isRequired,
|
|
};
|
|
|
|
const Actions = ({ token }) => {
|
|
const dispatch = useDispatch();
|
|
|
|
const handleClick = () => {
|
|
dispatch(deleteUserToken(token));
|
|
};
|
|
|
|
return (
|
|
<span
|
|
className="fa fa-trash fa-lg pull-right clickable"
|
|
onClick={handleClick}
|
|
></span>
|
|
);
|
|
};
|
|
Actions.propTypes = {
|
|
token: PropTypes.string.isRequired,
|
|
};
|
|
|
|
const Logo = ({ ua, device, browser }) => {
|
|
var className;
|
|
if (ua === "canape-cli") {
|
|
className = "terminal";
|
|
} else if (device.type == "mobile") {
|
|
className = "mobile";
|
|
} else {
|
|
switch (browser.name) {
|
|
case "Chrome":
|
|
case "chrome":
|
|
className = "chrome";
|
|
break;
|
|
case "Safari":
|
|
case "safari":
|
|
className = "safari";
|
|
break;
|
|
case "Firefox":
|
|
case "firefox":
|
|
className = "firefox";
|
|
break;
|
|
default:
|
|
className = "question";
|
|
break;
|
|
}
|
|
}
|
|
|
|
return <span className={`fa fa-${className}`}></span>;
|
|
};
|
|
Logo.propTypes = {
|
|
ua: PropTypes.string,
|
|
device: PropTypes.object,
|
|
browser: PropTypes.object,
|
|
};
|
|
|
|
const OS = ({ name, version }) => {
|
|
var osName = "-";
|
|
|
|
if (name !== undefined) {
|
|
osName = name;
|
|
|
|
if (version !== undefined) {
|
|
osName += " " + version;
|
|
}
|
|
}
|
|
|
|
return <span> {osName}</span>;
|
|
};
|
|
OS.propTypes = {
|
|
name: PropTypes.string,
|
|
version: PropTypes.string,
|
|
};
|
|
|
|
const Device = ({ model }) => {
|
|
var deviceName = "-";
|
|
|
|
if (model !== undefined) {
|
|
deviceName = model;
|
|
}
|
|
|
|
return <span> {deviceName}</span>;
|
|
};
|
|
Device.propTypes = {
|
|
model: PropTypes.string,
|
|
};
|
|
|
|
const Browser = ({ name, version }) => {
|
|
var browserName = "-";
|
|
if (name !== undefined) {
|
|
browserName = name;
|
|
|
|
if (version !== undefined) {
|
|
browserName += " - " + version;
|
|
}
|
|
}
|
|
|
|
return <span> {browserName}</span>;
|
|
};
|
|
Browser.propTypes = {
|
|
name: PropTypes.string,
|
|
version: PropTypes.string,
|
|
};
|