Using react-router-dom to transition from one component to another

Hi again @nnkogift @Gassim ,

Following the solution to this issue, I was able to build the project, but now I can’t get it to do what I want. I have two components, an EntityTable which holds a table of all tracked entities, and a Details component which is supposed to displace details about an entity when clicked. I want to achieve this by surrounding table rows in EntityTable with LINKs that direct to the Details page.

The following are the problems that I’m currently facing:

  1. Using the d2 app scripts init app-name command to create an application does not generate an index.js that is supposed to hold routes configurations. By index.js, I mean a file that contains code similar to the following:
    index.js
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';

ReactDOM.render(<App/>, document.querySelector('#root'));
  1. Due to the problem described in 1, I’m configuring the routes in App.js. As result, I’m getting a blank page when I deploy my application.

  2. How do I surround table rows with LINK from react-router-dom. I would appreciate your directions on how to achieve this.

Please find below my codes below:

App.js

import React from 'react';
import { BrowserRouter as Router, Route, Routes } from 'react-router-dom';
import Details from './components/Details';
import EntityTable from './components/EntityTable';

const App = () => {

  <Router>
    <Routes>
      <Route path="/" element={<EntityTable />} />
      <Route path="/details" element={<Details />} />
    </Routes>
  </Router >

};
export default App

EntityTable.js

import React, { useState } from 'react'
import { useDataQuery } from '@dhis2/app-runtime'
import i18n from '@dhis2/d2-i18n'
import styles from '../App.module.css'
import { Icon, Label, Menu, Table, Input } from 'semantic-ui-react'
import { Router, Route, Switch, Link} from 'react-router-dom';
import Details from './Details'



const query = {
    results: {
        resource: 'trackedEntityInstances',
        params: {
            ou: "QoptHf4izj7",
            program: "lJN7Imivbpc",
            fields: ['created', 'trackedEntityInstance', 'attributes'],
        },
    },
}


const EntityTable = () => {
    const { loading, error, data } = useDataQuery(query)

    if (error) {
        return <span>ERROR: {error.message}</span>
    }

    if (loading) {
        return <span>Loading...</span>
    }
    const trackedEntities = data.results.trackedEntityInstances
    console.log("Tracked Entities", data.results)
    function handleClick(e) {
        e.preventDefault();
        console.log('Event', e);
        //this.router.transitionTo('index');
    }

    return (
        <div className={styles.container}>
            <div className='search'>
                <Input
                    icon={{ name: 'search', circular: true, link: true }}
                    placeholder='Search...'
                />
            </div>
            <Table celled>
                <Table.Header>
                    <Table.Row>
                        <Table.HeaderCell>Registration Date</Table.HeaderCell>
                        <Table.HeaderCell>Registration Number</Table.HeaderCell>
                        <Table.HeaderCell>First Name</Table.HeaderCell>
                        <Table.HeaderCell>Last Name</Table.HeaderCell>
                        <Table.HeaderCell>Date of Birth</Table.HeaderCell>
                        <Table.HeaderCell>Gender</Table.HeaderCell>
                    </Table.Row>
                </Table.Header>

                <Table.Body>
                    {trackedEntities && trackedEntities.map(trackedEntity =>
                        <Table.Row onClick={handleClick}>
                            <Table.Cell>{trackedEntity['created'].split('T')[0]}</Table.Cell>
                            <Table.Cell>{trackedEntity['attributes'].find((attribute) => attribute.attribute === "MCDUAHWauQl")?.value ?? "N/A"}</Table.Cell>
                            <Table.Cell>{trackedEntity['attributes'].find((attribute) => attribute.attribute === "KrrfjFD9CwI")?.value ?? "N/A"}</Table.Cell>
                            <Table.Cell>{trackedEntity['attributes'].find((attribute) => attribute.attribute === "Epa1sjrcL4m")?.value ?? "N/A"}</Table.Cell>
                            <Table.Cell>{trackedEntity['attributes'].find((attribute) => attribute.attribute === "quUznibYSw5")?.value ?? "N/A"}</Table.Cell>
                            <Table.Cell>{trackedEntity['attributes'].find((attribute) => attribute.attribute === "puNPAwo3cO9")?.value ?? "N/A"}</Table.Cell>
                        </Table.Row>
                    )}
                </Table.Body>
                <Table.Footer>
                    <Table.Row>
                        <Table.HeaderCell colSpan='3'>
                            <Menu floated='right' pagination>
                                <Menu.Item as='a' icon>
                                    <Icon name='chevron left' />
                                </Menu.Item>
                                <Menu.Item as='a'>1</Menu.Item>
                                <Menu.Item as='a'>2</Menu.Item>
                                <Menu.Item as='a'>3</Menu.Item>
                                <Menu.Item as='a'>4</Menu.Item>
                                <Menu.Item as='a' icon>
                                    <Icon name='chevron right' />
                                </Menu.Item>
                            </Menu>
                        </Table.HeaderCell>
                    </Table.Row>
                </Table.Footer>
            </Table>
        </div>
    )
}

export default EntityTable

Details.js

import React from 'react';

const Details = () => {  
    return(
        <div>
        This will hold details of a tracked entity
        </div>
    )
}

export default Details 

Below is the folder structure of my project:

1 Like

Hello @Orly_MUGWANEZA

I suggest for DHIS2 apps you use HashRouter or MemoryRouter for routing instead of BrowserRouter. See their usages here.

The BrowserRouter has challenges for apps that are not hosted at the base URL. You will have to set the basename prop which is very dynamic for DHIS2 apps (they vary with DHIS2 versions).

1 Like

Hello @nnkogift

I have changed my App.js to be like:

import React from 'react';
import { HashRouter as Router, Route, Routes } from 'react-router-dom';
import Details from './components/Details';
import EntityTable from './components/EntityTable';

const App = () => {

  <Router>
    <Routes>
      <Route path="/" element={<EntityTable />} />
      <Route path="/details" element={<Details />} />
    </Routes>
  </Router >

};
export default App

but I’m getting the following error:
image

I also couldn’t find the basename of my app. Where can I find this?I’m running DHIS2 2.37.1

Thanks,
OM

Hello

Was this after you build the application or during the development? The error means one of your components is not returning anything (see here)

As for the basename, you can combine the server URL with the location the app is going to be hosted.
for DHIS2 2.37.1 I think it will be {baseUrl}/api/apps/{name-of-app-from-package.json}/index.html The base URL can be obtained from useConfig hook from the @dhis2/runtime

2 Likes

Thank you @nnkogift, I have added the baseUrl property and it’s working.

2 Likes