In collaboration between CivicDataLab and Open Contracting Partnership
A data-driven tool to enable public officials in the state of Asaam to make smarter, data-informed decisions about public spending
Install a recent version of Node. Node 16 is recommended.
For error:0308010C:digital envelope routines::unsupported
follow this
We use SASS preprocessor to manage styling. All of it can be found at /styles
directory where it's managed by using ITCSS architecture to make it scalable. For naming, we use BEM methodology.
You can connect CMS and DMS backends easily via environment variables:
$ export DMS=http://ckan:5000
$ export CMS=http://myblog.wordpress.com
Note that we don't yet have implementations for the following CKAN features:
- Activities
- Auth
- Groups
/
/datasets
/datasets/[tender]
/kpi
/kpi/[analysis]
/stories
/about
We use Apollo client which allows us to query data with GraphQL. We have setup CKAN API for the demo (it uses demo.ckan.org as DMS):
Note that we don't have Apollo Server but we connect CKAN API using apollo-link-rest
module. You can see how it works in lib/apolloClient.ts and then have a look at pages/_app.tsx.
For development/debugging purposes, we suggest installing the Chrome extension - https://chrome.google.com/webstore/detail/apollo-client-developer-t/jdkknkkbebbapilgoeccciglkfbmbnfm.
This is configured by default to support both English
and French
subpath for language translation. But for subsequent users, this following steps can be used to configure i18n for other languages;
next.config.js
, to add more languages to the i18n localesi18n: {
locales: ['en', 'fr', 'nl-NL'], // add more language to the list
defaultLocale: 'en', // set the default language to use
},
Create a folder for the language in locales
--> locales/en-Us
In the language folder, different namespace files (json) can be created for each translation. For the index.js
use-case, I named it common.json
// locales/en/common.json
{
"title" : "Portal js in English",
}
// locales/fr/common.json
{
"title" : "Portal js in French",
}
import { loadNamespaces } from './_app';
import useTranslation from 'next-translate/useTranslation';
const Home: React.FC = ()=> {
const { t } = useTranslation();
return (
<div>{t(`common:title`)}</div> // we use common and title base on the common.json data
);
};
export const getServerSideProps: GetServerSideProps = async ({ locale }) => {
........ ........
return {
props : {
_ns: await loadNamespaces(['common'], locale),
}
};
};
http://localhost:3000
and http://localhost:3000/fr
. Note The subpath also activate chrome language TranslatorWhen visiting a dataset page, you may want to fetch the dataset metadata in the server-side. To do so, you can use getServerSideProps
function from NextJS:
import { GetServerSideProps } from 'next';
import { initializeApollo } from '../lib/apolloClient';
import gql from 'graphql-tag';
const QUERY = gql`
query dataset($id: String) {
dataset(id: $id) @rest(type: "Response", path: "package_show?{args}") {
result
}
}
`;
...
export const getServerSideProps: GetServerSideProps = async (context) => {
const apolloClient = initializeApollo();
await apolloClient.query({
query: QUERY,
variables: {
id: 'my-dataset'
},
});
return {
props: {
initialApolloState: apolloClient.cache.extract(),
},
};
};
This would fetch the data from DMS and save it in the Apollo cache so that we can query it again from the components.
Consider situation when rendering a component for org info on the dataset page. We already have pre-fetched dataset metadata that includes organization
property with attributes such as name
, title
etc. We can now query only organization part for our Org
component:
import { useQuery } from '@apollo/react-hooks';
import gql from 'graphql-tag';
export const GET_ORG_QUERY = gql`
query dataset($id: String) {
dataset(id: $id) @rest(type: "Response", path: "package_show?{args}") {
result {
organization {
name
title
image_url
}
}
}
}
`;
export default function Org({ variables }) {
const { loading, error, data } = useQuery(
GET_ORG_QUERY,
{
variables: { id: 'my-dataset' }
}
);
...
const { organization } = data.dataset.result;
return (
<>
{organization ? (
<>
<img
src={
organization.image_url
}
className="h-5 w-5 mr-2 inline-block"
/>
<Link href={`/@${organization.name}`}>
<a className="font-semibold text-primary underline">
{organization.title || organization.name}
</a>
</Link>
</>
) : (
''
)}
</>
);
}
Install the dependencies:
npm i
Boot the demo frontend:
npm run dev
Open http://localhost:3000 to see the home page π
You can start editing the page by modifying /pages/index.tsx
. The page auto-updates as you edit the file.
For any new feature or bug reports, please request it in issues.
See CONTRIBUTING.md for ways to get started.
Please adhere to Code of Conduct.
This is based on a PortalJS.