From f501bdc2be0ee176734a2f8c141ee1fdcb213164 Mon Sep 17 00:00:00 2001 From: Spectralitree Date: Mon, 14 Dec 2020 22:25:35 +0100 Subject: [PATCH] Add public profiles --- .eslintcache | 2 +- src/App.js | 32 +++++++--- src/Components/Profile.js | 97 ++++++++++++++++++++++++---- src/Components/ProfileCard.js | 100 +++++++++++++++++++++++++++++ src/Components/ProfileList.js | 117 ++++++++++++++++++++++++++++++++++ src/Components/Public.js | 47 ++++++++++++++ 6 files changed, 375 insertions(+), 20 deletions(-) create mode 100644 src/Components/ProfileCard.js create mode 100644 src/Components/ProfileList.js create mode 100644 src/Components/Public.js diff --git a/.eslintcache b/.eslintcache index e22bf8dc..51775ada 100644 --- a/.eslintcache +++ b/.eslintcache @@ -1 +1 @@ -[{"C:\\Users\\Fleur\\Desktop\\website projects etc\\pk-web\\src\\index.js":"1","C:\\Users\\Fleur\\Desktop\\website projects etc\\pk-web\\src\\History.js":"2","C:\\Users\\Fleur\\Desktop\\website projects etc\\pk-web\\src\\App.js":"3","C:\\Users\\Fleur\\Desktop\\website projects etc\\pk-web\\src\\Components\\Dash.js":"4","C:\\Users\\Fleur\\Desktop\\website projects etc\\pk-web\\src\\Constants\\constants.js":"5","C:\\Users\\Fleur\\Desktop\\website projects etc\\pk-web\\src\\Components\\Loading.js":"6","C:\\Users\\Fleur\\Desktop\\website projects etc\\pk-web\\src\\Components\\System.js":"7","C:\\Users\\Fleur\\Desktop\\website projects etc\\pk-web\\src\\Components\\Memberlist.js":"8","C:\\Users\\Fleur\\Desktop\\website projects etc\\pk-web\\src\\Components\\MemberCard.js":"9","C:\\Users\\Fleur\\Desktop\\website projects etc\\pk-web\\src\\Functions\\discord-parser.js":"10","C:\\Users\\Fleur\\Desktop\\website projects etc\\pk-web\\src\\Components\\Footer.js":"11","C:\\Users\\Fleur\\Desktop\\website projects etc\\pk-web\\src\\Components\\Profile.js":"12","C:\\Users\\Fleur\\Desktop\\website projects etc\\pk-web\\src\\Components\\Navigation.js":"13"},{"size":329,"mtime":1607895960007,"results":"14","hashOfConfig":"15"},{"size":87,"mtime":1607504507181,"results":"16","hashOfConfig":"15"},{"size":7704,"mtime":1607900527875,"results":"17","hashOfConfig":"15"},{"size":243,"mtime":1607696817140,"results":"18","hashOfConfig":"15"},{"size":73,"mtime":1607504507180,"results":"19","hashOfConfig":"15"},{"size":231,"mtime":1607504507174,"results":"20","hashOfConfig":"15"},{"size":10249,"mtime":1607892068230,"results":"21","hashOfConfig":"15"},{"size":14056,"mtime":1607899022832,"results":"22","hashOfConfig":"15"},{"size":19256,"mtime":1607893177574,"results":"23","hashOfConfig":"15"},{"size":10382,"mtime":1607549930730,"results":"24","hashOfConfig":"15"},{"size":741,"mtime":1607797507192,"results":"25","hashOfConfig":"15"},{"size":436,"mtime":1607896148590,"results":"26","hashOfConfig":"15"},{"size":1775,"mtime":1607899033295,"results":"27","hashOfConfig":"15"},{"filePath":"28","messages":"29","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},"1uc84gl",{"filePath":"30","messages":"31","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"32","messages":"33","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"34","messages":"35","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"36","messages":"37","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"38","messages":"39","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"40","messages":"41","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"42","messages":"43","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"44","messages":"45","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"46","messages":"47","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"48","messages":"49","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"50","messages":"51","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"52","messages":"53","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},"C:\\Users\\Fleur\\Desktop\\website projects etc\\pk-web\\src\\index.js",[],"C:\\Users\\Fleur\\Desktop\\website projects etc\\pk-web\\src\\History.js",[],"C:\\Users\\Fleur\\Desktop\\website projects etc\\pk-web\\src\\App.js",[],"C:\\Users\\Fleur\\Desktop\\website projects etc\\pk-web\\src\\Components\\Dash.js",[],"C:\\Users\\Fleur\\Desktop\\website projects etc\\pk-web\\src\\Constants\\constants.js",[],"C:\\Users\\Fleur\\Desktop\\website projects etc\\pk-web\\src\\Components\\Loading.js",[],"C:\\Users\\Fleur\\Desktop\\website projects etc\\pk-web\\src\\Components\\System.js",[],"C:\\Users\\Fleur\\Desktop\\website projects etc\\pk-web\\src\\Components\\Memberlist.js",[],"C:\\Users\\Fleur\\Desktop\\website projects etc\\pk-web\\src\\Components\\MemberCard.js",[],"C:\\Users\\Fleur\\Desktop\\website projects etc\\pk-web\\src\\Functions\\discord-parser.js",[],"C:\\Users\\Fleur\\Desktop\\website projects etc\\pk-web\\src\\Components\\Footer.js",[],"C:\\Users\\Fleur\\Desktop\\website projects etc\\pk-web\\src\\Components\\Profile.js",[],"C:\\Users\\Fleur\\Desktop\\website projects etc\\pk-web\\src\\Components\\Navigation.js",[]] \ No newline at end of file +[{"C:\\Users\\Fleur\\Desktop\\website projects etc\\pk-web\\src\\index.js":"1","C:\\Users\\Fleur\\Desktop\\website projects etc\\pk-web\\src\\History.js":"2","C:\\Users\\Fleur\\Desktop\\website projects etc\\pk-web\\src\\App.js":"3","C:\\Users\\Fleur\\Desktop\\website projects etc\\pk-web\\src\\Components\\Dash.js":"4","C:\\Users\\Fleur\\Desktop\\website projects etc\\pk-web\\src\\Constants\\constants.js":"5","C:\\Users\\Fleur\\Desktop\\website projects etc\\pk-web\\src\\Components\\Loading.js":"6","C:\\Users\\Fleur\\Desktop\\website projects etc\\pk-web\\src\\Components\\System.js":"7","C:\\Users\\Fleur\\Desktop\\website projects etc\\pk-web\\src\\Components\\Memberlist.js":"8","C:\\Users\\Fleur\\Desktop\\website projects etc\\pk-web\\src\\Components\\MemberCard.js":"9","C:\\Users\\Fleur\\Desktop\\website projects etc\\pk-web\\src\\Functions\\discord-parser.js":"10","C:\\Users\\Fleur\\Desktop\\website projects etc\\pk-web\\src\\Components\\Footer.js":"11","C:\\Users\\Fleur\\Desktop\\website projects etc\\pk-web\\src\\Components\\Profile.js":"12","C:\\Users\\Fleur\\Desktop\\website projects etc\\pk-web\\src\\Components\\Public.js":"13","C:\\Users\\Fleur\\Desktop\\website projects etc\\pk-web\\src\\Components\\ProfileList.js":"14","C:\\Users\\Fleur\\Desktop\\website projects etc\\pk-web\\src\\Components\\ProfileCard.js":"15"},{"size":329,"mtime":1607895960007,"results":"16","hashOfConfig":"17"},{"size":87,"mtime":1607504507181,"results":"18","hashOfConfig":"17"},{"size":8414,"mtime":1607980494066,"results":"19","hashOfConfig":"17"},{"size":243,"mtime":1607696817140,"results":"20","hashOfConfig":"17"},{"size":73,"mtime":1607504507180,"results":"21","hashOfConfig":"17"},{"size":231,"mtime":1607504507174,"results":"22","hashOfConfig":"17"},{"size":10751,"mtime":1607980847885,"results":"23","hashOfConfig":"17"},{"size":14176,"mtime":1607980037183,"results":"24","hashOfConfig":"17"},{"size":19447,"mtime":1607974550971,"results":"25","hashOfConfig":"17"},{"size":10382,"mtime":1607549930730,"results":"26","hashOfConfig":"17"},{"size":741,"mtime":1607964943027,"results":"27","hashOfConfig":"17"},{"size":3692,"mtime":1607980639044,"results":"28","hashOfConfig":"17"},{"size":1636,"mtime":1607976735762,"results":"29","hashOfConfig":"17"},{"size":4781,"mtime":1607980012105,"results":"30","hashOfConfig":"17"},{"size":4981,"mtime":1607980616919,"results":"31","hashOfConfig":"17"},{"filePath":"32","messages":"33","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"34"},"1uc84gl",{"filePath":"35","messages":"36","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"34"},{"filePath":"37","messages":"38","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"39","messages":"40","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"34"},{"filePath":"41","messages":"42","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"34"},{"filePath":"43","messages":"44","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"34"},{"filePath":"45","messages":"46","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"47","messages":"48","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"49","messages":"50","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"51","messages":"52","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"34"},{"filePath":"53","messages":"54","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"34"},{"filePath":"55","messages":"56","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"57","messages":"58","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"59","messages":"60","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"61","messages":"62","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},"C:\\Users\\Fleur\\Desktop\\website projects etc\\pk-web\\src\\index.js",[],["63","64"],"C:\\Users\\Fleur\\Desktop\\website projects etc\\pk-web\\src\\History.js",[],"C:\\Users\\Fleur\\Desktop\\website projects etc\\pk-web\\src\\App.js",[],"C:\\Users\\Fleur\\Desktop\\website projects etc\\pk-web\\src\\Components\\Dash.js",[],"C:\\Users\\Fleur\\Desktop\\website projects etc\\pk-web\\src\\Constants\\constants.js",[],"C:\\Users\\Fleur\\Desktop\\website projects etc\\pk-web\\src\\Components\\Loading.js",[],"C:\\Users\\Fleur\\Desktop\\website projects etc\\pk-web\\src\\Components\\System.js",[],"C:\\Users\\Fleur\\Desktop\\website projects etc\\pk-web\\src\\Components\\Memberlist.js",[],"C:\\Users\\Fleur\\Desktop\\website projects etc\\pk-web\\src\\Components\\MemberCard.js",[],"C:\\Users\\Fleur\\Desktop\\website projects etc\\pk-web\\src\\Functions\\discord-parser.js",[],"C:\\Users\\Fleur\\Desktop\\website projects etc\\pk-web\\src\\Components\\Footer.js",[],"C:\\Users\\Fleur\\Desktop\\website projects etc\\pk-web\\src\\Components\\Profile.js",[],"C:\\Users\\Fleur\\Desktop\\website projects etc\\pk-web\\src\\Components\\Public.js",[],"C:\\Users\\Fleur\\Desktop\\website projects etc\\pk-web\\src\\Components\\ProfileList.js",[],"C:\\Users\\Fleur\\Desktop\\website projects etc\\pk-web\\src\\Components\\ProfileCard.js",[],{"ruleId":"65","replacedBy":"66"},{"ruleId":"67","replacedBy":"68"},"no-native-reassign",["69"],"no-negated-in-lhs",["70"],"no-global-assign","no-unsafe-negation"] \ No newline at end of file diff --git a/src/App.js b/src/App.js index 9d16c8ce..8b10ffd5 100644 --- a/src/App.js +++ b/src/App.js @@ -15,7 +15,7 @@ import Dash from './Components/Dash.js' import history from "./History.js"; import Loading from "./Components/Loading.js"; import Footer from './Components/Footer.js' -import Profile from './Components/Profile.js' +import Public from './Components/Public.js' import API_URL from "./Constants/constants.js"; @@ -105,13 +105,13 @@ export default function App() { pk-webs - { localStorage.getItem('token') ? logOut()}>Log out : "" } history.push('/pk-webs/dash')} >Dash history.push('/pk-webs/settings')} >Settings history.push('/pk-webs/profile')}>Public profile + { localStorage.getItem('token') ? <>
logOut()}>Log out : "" }
- + - + { !localStorage.getItem('token') || isInvalid ? : } @@ -138,7 +138,7 @@ export default function App() { history.push('/pk-webs/dash')}>Continue to dash : - + Enter your token here. You can get your token by using "pk;token". @@ -155,10 +155,10 @@ export default function App() { } - - + + - + Settings @@ -183,6 +183,22 @@ export default function App() { forceUpdate()}} /> } Use opendyslexic? + + { localStorage.getItem('twemoji') ? + { + localStorage.removeItem('twemoji'); + forceUpdate()}} /> : + { + localStorage.setItem('twemoji', 'true') + forceUpdate()}} /> } + Use twemoji? + diff --git a/src/Components/Profile.js b/src/Components/Profile.js index 941167d6..d297125c 100644 --- a/src/Components/Profile.js +++ b/src/Components/Profile.js @@ -1,15 +1,90 @@ +import React, { useEffect, useState } from 'react'; +import { useParams } from 'react-router-dom'; import * as BS from 'react-bootstrap'; -import { FaStar } from "react-icons/fa"; +import Popup from 'reactjs-popup'; +import Twemoji from 'react-twemoji'; + +import { FaAddressCard } from "react-icons/fa"; +import defaultAvatar from '../default_discord_avatar.png' +import Loading from "./Loading.js"; +import API_URL from "../Constants/constants.js"; +import ProfileList from "./ProfileList.js"; export default function Profile () { - return ( - - - Profile - - - WIP. Public profiles coming soon here! - - - ) + + const { sysID } = useParams(); + const [ system, setSystem ] = useState(''); + const [ name, setName ] = useState(''); + const [ tag, setTag ] = useState(""); + const [ timezone, setTimezone ] = useState(""); + const [ desc, setDesc ] = useState(""); + + const [ isLoading, setIsLoading ] = useState(true); + const [ isError, setIsError ] = useState(false); + + useEffect (() => { + fetch(`${API_URL}s/${sysID}`,{ + method: 'GET' + }).then ( res => res.json() + ).then (data => { + setSystem(data); + setIsLoading(false); + }) + .catch (error => { + console.log(error); + setIsError(true); + setIsLoading(false); + }) + }, [sysID]) + + useEffect(() => { + const { toHTML } = require('../Functions/discord-parser.js'); + + if (system.name) { + setName(system.name); + } else setName(''); + + if (system.tag) { + setTag(system.tag); + } else setTag(''); + + if (system.tz) { + setTimezone(system.tz); + } else setTimezone(''); + + if (system.description) { + setDesc(toHTML(system.description)); + } else setDesc("(no description)"); + }, [system.description, system.tag, system.avatar_url, system.tz, system.name]); + + + return (<>{ isLoading ? : isError ? Something went wrong, either the system doesn't exist, or there was an error fetching data. : + <>You are currently viewing a system. + + + {name} ({system.id}) + { system.avatar_url ? } className="avatar" modal> + {close => ( +
close()}> + +
+ )} +
: + } +
+ + + ID: {system.id} + Tag: {tag} + Timezone: {timezone} + +

Description:

+ { localStorage.getItem('twemoji') ?

:

} +
+
+ + } + + + ) } \ No newline at end of file diff --git a/src/Components/ProfileCard.js b/src/Components/ProfileCard.js new file mode 100644 index 00000000..9f018986 --- /dev/null +++ b/src/Components/ProfileCard.js @@ -0,0 +1,100 @@ +import React, { useEffect, useState } from 'react'; +import * as BS from 'react-bootstrap' +import moment from 'moment'; +import Popup from 'reactjs-popup'; +import 'reactjs-popup/dist/index.css'; +import autosize from 'autosize'; +import LazyLoad from 'react-lazyload'; +import Twemoji from 'react-twemoji'; + +import defaultAvatar from '../default_discord_avatar.png' +import { FaUser } from "react-icons/fa"; + +export default function MemberCard(props) { + + const member = props.member; + + const [ displayName, setDisplayName ] = useState(""); + const [ birthday, setBirthday ] = useState(""); + const [ pronouns, setPronouns ] = useState(""); + const [ color, setColor ] = useState(""); + const [ desc, setDesc ] = useState(""); + const proxyTags = member.proxy_tags; + + const [ proxyView, setProxyView ] = useState(false); + + useEffect(() => { + autosize(document.querySelector('textarea')); + }) + + useEffect(() => { + const { toHTML } = require('../Functions/discord-parser.js'); + + if (member.display_name) { + setDisplayName(member.display_name) + } else setDisplayName('') + + if (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(member.birthday, 'YYYY-MM-DD').format('MMM D, YYYY'); + setBirthday(birthdaymoment); + } + } else { setBirthday(''); + } + + if (member.pronouns) { + setPronouns(member.pronouns) + } else setPronouns('') + + if (member.color) { + setColor(member.color); + } else setColor(''); + + if (member.description) { + setDesc(toHTML(member.description)); + } else setDesc("(no description)"); + }, [member.description, member.color, member.birthday, member.display_name, member.pronouns, member.avatar_url, member.proxy_tags]); + + return ( + + + {member.name} ({member.id}) + { member.avatar_url ? } className="avatar" modal> + {close => ( +
close()}> + +
+ )} +
: + } +
+ + + + ID: {member.id} + { member.display_name ? Display name: {displayName} : "" } + { member.birthday ? Birthday: {birthday} : "" } + { member.pronouns ? Pronouns: {pronouns} : "" } + { member.color ? Color: {color} : "" } + { proxyView ? "" : Proxy tags: setProxyView(true)}>View } + + + { proxyView ? <>
+
Viewing proxy tags
+ + { proxyTags.length === 0 ? No proxy tags set. : proxyTags.map((proxytag) => {proxytag.prefix}text{proxytag.suffix} )} + + setProxyView(false)}>Exit +
: "" } +

Description:

+ { localStorage.getItem('twemoji') ?

:

} +
+
+
+ + ) +} diff --git a/src/Components/ProfileList.js b/src/Components/ProfileList.js new file mode 100644 index 00000000..70a0745c --- /dev/null +++ b/src/Components/ProfileList.js @@ -0,0 +1,117 @@ +import React, { useEffect, useState, useCallback } from 'react'; +import * as BS from 'react-bootstrap' +import 'reactjs-popup/dist/index.css'; + +import ProfileCard from './ProfileCard.js' +import Loading from "./Loading.js"; +import API_URL from "../Constants/constants.js"; + +export default function Memberlist(props) { + + const sysID = props.sysID; + + const [isLoading, setIsLoading ] = useState(false); + const [isError, setIsError ] = useState(false); + + const [currentPage, setCurrentPage] = useState(1); + const [membersPerPage, setMembersPerPage] = useState(25); + + const [members, setMembers ] = useState([]); + const [value, setValue] = useState(''); + + const fetchMembers = useCallback( () => { + setIsLoading(true); + setIsError(false); + setMembersPerPage(25); + + fetch(`${API_URL}s/${sysID}/members`,{ + method: 'GET', + }).then ( res => res.json() + ).then (data => { + setMembers(data) + setIsLoading(false); + }) + .catch (error => { + console.log(error); + setIsError(true); + setIsLoading(false); + }) + }, [sysID]) + + useEffect(() => { + fetchMembers(); + }, [fetchMembers]) + + const indexOfLastMember = currentPage * membersPerPage; + const indexOfFirstMember = indexOfLastMember - membersPerPage; + const currentMembers = members.filter(member => { + if (!value) return true; + if (member.name.toLowerCase().includes(value.toLowerCase())) { + return true; + } + return false; + }).sort((a, b) => a.name.localeCompare(b.name)).slice(indexOfFirstMember, indexOfLastMember); + + + const active = currentPage; + const pageAmount = Math.ceil(members.length / membersPerPage); + + const memberList = currentMembers.map((member) => + + + ); + + return ( + <> + { isLoading ? : isError ? + Error fetching members. Perhaps the member list has been set to private. : + <> + + + + + + { + setMembersPerPage(e.target.value); + setCurrentPage(1); + }}> + + + + + + + + + + + {setValue(e.target.value); setCurrentPage(1)}} placeholder="Search"/> + + + + fetchMembers()}>Refresh + + + + + { currentPage === 1 ? : setCurrentPage(currentPage - 1)} />} + { currentPage < 3 ? "" : setCurrentPage(1)} active={1 === active}>{1}} + { currentPage < 4 ? "" :} + { currentPage > 1 ? setCurrentPage(currentPage - 1)}>{currentPage - 1} : "" } + setCurrentPage(currentPage)} active={currentPage === active}>{currentPage} + { currentPage < pageAmount ? setCurrentPage(currentPage + 1)}>{currentPage + 1} : "" } + { currentPage > pageAmount - 3 ? "" : } + { currentPage > pageAmount - 2 ? "" : setCurrentPage(pageAmount)} active={pageAmount === active}>{pageAmount}} + { currentPage === pageAmount ? : setCurrentPage(currentPage + 1)} />} + + + + {memberList} + + + } + + ) +} \ No newline at end of file diff --git a/src/Components/Public.js b/src/Components/Public.js new file mode 100644 index 00000000..932e90ba --- /dev/null +++ b/src/Components/Public.js @@ -0,0 +1,47 @@ +import React from 'react'; +import * as BS from 'react-bootstrap'; +import { FaStar } from "react-icons/fa"; +import { useForm } from "react-hook-form"; +import history from "../History.js"; +import { Switch, Route, useRouteMatch } from 'react-router-dom'; +import Profile from './Profile.js' + +export default function Public () { + const { path, url } = useRouteMatch(); + const { register, handleSubmit } = useForm(); + + const submitID = (data) => { + history.push(`${url}/${data.sysID}`); + } + + return ( + + + + + + Profile + + + + + Submit a system ID to view to that system's profile. + + + + + + + Submit + + + + + + + + + + + ) +} \ No newline at end of file