Skip to content

Commit 64fd397

Browse files
committed
Fixed UI bugs (load anim), improved file upload screen, added new queries alongside better contact screen for a given person, added more padding in home screen to avoid bottom nav from overlapping images, fixed some errors due to react keys in arrays.
1 parent e7f7eb2 commit 64fd397

9 files changed

+232
-73
lines changed

Diff for: src/App.css

+4-1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121

2222
.app-div
2323
{
24+
position: absolute;
2425
margin: 0;
2526
padding: 0;
2627
width: 100%;
@@ -37,7 +38,9 @@
3738

3839
.content
3940
{
40-
padding: 20px;
41+
height: 100%;
42+
width: 100%;
43+
padding: 20px 20px 70px 20px; /* slightly more at bottom, account for bottom nav*/
4144
}
4245

4346

Diff for: src/App.js

+27-7
Original file line numberDiff line numberDiff line change
@@ -162,8 +162,9 @@ function BottomNavBar(props)
162162
let gotoScreen = props.gotoScreen;
163163
let [location, setLocation] = useState("/");
164164

165-
const handleChange = async (event, newValue) => {await setLocation(newValue); await gotoScreen(newValue)};
166-
165+
// NOTICE: we false as last parameter of gotoScreen, because we consider all the navigation tabs independent
166+
// and as such we want hidden parameters to be updated after the screen change to not cause errors
167+
const handleChange = async (event, newValue) => {await setLocation(newValue); await gotoScreen(newValue, null, false)};
167168

168169
return(
169170
<BottomNavigation className={classes.appBar} value={location} onChange={handleChange}
@@ -181,7 +182,7 @@ function BottomNavBar(props)
181182
function Home(props)
182183
{
183184
let [notifMsg, setNotifMsg] = useState("");
184-
let [notifType, setNotifType] = useState("");
185+
let [notifType, setNotifType] = useState("info");
185186
let [loadingAnim, setLoadingAnim] = useState(false); // when first loading, show anim
186187
let [urlHiddenParams, setUrlHiddenParams] = useState([]);
187188

@@ -205,19 +206,35 @@ function Home(props)
205206
};
206207

207208

208-
async function gotoScreen(screenPath, hiddenParams = null)
209+
async function gotoScreen(screenPath, hiddenParams = null, updateHiddenParamsBefore=true)
209210
{
210211
console.log(`goto ${screenPath} ...`);
211212
console.log(`hidden params:\n`, hiddenParams);
212-
await setUrlHiddenParams(hiddenParams);
213+
214+
// By default, we update the hidden params before redirecting.
215+
// This way, the newpage will have the proper parameters set before rendering
216+
if (updateHiddenParamsBefore)
217+
{
218+
await setUrlHiddenParams(hiddenParams);
219+
}
220+
await setLoadingAnim(false); // always cancel loading anim when switching screen
213221
history.push(`${screenPath}`);
222+
223+
// Some screens rely on hidden params as props, hence they will show an error
224+
// if we change the hidden param before changing location (since everything is reference in JS).
225+
// In that case, we can avoid the problem by setting updateHiddenParamsBefore to false,
226+
// hence updating such prop after the screen change.
227+
if (! updateHiddenParamsBefore)
228+
{
229+
await setUrlHiddenParams(hiddenParams);
230+
}
214231
}
215232

216233
function showLoadingAnimation()
217234
{
218235
if (loadingAnim)
219236
{
220-
return <CircularProgress size={100} style={{zIndex: 1600, position: "fixed", color: '#1a90ff'}}/>
237+
return <CircularProgress color="secondary" size={100} style={{zIndex: 1700, opacity: ".7", position: "fixed", top: "45vh"}}/>
221238
}
222239
}
223240

@@ -242,12 +259,15 @@ function Home(props)
242259
}
243260

244261
return (<>
262+
{showLoadingAnimation()}
245263
<MenuBar classes={classes} history={history} gotoScreen={gotoScreen}/>
246264
<Notification notifMsg={notifMsg} notifType={notifType}/>
247-
{showLoadingAnimation()}
248265
<div className="content">
249266
{/*</div>*/}
250267
<Switch>
268+
<Route exact path="/redirect">
269+
<h1>Redirecting...</h1>
270+
</Route>
251271
<Route exact path="/upload">
252272
<FileUpload explorerPath={explorerPath} setNotifMsg={setNotifMsg}
253273
setNotifType={setNotifType} setLoadingAnim={setLoadingAnim}/>

Diff for: src/ContactDetails.js

+71-12
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,90 @@
11

22
import React, {useState, useEffect} from "react";
33
import {executeQuery} from "./rdf";
4+
import {getPODUrlFromWebId} from './pod';
5+
import {useSession} from "@inrupt/solid-ui-react";
46

7+
// using person file as source
8+
const getWebIdFromPersonFileQuery = "SELECT ?o WHERE { ?s <http://www.w3.org/2006/vcard/ns#value> ?o }";
9+
// using webid as source
10+
const getRoleQuery = "SELECT ?o WHERE { ?s <http://www.w3.org/2006/vcard/ns#role> ?o }";
11+
const getPODProviderUrlQuery = "SELECT ?o WHERE { ?s <http://www.w3.org/ns/solid/terms#oidcIssuer> ?o }";
12+
const getEmailCardUrlQuery = "SELECT ?o WHERE { ?s <http://www.w3.org/2006/vcard/ns#hasEmail> ?o }";
13+
// using email card url
14+
const getEmailFromEmailCardUrlQuery = "SELECT ?o WHERE { ?s <http://www.w3.org/2006/vcard/ns#value> ?o }";
515

616
function ContactDetails(props)
717
{
818
console.log("data:", props);
9-
let username = props.realProps.match.params.username; //data.public;
10-
let personFileUrl = props.urlHiddenParams[0]; //data.hidden;
19+
let contactUsername = props.realProps.match.params.username; //data.public;
20+
let contactPersonFileUrl = props.urlHiddenParams[0]; //data.hidden;
21+
let [contactWebId,setContactWebId] = useState("");
22+
let [contactPodUrl, setContactPodUrl] = useState("");
23+
let [role, setRole] = useState("");
24+
let [email, setEmail] = useState("");
1125

12-
// TODO: set the web id of the contact in useEffect()
13-
// let [contactWebId, setContactWebId] = useState("");
14-
// useEffect(() => {
26+
const { session } = useSession();
27+
28+
function parseSingleResult(bindings)
29+
{
30+
return bindings[0]['_root'].entries[0][1]['id'].replace(/['"]+/g, '');
31+
}
32+
33+
async function getContactDetailsFromPersonFile()
34+
{
35+
let resBindings = await executeQuery(getWebIdFromPersonFileQuery, [contactPersonFileUrl], session);
36+
let parsedWebId = parseSingleResult(resBindings);
37+
console.log("parsed contact webid:", parsedWebId);
38+
setContactWebId(parsedWebId);
39+
let newContactPodUrl = getPODUrlFromWebId(parsedWebId);
40+
setContactPodUrl(newContactPodUrl);
41+
resBindings = await executeQuery(getRoleQuery, [parsedWebId], session);
42+
console.log("role res:", resBindings);
43+
if (resBindings.length > 0)
44+
{
45+
let parsedRole = parseSingleResult(resBindings);
46+
setRole(parsedRole);
47+
}
48+
resBindings = await executeQuery(getEmailCardUrlQuery, [parsedWebId], session);
49+
console.log("email card url res:", resBindings);
50+
if (resBindings.length > 0)
51+
{
52+
let parsedEmailCardUrl = parseSingleResult(resBindings);
53+
resBindings = await executeQuery(getEmailFromEmailCardUrlQuery, [parsedEmailCardUrl], session);
54+
console.log("email res:", resBindings);
55+
if (resBindings.length > 0)
56+
{
57+
let parsedEmail = parseSingleResult(resBindings);
58+
setEmail(parsedEmail);
59+
}
60+
}
61+
// let email =
62+
}
63+
64+
useEffect(() => {
65+
getContactDetailsFromPersonFile();
66+
}, [contactPersonFileUrl]);
67+
68+
69+
function showField(field)
70+
{
71+
return (<p>{field ? field : "-"}</p>);
72+
}
1573

16-
// }, [username]);
1774

1875
return (
1976
<>
20-
<h1>Contact page of {username}</h1>
77+
<h1>Contact page of {contactUsername}</h1>
2178
<h4>Person file url:</h4>
22-
<p>{personFileUrl}</p>
79+
{showField(contactPersonFileUrl)}
2380
<h4>WebId:</h4>
24-
<p>todo</p>
81+
{showField(contactWebId)}
82+
<h4>POD url</h4>
83+
{showField(contactPodUrl)}
2584
<h4>Email:</h4>
26-
<p>todo</p>
27-
<h4>Nickname:</h4>
28-
<p>todo</p>
85+
{showField(email)}
86+
<h4>Role</h4>
87+
{showField(role)}
2988
</>
3089
);
3190
}

Diff for: src/Contacts.css

+17-1
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,25 @@
11

22
.contact {
3+
margin: 0;
4+
padding: 10px;
5+
max-width: 600px;
36
display: flex;
4-
flex-direction: row;
7+
flex-direction: row;
8+
/*box-sizing: border-box; allow the borders to consider */
9+
510
}
611

712

13+
.contact:not(:first-child){
14+
border-top: 1px solid grey;
15+
}
16+
17+
.contact:last-child{
18+
border-bottom: 1px solid grey;
19+
}
20+
21+
22+
823
.contact-name
924
{
1025
padding-left: 5px;
@@ -14,5 +29,6 @@
1429
{
1530
/*border-left: 3px solid cyan;*/
1631
color: cyan;
32+
background-color: red;
1733
}
1834

Diff for: src/Contacts.js

+4-6
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,7 @@
33
import { useState,React, useEffect } from "react";
44
import {executeQuery} from "./rdf";
55
import "./Contacts.css";
6-
import {
7-
useSession,
8-
} from "@inrupt/solid-ui-react";
6+
import {useSession} from "@inrupt/solid-ui-react";
97

108
import PersonIcon from '@material-ui/icons/Person';
119

@@ -61,7 +59,7 @@ function Contacts(props)
6159
function Contact(props)
6260
{
6361
let binding = props.binding;
64-
const boundVariables = binding['_root'].entries.map(e => e[0]);
62+
// const boundVariables = binding['_root'].entries.map(e => e[0]);
6563

6664
let username = binding['_root'].entries[1][1]['id'].replace(/['"]+/g, '');
6765
// username = username.replace("/(\"|\"$)/", '');
@@ -81,8 +79,8 @@ function Contacts(props)
8179

8280
return (
8381
<div>
84-
{bindings.map(binding => {
85-
console.log("Binding:", binding); return (<Contact binding={binding}/>)
82+
{bindings.map((binding, idx) => {
83+
console.log("Binding:", binding); return (<Contact key={idx} binding={binding}/>)
8684
}) }
8785
</div>
8886
);

Diff for: src/FileExplorer.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ function FileExplorer(props) {
106106
getFilesFromResourceURL(POD_URL).then((fileArray) => {
107107
setCurrentPath(POD_URL);
108108
setFiles(fileArray);
109-
setLoadingAnim(false);
109+
// setLoadingAnim(false);
110110
});
111111

112112
}

Diff for: src/FileUpload.css

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
2+
.upload-section
3+
{
4+
margin-top: 15px;
5+
}

Diff for: src/FileUpload.js

+24-11
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
2+
import "./FileUpload.css"
3+
14
import React, {useState} from "react"
25

36
// Import from "@inrupt/solid-client"
@@ -10,6 +13,10 @@ import {
1013
fetch
1114
} from '@inrupt/solid-client-authn-browser';
1215

16+
import Button from '@material-ui/core/Button';
17+
import CloudUploadIcon from '@material-ui/icons/CloudUpload';
18+
import SendIcon from '@material-ui/icons/Send';
19+
1320

1421
function FileUpload(props) {
1522
let currentPath = props.explorerPath;
@@ -35,7 +42,7 @@ function FileUpload(props) {
3542
// promise is undefined if the upload wasn't sucessful
3643
if (! res)
3744
{
38-
errorMsg += "Could not upload '" + selectedFiles[i].name + "', the file might already exist.\n";
45+
errorMsg += "'" + selectedFiles[i].name + "'";
3946
}
4047

4148
}
@@ -44,7 +51,7 @@ function FileUpload(props) {
4451
if (errorMsg !== "")
4552
{
4653
await setNotifType("error");
47-
await setNotifMsg(errorMsg);
54+
await setNotifMsg("Could not upload file(s), they might already exist: " + errorMsg);
4855
}
4956
else if (selectedFiles.length > 0)
5057
{
@@ -93,32 +100,38 @@ function FileUpload(props) {
93100

94101
function selectedFilesToReact() {
95102
let res = [];
96-
103+
let i = 0;
97104
// selectedFiles is iterable but not an array,
98105
// so map() and forEach() functions don't work
99106
for (let file of selectedFiles) {
100-
res.push(<li>{file.name}</li>);
107+
res.push(<li key={i}>{file.name}</li>);
108+
++i;
101109
}
102110

103111
return res;
104112
}
105113

106-
function showSelectedFiles() {
114+
function showUploadSection() {
107115
return (
108-
<div className="SelectedFilesDiv">
109-
<p>Selected files:</p>
116+
<div className="upload-section">
117+
<h4>Selected files:</h4>
110118
<ul>{selectedFilesToReact()}</ul>
119+
<Button variant="contained" color="primary" onClick={upload}
120+
endIcon={<SendIcon/>}>Upload</Button>
111121
</div>
112122
);
113123
}
114124

115125
return (
116126
<div>
117127
<h1>Upload files</h1>
118-
<p>Current path: {currentPath}</p>
119-
<button className="Button" onClick={openFileSelectionWindow}>Add file(s)</button>
120-
{showSelectedFiles()}
121-
<button className="Button" onClick={upload}>Upload</button>
128+
<h4>Destination:</h4>
129+
<p>{currentPath}</p>
130+
<Button variant="contained" color="primary" onClick={openFileSelectionWindow}
131+
startIcon={<CloudUploadIcon/>}>
132+
Select file(s)
133+
</Button>
134+
{selectedFiles.length > 0 ? showUploadSection() : null}
122135
<input id="file-input" type="file" multiple="multiple"
123136
name="fileUploadInput"
124137
className="file-selection"

0 commit comments

Comments
 (0)