add member editing

This commit is contained in:
Spectralitree 2020-12-11 00:53:43 +01:00
parent f526a6c40f
commit d30136fba2
9 changed files with 290 additions and 48 deletions

File diff suppressed because one or more lines are too long

54
package-lock.json generated
View File

@ -1299,6 +1299,11 @@
"@hapi/hoek": "^8.3.0" "@hapi/hoek": "^8.3.0"
} }
}, },
"@hookform/resolvers": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/@hookform/resolvers/-/resolvers-1.1.2.tgz",
"integrity": "sha512-I3kYtdj1QX9VkNq4GtC2ZNfoBV13GpoxZCsoA9F3CyAmkQmiznJt6HG8Oc9/R3PLqPrw98FiIzyVs/rG0FnGAA=="
},
"@istanbuljs/load-nyc-config": { "@istanbuljs/load-nyc-config": {
"version": "1.1.0", "version": "1.1.0",
"resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz",
@ -2068,6 +2073,11 @@
"resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz",
"integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=" "integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4="
}, },
"@types/lodash": {
"version": "4.14.165",
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.165.tgz",
"integrity": "sha512-tjSSOTHhI5mCHTy/OOXYIhi2Wt1qcbHmuXD1Ha7q70CgI/I71afO4XtLb/cVexki1oVYchpul/TOuu3Arcdxrg=="
},
"@types/minimatch": { "@types/minimatch": {
"version": "3.0.3", "version": "3.0.3",
"resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz", "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz",
@ -2864,6 +2874,11 @@
"postcss-value-parser": "^4.1.0" "postcss-value-parser": "^4.1.0"
} }
}, },
"autosize": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/autosize/-/autosize-4.0.2.tgz",
"integrity": "sha512-jnSyH2d+qdfPGpWlcuhGiHmqBJ6g3X+8T+iRwFrHPLVcdoGJE/x6Qicm6aDHfTsbgZKxyV8UU/YB2p4cjKDRRA=="
},
"aws-sign2": { "aws-sign2": {
"version": "0.7.0", "version": "0.7.0",
"resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz",
@ -9699,6 +9714,11 @@
"minimist": "^1.2.5" "minimist": "^1.2.5"
} }
}, },
"moment": {
"version": "2.29.1",
"resolved": "https://registry.npmjs.org/moment/-/moment-2.29.1.tgz",
"integrity": "sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ=="
},
"move-concurrently": { "move-concurrently": {
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz", "resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz",
@ -9746,6 +9766,11 @@
"resolved": "https://registry.npmjs.org/nan/-/nan-2.14.2.tgz", "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.2.tgz",
"integrity": "sha512-M2ufzIiINKCuDfBSAUr1vWQ+vuVcA9kqx8JJUsbQi6yf1uGRyb7HfpdfUr5qLXf3B/t8dPvcjhKMmlfnP47EzQ==" "integrity": "sha512-M2ufzIiINKCuDfBSAUr1vWQ+vuVcA9kqx8JJUsbQi6yf1uGRyb7HfpdfUr5qLXf3B/t8dPvcjhKMmlfnP47EzQ=="
}, },
"nanoclone": {
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/nanoclone/-/nanoclone-0.2.1.tgz",
"integrity": "sha512-wynEP02LmIbLpcYw8uBKpcfF6dmg2vcpKqxeH5UcoKEYdExslsdUA4ugFauuaeYdTB76ez6gJW8XAZ6CgkXYxA=="
},
"nanoid": { "nanoid": {
"version": "3.1.20", "version": "3.1.20",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.20.tgz", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.20.tgz",
@ -11873,6 +11898,11 @@
"warning": "^4.0.0" "warning": "^4.0.0"
} }
}, },
"property-expr": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/property-expr/-/property-expr-2.0.4.tgz",
"integrity": "sha512-sFPkHQjVKheDNnPvotjQmm3KD3uk1fWKUN7CrpdbwmUx3CrG3QiM8QpTSimvig5vTXmTvjz7+TDvXOI9+4rkcg=="
},
"proxy-addr": { "proxy-addr": {
"version": "2.0.6", "version": "2.0.6",
"resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.6.tgz", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.6.tgz",
@ -12213,6 +12243,11 @@
"resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz", "resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz",
"integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==" "integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA=="
}, },
"react-moment": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/react-moment/-/react-moment-1.0.0.tgz",
"integrity": "sha512-J4iIiwUT4oZcL7cp2U7naQKbQtqvmzGXXBMg/DLj+Pi7n9EW0VhBRx/1aJ1Tp2poCqTCAPoadLEoUIkReGnNNg=="
},
"react-overlays": { "react-overlays": {
"version": "4.1.1", "version": "4.1.1",
"resolved": "https://registry.npmjs.org/react-overlays/-/react-overlays-4.1.1.tgz", "resolved": "https://registry.npmjs.org/react-overlays/-/react-overlays-4.1.1.tgz",
@ -14698,6 +14733,11 @@
"resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz",
"integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==" "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw=="
}, },
"toposort": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/toposort/-/toposort-2.0.2.tgz",
"integrity": "sha1-riF2gXXRVZ1IvvNUILL0li8JwzA="
},
"tough-cookie": { "tough-cookie": {
"version": "3.0.1", "version": "3.0.1",
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-3.0.1.tgz", "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-3.0.1.tgz",
@ -16688,6 +16728,20 @@
"version": "0.1.0", "version": "0.1.0",
"resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
"integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==" "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q=="
},
"yup": {
"version": "0.32.8",
"resolved": "https://registry.npmjs.org/yup/-/yup-0.32.8.tgz",
"integrity": "sha512-SZulv5FIZ9d5H99EN5tRCRPXL0eyoYxWIP1AacCrjC9d4DfP13J1dROdKGfpfRHT3eQB6/ikBl5jG21smAfCkA==",
"requires": {
"@babel/runtime": "^7.10.5",
"@types/lodash": "^4.14.165",
"lodash": "^4.17.20",
"lodash-es": "^4.17.11",
"nanoclone": "^0.2.1",
"property-expr": "^2.0.4",
"toposort": "^2.0.2"
}
} }
} }
} }

View File

@ -4,22 +4,27 @@
"version": "0.1.0", "version": "0.1.0",
"private": true, "private": true,
"dependencies": { "dependencies": {
"@hookform/resolvers": "^1.1.2",
"@testing-library/jest-dom": "^5.11.4", "@testing-library/jest-dom": "^5.11.4",
"@testing-library/react": "^11.1.0", "@testing-library/react": "^11.1.0",
"@testing-library/user-event": "^12.1.10", "@testing-library/user-event": "^12.1.10",
"autosize": "^4.0.2",
"bootstrap": "^4.5.3", "bootstrap": "^4.5.3",
"discord-markdown": "^2.4.1", "discord-markdown": "^2.4.1",
"moment": "^2.29.1",
"node-fetch": "^2.6.1", "node-fetch": "^2.6.1",
"node-sass": "^4.14.1", "node-sass": "^4.14.1",
"react": "^17.0.1", "react": "^17.0.1",
"react-bootstrap": "^1.4.0", "react-bootstrap": "^1.4.0",
"react-dom": "^17.0.1", "react-dom": "^17.0.1",
"react-icons": "^4.1.0", "react-icons": "^4.1.0",
"react-moment": "^1.0.0",
"react-router-dom": "^5.2.0", "react-router-dom": "^5.2.0",
"react-scripts": "4.0.1", "react-scripts": "4.0.1",
"react-toggle": "^4.1.1", "react-toggle": "^4.1.1",
"use-dark-mode": "^2.3.1", "use-dark-mode": "^2.3.1",
"web-vitals": "^0.2.4" "web-vitals": "^0.2.4",
"yup": "^0.32.8"
}, },
"scripts": { "scripts": {
"predeploy": "npm run build", "predeploy": "npm run build",

View File

@ -2,35 +2,26 @@
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<link rel="icon" href="public/favicon.ico" /> <link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" /> <meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" /> <meta name="theme-color" content="#000000" />
<meta <meta
name="description" name="A web interface for pluralkit."
content="A web interface for pluralkit." content="(This is still a work in progress)"
/> />
<!-- <!--
manifest.json provides metadata used when your web app is installed on a manifest.json provides metadata used when your web app is installed on a
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/ user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
--> -->
<link rel="manifest" href="public/manifest.json" /> <link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<!--
Notice the use of %PUBLIC_URL% in the tags above.
It will be replaced with the URL of the `public` folder during the build.
Only files inside the `public` folder can be referenced from the HTML.
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
<title>pk-webs</title> <title>pk-webs</title>
<link <link rel="stylesheet"
rel="stylesheet"
href="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css"
integrity="sha384-9aIt2nRpC12Uk9gS9baDl411NQApFmC26EwAOH8WgZl5MYYxFfc+NcPb1dKGj7Sk" integrity="sha384-9aIt2nRpC12Uk9gS9baDl411NQApFmC26EwAOH8WgZl5MYYxFfc+NcPb1dKGj7Sk"
crossorigin="anonymous" crossorigin="anonymous" />
/>
<script type="text/javascript"> <script type="text/javascript">
// Single Page Apps for GitHub Pages // Single Page Apps for GitHub Pages
// MIT License // MIT License
@ -59,16 +50,6 @@
<noscript>You need to enable JavaScript to run this app.</noscript> <noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div> <div id="root"></div>
<!--
This HTML file is a template.
If you open it directly in the browser, you will see an empty page.
You can add webfonts, meta tags, or analytics to this file.
The build step will place the bundled scripts into the <body> tag.
To begin the development, run `npm start` or `yarn start`.
To create a production bundle, use `npm run build` or `yarn build`.
-->
</body> </body>
</html> </html>

View File

@ -39,7 +39,7 @@ export default function App() {
setIsLoading(true); setIsLoading(true);
fetch(`${API_URL}s/`,{ fetch(`${API_URL}s/`,{
method: 'get', method: 'GET',
headers: { headers: {
'Authorization': JSON.stringify(localStorage.getItem("token")).slice(1, -1) 'Authorization': JSON.stringify(localStorage.getItem("token")).slice(1, -1)
}}).then ( res => res.json() }}).then ( res => res.json()

View File

@ -1,29 +1,112 @@
import React, { useEffect, useState } from 'react'; import React, { useEffect, useState } from 'react';
import * as BS from 'react-bootstrap' import * as BS from 'react-bootstrap'
import { useForm, Controller } from "react-hook-form";
import autosize from 'autosize';
import moment from 'moment';
import Loading from "./Loading.js";
import API_URL from "../Constants/constants.js";
import defaultAvatar from '../default_discord_avatar.png' import defaultAvatar from '../default_discord_avatar.png'
import { FaUser } from "react-icons/fa"; import { FaUser } from "react-icons/fa";
export default function MemberCard(props) { export default function MemberCard(props) {
const { toHTML } = require('../Functions/discord-parser.js'); const { register, handleSubmit, errors, control } = useForm();
const [ desc, setDesc ] = useState(""); const [member, setMember] = useState(props.member);
const [ displayName, setDisplayName ] = useState("");
const [ birthday, setBirthday ] = useState("");
const [ birthdate, setBirthdate ] = useState("");
const [ pronouns, setPronouns ] = useState("");
const [ avatar, setAvatar ] = useState("");
const [ color, setColor ] = useState(""); const [ color, setColor ] = useState("");
const [ desc, setDesc ] = useState("");
const [ editDesc, setEditDesc ] = useState("");
const member = props.member; const [ editMode, setEditMode ] = useState(false);
const [ privacyMode, setPrivacyMode ] = useState(false);
const [ privacyView, setPrivacyView ] = useState(false);
useEffect(() => { useEffect(() => {
if (member.description) { const { toHTML } = require('../Functions/discord-parser.js');
setDesc(toHTML(member.description));
} else setDesc("(no description)"); if (member.display_name) {
setDisplayName(member.display_name)
} else setDisplayName('')
if (member.birthday) {
setBirthdate(member.birthday)
if (member.birthday.startsWith('0004-')) {
var bday = member.birthday.replace('0004-','');
var bdaymoment = moment(bday, 'MM DD').format('MMM D');
setBirthday(bdaymoment);
} else {
var birthdaymoment = moment(bday, 'YYYY MM DD').format('MMM D, YYYY');
setBirthday(birthdaymoment);
}
} else { setBirthday('');
setBirthdate('');
}
if (member.pronouns) {
setPronouns(member.pronouns)
} else setPronouns('')
if (member.avatar_url) {
setAvatar(member.avatar_url)
} else setAvatar('')
if (member.color) { if (member.color) {
setColor(member.color); setColor(member.color);
} } else { setColor('');
else setColor('transparent'); }
}, [member.description, member.color]); if (member.description) {
setDesc(toHTML(member.description));
setEditDesc(member.description);
} else { setDesc("(no description)");
setEditDesc("");
}
}, [member.description, member.color, member.birthday, member.display_name, member.pronouns, member.avatar_url]);
useEffect(() => {
autosize(document.querySelector('textarea'));
})
const submitEdit = data => {
fetch(`${API_URL}m/${member.id}`,{
method: 'PATCH',
body: JSON.stringify(data),
headers: {
'Content-Type': 'application/json',
'Authorization': JSON.stringify(localStorage.getItem("token")).slice(1, -1)
}}).then (res => res.json()
).then (data => setMember(data), setEditMode(false)
).catch (error => {
console.error(error);
})
}
const submitPrivacy = data => {
fetch(`${API_URL}m/${member.id}`,{
method: 'PATCH',
body: JSON.stringify(data),
headers: {
'Content-Type': 'application/json',
'Authorization': JSON.stringify(localStorage.getItem("token")).slice(1, -1)
}}).then (res => res.json()
).then (data => setMember(data),
setPrivacyMode(false)
).catch (error => {
console.error(error);
})
}
return ( return (
<> <>
@ -34,16 +117,118 @@ export default function MemberCard(props) {
</BS.Accordion.Toggle> </BS.Accordion.Toggle>
<BS.Accordion.Collapse eventKey={member.id}> <BS.Accordion.Collapse eventKey={member.id}>
<BS.Card.Body style={{borderLeft: `5px solid #${color}` }}> <BS.Card.Body style={{borderLeft: `5px solid #${color}` }}>
{ editMode ?
<BS.Form onSubmit={handleSubmit(submitEdit)}>
<BS.Form.Row>
<BS.Col className="mb-lg-2" xs={12} lg={3}>
<BS.Form.Label>Name:</BS.Form.Label>
<Controller as={<BS.Form.Control placeholder={member.name}/>} name="name" control={control}/>
</BS.Col>
<BS.Col className="mb-lg-2" xs={12} lg={3}>
<BS.Form.Label>AKA: </BS.Form.Label>
<Controller as={<BS.Form.Control placeholder={displayName}/>} name="display_name" control={control}/>
</BS.Col>
<BS.Col className="mb-lg-2" xs={12} lg={3}>
<BS.Form.Label>Birthday:</BS.Form.Label>
<Controller as={<BS.Form.Control placeholder={birthdate} pattern="/^\d{4}(0[1-9]|1[012])(0[1-9]|[12][0-9]|3[01])$/g"/>} name="birthday" control={control}/>
<BS.Form.Text>(YYYY-MM-DD)</BS.Form.Text>
</BS.Col>
<BS.Col className="mb-lg-2" xs={12} lg={3}>
<BS.Form.Label>Pronouns:</BS.Form.Label>
<Controller as={<BS.Form.Control placeholder={pronouns}/>} name="pronouns" control={control}/>
</BS.Col>
<BS.Col className="mb-lg-2" xs={12} lg={3}>
<BS.Form.Label>Avatar url:</BS.Form.Label>
<Controller as={<BS.Form.Control type="url" placeholder={avatar}/>} name="avatar_url" control={control} />
</BS.Col>
<BS.Col className="mb-lg-2" xs={12} lg={3}>
<BS.Form.Label>Color:</BS.Form.Label>
<Controller as={<BS.Form.Control placeholder={color} pattern="/[A-Fa-f0-9]{6}$/g"/>} name="color" control={control}/>
<BS.Form.Text>(hexcode)</BS.Form.Text>
</BS.Col>
</BS.Form.Row>
<BS.Form.Group className="mt-3">
<BS.Form.Label>Description:</BS.Form.Label>
<Controller as={<BS.Form.Control maxLength="1000" as="textarea" />} name="description" control={control} defaultValue={editDesc}/>
</BS.Form.Group>
<BS.Button variant="light" onClick={() => setEditMode(false)}>Cancel</BS.Button> <BS.Button variant="primary" type="submit">Submit</BS.Button>
</BS.Form>
:
<>
<BS.Row> <BS.Row>
<BS.Col className="mb-lg-3" xs={12} lg={3}><b>ID:</b> {member.id}</BS.Col> <BS.Col className="mb-lg-3" xs={12} lg={3}><b>ID:</b> {member.id}</BS.Col>
{ member.display_name ? <BS.Col className="mb-lg-3" xs={12} lg={3}><b>AKA: </b>{member.display_name}</BS.Col> : "" } { member.display_name ? <BS.Col className="mb-lg-3" xs={12} lg={3}><b>AKA: </b>{displayName}</BS.Col> : "" }
{ member.birthday ? <BS.Col className="mb-lg-3" xs={12} lg={3}><b>Birthday:</b> {member.birthday}</BS.Col> : "" } { member.birthday ? <BS.Col className="mb-lg-3" xs={12} lg={3}><b>Birthday:</b> {birthday}</BS.Col> : "" }
{ member.pronouns ? <BS.Col className="mb-lg-3" xs={12} lg={3}><b>Pronouns:</b> {member.pronouns}</BS.Col> : "" } { member.pronouns ? <BS.Col className="mb-lg-3" xs={12} lg={3}><b>Pronouns:</b> {pronouns}</BS.Col> : "" }
{ member.color ? <BS.Col className="mb-lg-3" xs={12} lg={3}><b>Color:</b> #{member.color}</BS.Col> : "" } { member.color ? <BS.Col className="mb-lg-3" xs={12} lg={3}><b>Color:</b> {color}</BS.Col> : "" }
{ privacyView ? "" : <BS.Col className="mb-lg-3" xs={12} lg={3}><b>Privacy:</b> <BS.Button variant="light" size="sm" onClick={() => setPrivacyView(true)}>View</BS.Button></BS.Col> }
</BS.Row> </BS.Row>
{ privacyMode ? <BS.Form onSubmit={handleSubmit(submitPrivacy)}>
<hr/>
<h5>Editing privacy settings</h5>
<BS.Form.Row>
<BS.Col className="mb-lg-2" xs={12} lg={3}>
<BS.Form.Label>Visibility:</BS.Form.Label>
<BS.Form.Control name="visibility" as="select" ref={register}>
<option>public</option>
<option>private</option>
</BS.Form.Control>
</BS.Col>
<BS.Col className="mb-lg-2" xs={12} lg={3}>
<BS.Form.Label>Name:</BS.Form.Label>
<BS.Form.Control name="name_privacy" as="select" ref={register}>
<option>public</option>
<option>private</option>
</BS.Form.Control>
</BS.Col>
<BS.Col className="mb-lg-2" xs={12} lg={3}>
<BS.Form.Label>Description:</BS.Form.Label>
<BS.Form.Control name="description_privacy" as="select" ref={register}>
<option>public</option>
<option>private</option>
</BS.Form.Control>
</BS.Col>
<BS.Col className="mb-lg-2" xs={12} lg={3}>
<BS.Form.Label>Birthday:</BS.Form.Label>
<BS.Form.Control name="birthday_privacy" as="select" ref={register}>
<option>public</option>
<option>private</option>
</BS.Form.Control>
</BS.Col>
<BS.Col className="mb-lg-2" xs={12} lg={3}>
<BS.Form.Label>Pronouns:</BS.Form.Label>
<BS.Form.Control name="pronoun_privacy" as="select" ref={register}>
<option>public</option>
<option>private</option>
</BS.Form.Control>
</BS.Col>
<BS.Col className="mb-lg-2" xs={12} lg={3}>
<BS.Form.Label>Meta:</BS.Form.Label>
<BS.Form.Control name="metadata_privacy" as="select" ref={register}>
<option>public</option>
<option>private</option>
</BS.Form.Control>
</BS.Col>
</BS.Form.Row>
<BS.Button variant="light" onClick={() => setPrivacyMode(false)}>Cancel</BS.Button> <BS.Button variant="primary" type="submit">Submit</BS.Button>
<hr/>
</BS.Form> : privacyView ? <><hr/>
<h5>Viewing privacy settings</h5>
<BS.Row>
<BS.Col className="mb-lg-3" xs={12} lg={3}><b>Visibility:</b> {member.visibility}</BS.Col>
<BS.Col className="mb-lg-3" xs={12} lg={3}><b>Name: </b>{member.name_privacy}</BS.Col>
<BS.Col className="mb-lg-3" xs={12} lg={3}><b>Description:</b> {member.description_privacy}</BS.Col>
<BS.Col className="mb-lg-3" xs={12} lg={3}><b>Birthday:</b> {member.birthday_privacy}</BS.Col>
<BS.Col className="mb-lg-3" xs={12} lg={3}><b>Pronouns:</b> {member.pronoun_privacy}</BS.Col>
<BS.Col className="mb-lg-3" xs={12} lg={3}><b>Meta:</b> {member.metadata_privacy}</BS.Col>
</BS.Row>
<BS.Button variant="light" onClick={() => setPrivacyView(false)}>Cancel</BS.Button> <BS.Button variant="primary" onClick={() => setPrivacyMode(true)}>Edit</BS.Button>
<hr/></> : "" }
<p><b>Description:</b></p> <p><b>Description:</b></p>
<p dangerouslySetInnerHTML={{__html: desc}}></p> <p dangerouslySetInnerHTML={{__html: desc}}></p>
</BS.Card.Body> { privacyMode ? "" : privacyView ? "" : <BS.Button variant="light" onClick={() => setEditMode(true)}>Edit</BS.Button>}
</> } </BS.Card.Body>
</BS.Accordion.Collapse> </BS.Accordion.Collapse>
</> </>
) )

View File

@ -1,4 +1,3 @@
import react from 'react';
import * as BS from 'react-bootstrap' import * as BS from 'react-bootstrap'
import useDarkMode from 'use-dark-mode'; import useDarkMode from 'use-dark-mode';
import Toggle from 'react-toggle' import Toggle from 'react-toggle'

View File

@ -6,12 +6,12 @@ import defaultAvatar from '../default_discord_avatar.png'
export default function System(props) { export default function System(props) {
const { toHTML } = require('../Functions/discord-parser.js');
const [ desc, setDesc ] = useState(""); const [ desc, setDesc ] = useState("");
const user = JSON.parse(localStorage.getItem("user")); const user = JSON.parse(localStorage.getItem("user"));
useEffect(() => { useEffect(() => {
const { toHTML } = require('../Functions/discord-parser.js');
if (user.description) { if (user.description) {
setDesc(toHTML(user.description)); setDesc(toHTML(user.description));
} else setDesc("(no description)"); } else setDesc("(no description)");

View File

@ -23,11 +23,11 @@
transition: background-color 0.3s ease; transition: background-color 0.3s ease;
} }
.navbar-light { .navbar {
background-color: $gray-100; background-color: $gray-100;
} }
.dark-mode .navbar-light { .dark-mode .navbar {
color: $gray-100; color: $gray-100;
background-color: $gray-900; background-color: $gray-900;
transition: background-color 0.3s ease; transition: background-color 0.3s ease;
@ -44,12 +44,30 @@
transition: background-color 0.3s ease; transition: background-color 0.3s ease;
} }
.dark-mode .form-control:disabled {
color: $gray-200;
border-color: #191c1f;
background-color: $gray-900;
transition: background-color 0.3s ease;
}
.dark-mode .form-control:focus { .dark-mode .form-control:focus {
color: $gray-200; color: $gray-200;
border-color: #191c1f; border-color: #191c1f;
background-color: $gray-900; background-color: $gray-900;
} }
.dark-mode .btn-light {
background-color: $gray-900;
border-color: #191c1f;
color: $gray-100;
}
.dark-mode .btn-light:focus {
background-color: $gray-900;
border-color: #191c1f;
color: $gray-100;
}
.dark-mode .alert-danger { .dark-mode .alert-danger {
color: $white; color: $white;