Add comparators for multilangual fields

This commit is contained in:
Kacper Donat 2020-11-18 23:06:06 +01:00
parent 96b1dafb65
commit 092171d27f
4 changed files with 40 additions and 14 deletions

View File

@ -0,0 +1,15 @@
import { Multilingual } from "@/data";
import React from "react";
import { Chip } from "@material-ui/core";
export type MultilingualCellProps = { value: Multilingual<React.ReactNode> }
export const MultilingualCell = ({ value }: MultilingualCellProps) => {
return <>
{ Object.keys(value).map(language => <div>
<Chip size="small" label={ language.toUpperCase() } style={ { marginRight: "0.5rem" } }/>
{ value[language as keyof Multilingual<any>] }
</div>) }
</>
}

View File

@ -2,6 +2,7 @@ import React from "react";
import { Column } from "material-table"; import { Column } from "material-table";
import { Actions } from "@/components"; import { Actions } from "@/components";
import { Trans } from "react-i18next"; import { Trans } from "react-i18next";
import { Multilingual } from "@/data";
export function actionsColumn<T extends Object>(render: (value: T) => React.ReactNode): Column<T> { export function actionsColumn<T extends Object>(render: (value: T) => React.ReactNode): Column<T> {
return { return {
@ -18,3 +19,17 @@ export function actionsColumn<T extends Object>(render: (value: T) => React.Reac
export function createBoundComponent<T, TBoundProps extends keyof T>(Component: React.ComponentType<T>, bound: Pick<T, TBoundProps>) { export function createBoundComponent<T, TBoundProps extends keyof T>(Component: React.ComponentType<T>, bound: Pick<T, TBoundProps>) {
return (props: Omit<T, TBoundProps>) => <Component { ...bound as any } { ...props } />; return (props: Omit<T, TBoundProps>) => <Component { ...bound as any } { ...props } />;
} }
export type Comparator<T> = (a: T, b: T) => number;
export type MultilingualComparator<T> = Comparator<Multilingual<T>>;
export function createMultilingualComparator<T>(comparator: Comparator<T>): MultilingualComparator<T> {
return (a, b) => comparator(a.pl, b.pl);
}
export const multilingualStringComparator = createMultilingualComparator<string>((a, b) => a && b ? a.localeCompare(b) : 0)
export const multilingualNumberComparator = createMultilingualComparator<number>((a, b) => a - b)
export function fieldComparator<T, K extends keyof T>(field: K, comparator: Comparator<T[K]>): Comparator<T> {
return (a, b) => comparator(a[field], b[field])
}

View File

@ -20,8 +20,9 @@ import { Confirm } from "@/components/confirm";
import useTheme from "@material-ui/core/styles/useTheme"; import useTheme from "@material-ui/core/styles/useTheme";
import { BulkActions } from "@/management/common/BulkActions"; import { BulkActions } from "@/management/common/BulkActions";
import { MaterialTableTitle } from "@/management/common/MaterialTableTitle"; import { MaterialTableTitle } from "@/management/common/MaterialTableTitle";
import { actionsColumn } from "@/management/common/helpers"; import { actionsColumn, fieldComparator, multilingualStringComparator } from "@/management/common/helpers";
import { createDeleteAction } from "@/management/common/DeleteResourceAction"; import { createDeleteAction } from "@/management/common/DeleteResourceAction";
import { MultilingualCell } from "@/management/common/MultilangualCell";
const label = (page: StaticPage) => page.title.pl; const label = (page: StaticPage) => page.title.pl;
@ -93,8 +94,9 @@ export const StaticPageManagement = () => {
const columns: Column<StaticPage>[] = [ const columns: Column<StaticPage>[] = [
{ {
render: page => page.title.pl, render: page => <MultilingualCell value={ page.title }/>,
title: t("page.field.title"), title: t("page.field.title"),
customSort: fieldComparator("title", multilingualStringComparator),
}, },
{ {
field: "slug", field: "slug",

View File

@ -2,32 +2,24 @@ import { Page } from "@/pages/base";
import React, { useEffect, useState } from "react"; import React, { useEffect, useState } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { useAsyncState } from "@/hooks"; import { useAsyncState } from "@/hooks";
import { InternshipType, Multilingual } from "@/data"; import { InternshipType } from "@/data";
import api from "@/management/api"; import api from "@/management/api";
import { Management } from "@/management/main"; import { Management } from "@/management/main";
import { Button, Chip, Container, Tooltip, Typography } from "@material-ui/core"; import { Button, Container, Tooltip, Typography } from "@material-ui/core";
import { Async } from "@/components/async"; import { Async } from "@/components/async";
import MaterialTable, { Column } from "material-table"; import MaterialTable, { Column } from "material-table";
import { MaterialTableTitle } from "@/management/common/MaterialTableTitle"; import { MaterialTableTitle } from "@/management/common/MaterialTableTitle";
import { actionsColumn } from "@/management/common/helpers"; import { actionsColumn, fieldComparator, multilingualStringComparator } from "@/management/common/helpers";
import { AccountCheck, Delete, Refresh, ShieldCheck } from "mdi-material-ui"; import { AccountCheck, Delete, Refresh, ShieldCheck } from "mdi-material-ui";
import { OneOrMany } from "@/helpers"; import { OneOrMany } from "@/helpers";
import { createDeleteAction } from "@/management/common/DeleteResourceAction"; import { createDeleteAction } from "@/management/common/DeleteResourceAction";
import { BulkActions } from "@/management/common/BulkActions"; import { BulkActions } from "@/management/common/BulkActions";
import { useSpacing } from "@/styles"; import { useSpacing } from "@/styles";
import { Actions } from "@/components"; import { Actions } from "@/components";
import { MultilingualCell } from "@/management/common/MultilangualCell";
const title = "type.index.title"; const title = "type.index.title";
const MultilingualCell = ({ value }: { value: Multilingual<React.ReactNode> }) => {
return <>
{ Object.keys(value).map(language => <div>
<Chip size="small" label={ language.toUpperCase() } style={ { marginRight: "0.5rem" } }/>
{ value[language as keyof Multilingual<any>] }
</div>) }
</>
}
const label = (type: InternshipType) => type?.label?.pl; const label = (type: InternshipType) => type?.label?.pl;
export const InternshipTypeManagement = () => { export const InternshipTypeManagement = () => {
@ -60,10 +52,12 @@ export const InternshipTypeManagement = () => {
{ {
title: t("type.field.label"), title: t("type.field.label"),
render: type => <MultilingualCell value={ type.label }/>, render: type => <MultilingualCell value={ type.label }/>,
customSort: fieldComparator("label", multilingualStringComparator),
}, },
{ {
title: t("type.field.description"), title: t("type.field.description"),
render: type => type.description && <MultilingualCell value={ type.description }/>, render: type => type.description && <MultilingualCell value={ type.description }/>,
sorting: false,
}, },
{ {
title: t("type.field.flags"), title: t("type.field.flags"),