Skip to content

Commit

Permalink
Add Carts and statice data for view all source
Browse files Browse the repository at this point in the history
- Add query to display the source details in view all source
- Fix source feed styling
- Add source pagination
  • Loading branch information
roshni73 authored and frozenhelium committed Apr 23, 2024
1 parent 42f28d2 commit fadd1f6
Show file tree
Hide file tree
Showing 11 changed files with 753 additions and 503 deletions.
8 changes: 3 additions & 5 deletions env.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,7 @@ import { defineConfig, Schema } from '@julr/vite-plugin-validate-env';

// TODO: Integrate .env for CI and remove optional() call on required fields
export default defineConfig({
APP_ENVIRONMENT: Schema.string.optional(),
APP_GRAPHQL_API_ENDPOINT: Schema.string(),
APP_MAPBOX_ACCESS_TOKEN: Schema.string(),
APP_TITLE: Schema.string(),
APP_GRAPHQL_CODEGEN_ENDPOINT: Schema.string.optional(),
APP_TITLE: Schema.string.optional(),
APP_MAPBOX_ACCESS_TOKEN: Schema.string.optional(),
APP_GRAPHQL_ENDPOINT: Schema.string.optional(),
})
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
},
"dependencies": {
"@apollo/client": "^3.9.9",
"@graphql-codegen/cli": "^5.0.2",
"@graphql-codegen/introspection": "^4.0.3",
"@graphql-codegen/typescript-operations": "^4.2.0",
"@ifrc-go/icons": "^1.3.3",
Expand Down Expand Up @@ -86,7 +87,7 @@
"vite-plugin-compression2": "^1.0.0",
"vite-plugin-radar": "^0.9.2",
"vite-plugin-svgr": "^4.2.0",
"vite-plugin-webfont-dl": "^3.9.1",
"vite-plugin-webfont-dl": "3.9.2",
"vite-tsconfig-paths": "^4.2.2",
"vitest": "^1.1.0"
}
Expand Down
10 changes: 10 additions & 0 deletions src/App/routes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -66,12 +66,22 @@ const alertDetails = myWrapRoute({
parent: root,
});

// TODO: rename this route and view name to "AllSources" or just "Sources"
const viewAllSource = myWrapRoute({
title: 'ViewAllSource',
path: 'sources',
component: () => import('#views/SourcesList'),
componentProps: {},
parent: root,
});

export const wrappedRoutes = {
root,
home,
preferences,
alertDetails,
resource,
viewAllSource,
};

export const unwrappedRoutes = unwrapRoute(Object.values(wrappedRoutes));
Expand Down
7 changes: 2 additions & 5 deletions src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,15 @@ import {
InMemoryCache,
} from '@apollo/client';

import { api } from '#config';

import App from './App';

const webappRootId = 'webapp-root';
const webappRootElement = document.getElementById(webappRootId);

const APP_GRAPHQL_ENDPOINT = 'http://localhost:8000/graphql/';
const client = new ApolloClient({
uri: api,
uri: APP_GRAPHQL_ENDPOINT,
cache: new InMemoryCache(),
});

if (!webappRootElement) {
// eslint-disable-next-line no-console
console.error(`Could not find html element with id '${webappRootId}'`);
Expand Down
6 changes: 6 additions & 0 deletions src/views/SourcesList/SourceCard/i18n.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"namespace": "sourceCard",
"strings": {
"sourceCardAlt": "Logo"
}
}
52 changes: 52 additions & 0 deletions src/views/SourcesList/SourceCard/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { Link } from 'react-router-dom';
import {
Container,
Header,
} from '@ifrc-go/ui';
import { useTranslation } from '@ifrc-go/ui/hooks';

import { SourceFeedsQuery } from '#generated/types/graphql';

import i18n from './i18n.json';
import styles from './styles.module.css';

type SourceFeed = NonNullable<NonNullable<SourceFeedsQuery['public']>['feeds']>['items'][number];

interface Props {
data: SourceFeed;
}

function SourceCard(props: Props) {
const {
data,
} = props;

const strings = useTranslation(i18n);

return (
<Link
className={styles.sourceCard}
to={data?.url}
>
<Container
childrenContainerClassName={styles.sourceDetail}
>
<img
className={styles.figure}
src={data?.languages?.map((image) => image.logo)?.[0] || ''}
alt={strings.sourceCardAlt}
/>
<div className={styles.title}>
<Header
heading={data?.languages?.map((lang) => lang.name)}
headingLevel={6}
/>
<div className={styles.language}>
{data?.languages?.map((name) => name.language)}
</div>
</div>
</Container>
</Link>
);
}
export default SourceCard;
33 changes: 33 additions & 0 deletions src/views/SourcesList/SourceCard/styles.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
.source-card {
display: flex;
gap: var(--go-ui-spacing-md);
text-decoration: none;

.source-detail {
display: flex;
gap: var(--go-ui-spacing-lg);
border-radius: var(--go-ui-border-radius-lg);
box-shadow: var(--go-ui-box-shadow-md);
padding: var(--go-ui-spacing-lg);

.title {
display: flex;
flex-direction: column;
gap: var(--go-ui-spacing-md);
justify-content: space-between;
color: var(--go-ui-color-text);
}

.language {
width: fit-content;
text-decoration: none;
color: var(--go-ui-color-gray-60);
font-weight: var(--go-ui-font-weight-medium);
}

.figure {
width: 10rem;
height: 4rem;
}
}
}
6 changes: 6 additions & 0 deletions src/views/SourcesList/i18n.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"namespace": "viewAllSource",
"strings": {
"sourceFeedsTitle":"Source Feeds"
}
}
115 changes: 115 additions & 0 deletions src/views/SourcesList/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
import {
useCallback,
useMemo,
useState,
} from 'react';
import {
gql,
useQuery,
} from '@apollo/client';
import {
Container,
List,
Pager,
} from '@ifrc-go/ui';
import { useTranslation } from '@ifrc-go/ui/hooks';
import { isDefined } from '@togglecorp/fujs';

import Page from '#components/Page';
import {
SourceFeedsQuery,
SourceFeedsQueryVariables,
} from '#generated/types/graphql';

import SourceCard from './SourceCard';

import i18n from './i18n.json';
import styles from './style.module.css';

const SOURCE_FEEDS = gql`
query SourceFeeds($pagination: OffsetPaginationInput) {
public {
feeds(pagination: $pagination) {
limit
offset
items {
languages {
logo
name
language
id
}
id
url
}
count
}
}
}
`;

type SourceFeed = NonNullable<NonNullable<SourceFeedsQuery['public']>['feeds']>['items'][number];

const MAX_ITEM_PER_PAGE = 21;

const keySelector = (source: SourceFeed) => source.id;

// eslint-disable-next-line import/prefer-default-export
export function Component() {
const strings = useTranslation(i18n);
const [activePage, setActivePage] = useState(1);

const variables = useMemo(() => ({
pagination: {
offset: (activePage - 1) * MAX_ITEM_PER_PAGE,
limit: MAX_ITEM_PER_PAGE,
},
}), [
activePage,
]);

const {
data: sourceFeedsResponse,
loading: sourceFeedsLoading,
error: sourceFeedsError,
} = useQuery<SourceFeedsQuery, SourceFeedsQueryVariables>(
SOURCE_FEEDS,
{
variables,
},
);

const rendererParams = useCallback((_: string, value: SourceFeed) => ({
data: value,
}), []);

return (
<Page>
<Container
heading={strings.sourceFeedsTitle}
withHeaderBorder
footerActions={(
<Pager
activePage={activePage}
itemsCount={sourceFeedsResponse?.public?.feeds?.count ?? MAX_ITEM_PER_PAGE}
maxItemsPerPage={MAX_ITEM_PER_PAGE}
onActivePageChange={setActivePage}
/>
)}
>
<List
className={styles.sourcesList}
data={sourceFeedsResponse?.public.feeds.items}
renderer={SourceCard}
rendererParams={rendererParams}
keySelector={keySelector}
pending={sourceFeedsLoading}
filtered={false}
errored={isDefined(sourceFeedsError)}
/>
</Container>
</Page>
);
}

Component.displayName = 'SourcesList';
5 changes: 5 additions & 0 deletions src/views/SourcesList/style.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
.sources-list {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(23rem, 1fr));
grid-gap: var(--go-ui-spacing-lg);
}
Loading

0 comments on commit fadd1f6

Please sign in to comment.