We'll be building a demo app to manage hackathons with refine. We'll be able to create new hackathons, new project entries for a hackathon and criterias for a hackathon.
We'll use supabase as the backend service. refine comes with a builtin data provider for supabase thus it's very easy to create crud pages.
Creating tables
Our app will have these tables in supabase
- criterias
- hackathons
- hackathoners
- projects
- projectscores
These are reflected in our app as
export type HackathonerType = {
id: string;
name: string;
};
export type HackathonType = {
id: string;
start: string;
end: string;
name: string;
};
export type ProjectType = {
id: string;
name: string;
description: string;
url: string;
hackathon_id: string;
hackathoner_id: string;
};
export type CriteriaType = {
id: string;
name: string;
hackathon_id: string;
};
export type ProjectScoreType = {
project_id: string;
criteria_id: string;
score: string;
};
Craeting CRUD pages
Creating crud pages is as easy like this:
List page:
import {
List,
Table,
useTable,
Space,
ShowButton,
EditButton,
TextField,
} from "@pankod/refine";
import dayjs from "dayjs";
import { HackathonType } from "interfaces";
export const HackathonsList: React.FC = () => {
const { tableProps } = useTable<HackathonType>();
return (
<List>
<Table {...tableProps} rowKey="id">
<Table.Column dataIndex="id" title="ID" />
<Table.Column dataIndex="name" title="Name" />
<Table.Column
dataIndex="start"
title="Starts"
render={(value) => (
<TextField value={dayjs(value).format("DD/MMMM dddd")} />
)}
/>
<Table.Column
dataIndex="end"
title="Ends"
render={(value) => (
<TextField value={dayjs(value).format("DD/MMMM dddd")} />
)}
/>
<Table.Column
title="Actions"
dataIndex="actions"
render={(_text, record: HackathonType): React.ReactNode => {
return (
<Space>
<ShowButton size="small" recordItemId={record.id} hideText />
<EditButton size="small" recordItemId={record.id} hideText />
</Space>
);
}}
/>
</Table>
</List>
);
};
Create page:
import { Create, Form, Input, useForm, DatePicker } from "@pankod/refine";
import { HackathonType } from "interfaces";
export const HackathonsCreate: React.FC = () => {
const { formProps, saveButtonProps } = useForm<HackathonType>();
return (
<Create saveButtonProps={saveButtonProps}>
<Form {...formProps} layout="vertical">
<Form.Item label="Name" name="name">
<Input />
</Form.Item>
<Form.Item label="Name" name="start">
<DatePicker />
</Form.Item>
<Form.Item label="Name" name="end">
<DatePicker />
</Form.Item>
</Form>
</Create>
);
};
Then use these pages as the corresponding crud component for the hackathon
resource:
import { Refine, Resource } from "@pankod/refine";
import "@pankod/refine/dist/styles.min.css";
import { dataProvider } from "@pankod/refine-supabase";
import { supabaseClient } from "utility";
import {
HackathonsList,
HackathonsCreate,
HackathonsEdit,
HackathonsShow,
} from "./pages/hackathons";
function App() {
return (
<Refine
dataProvider={dataProvider(supabaseClient)}
>
<Resource
name="hackathons"
list={HackathonsList}
create={HackathonsCreate}
edit={HackathonsEdit}
show={HackathonsShow}
/>
</Refine>
);
}
export default App;
refine comes with builtin hooks for Ant design components. You can find detailed usage for the hooks and supabase in the documentation
Creating voting page
We'll use the dashboard option to place voting page. We'll need data from different resources. refine comes with powerful hooks that are based on react-query to get data from those resources.
For example to get the hackathons that are active now we can use the useList
hook:
export const DashboardPage: React.FC = () => {
const currentHackathons = useList<HackathonType>({
resource: "hackathons",
config: {
filters: [
{
field: "start",
operator: "lte",
value: now,
},
{
field: "end",
operator: "gte",
value: now,
},
],
},
});
}
We can get data from other resources in a similar fashion. You can find the codesandbox here and the repo here
Conclusion
This project itself is a product of a hackathon. It lacks lots of feature like authorization though it shows how refine makes it easy to quickly build a working app.
Top comments (0)