This is a sample react application that uses solid components.
npm install --legacy-peer-deps
npm startDocumentation links:
First, create a React application with npx create-react-app solid-react-example. This command will create a react sample application in the directory solid-react-example.
Let's add a dependency to this project. We want to use solid components, let's use npm to add the required dependencies:
cd solid-react-example
npm install @inrupt/solid-ui-reactin the file package.json you can see now that the line "@inrupt/solid-ui-react": "^2.8.2" has been added. This file is critical to install the dependencies in another computer (using npm install).
Let's install also two other dependencies that are needed for this project:
npm install @inrupt/lit-generated-vocab-common
npm install @material-ui/core --legacy-peer-depsNow let's modify the code so we can use these components to make a basic login page against a solid server and then show some basic information extracted from the POD.
This component application will have two subcomponents, depending if we are logged in or not. If we are not logged in, we will show the LoginForm component. If we are already logged in, we will show some information from the user pod, using the ProfileViewer component.
Note that we have two listeners to know when the login changes. We use these listeners to handle the isLoggedIn state variable. React will handle the rest, changing the virtual dom depending on the value of this variable.
const App = () => {
//We use this state variable
const [isLoggedIn, setIsLoggedIn] = useState(false);
//With this we can control the login status for solid
const { session } = useSession();
//We have logged in
session.onLogin(()=>{
setIsLoggedIn(true)
})
//We have logged out
session.onLogout(()=>{
setIsLoggedIn(false)
})
return(
<SessionProvider sessionId="log-in-example">
{(!isLoggedIn) ? <LoginForm/> : <ProfileViewer/>}
</SessionProvider>
)
}For logging in, we have a LoginButton component. Login in solid is carried out by another site (the pod provider), so we must handle the redirect when coming back from the login process.
const LoginForm = () => {
const [idp, setIdp] = useState("https://inrupt.net");
const [currentUrl, setCurrentUrl] = useState("https://localhost:3000");
useEffect(() => {
setCurrentUrl(window.location.href);
}, [setCurrentUrl]);
return (
<Container fixed>
<FormGroup>
<TextField
label="Identity Provider"
placeholder="Identity Provider"
type="url"
value={idp}
onChange={(e) => setIdp(e.target.value)}
InputProps={{
endAdornment: (
<LoginButton oidcIssuer={idp} redirectUrl={currentUrl}>
<Button variant="contained" color="primary">
Login
</Button>
</LoginButton>
),
}}
/>
</FormGroup>
</Container>
);
}Note the useEffect hook. It allows us to execute some code when the component is mounted. Using setCurrentUrl as a parameter means that this function will only get executed when this value changes.
Once we are logged in, we can proceed to show some profile information. In this little example we are showing the user name, the organization to which the user belongs and its picture. For that, we use the solid react components that allow us to easily show this information without having to use the internal language used for these queries.
const ProfileViewer = () => {
const { session } = useSession();
const { webId } = session.info;
return (
<Container fixed>
<CombinedDataProvider datasetUrl={webId} thingUrl={webId}>
<Card style={{ maxWidth: 480 }}>
<CardContent>
<Typography gutterBottom variant="h5" component="h2">
<Text property={FOAF.name.iri.value} />
</Typography>
<Typography variant="body2" color="textSecondary" component="p" style={{ display: "flex", alignItems: "center" }}>
<Text property={VCARD.role.iri.value} />
</Typography>
</CardContent>
<CardActionArea style={{ justifyContent: "center", display: "flex" }}>
<Image property={VCARD.hasPhoto.iri.value} width={480} />
</CardActionArea>
</Card>
</CombinedDataProvider>
<LogoutButton >
<Button style={{ marginTop: 20 }} variant="contained" color="primary">
Logout
</Button>
</LogoutButton>
</Container>
);
}
export default ProfileViewer