From 6caed9165bb008b6551ba0c9e2e3497754c83287 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Necati=20=C3=96zmen?= Date: Tue, 13 Feb 2024 16:37:23 +0300 Subject: [PATCH] docs(blog): update blog posts (#5634) * docs(blog): update create refine commands * docs(blog): remove dead posts * chore: remove examples of deleted posts * chore: add removed posts redirections --- ...021-10-25-mail-subscription-with-refine.md | 451 ---------- .../blog/2021-10-4-feedback-admin-panel.md | 399 --------- .../blog/2021-10-4-manage-hackatons.md | 226 ----- .../blog/2021-10-4-simple-web-application.md | 775 ------------------ documentation/blog/2021-12-13-web3-refine.md | 67 -- .../blog/2022-02-12-implement-darkmode.md | 307 ------- .../blog/2022-02-14-refine-ecommerce-blog.md | 708 ---------------- .../blog/2022-02-21-become-production-hero.md | 91 -- ...y-accesscontrol-admin-panel-with-nestjs.md | 176 ---- .../blog/2022-04-29-create-full-stack-app.md | 249 ------ .../2023-07-26-refine-primereact-dashboard.md | 2 +- .../blog/2023-10-06-react-hot-toast.md | 1 + documentation/blog/authors.yml | 12 - documentation/redirects.json | 40 + examples/blog-hackathonize/.gitignore | 23 - examples/blog-hackathonize/README.MD | 29 - examples/blog-hackathonize/package.json | 46 -- examples/blog-hackathonize/public/favicon.ico | Bin 7406 -> 0 bytes examples/blog-hackathonize/public/index.html | 40 - examples/blog-hackathonize/public/refine.svg | 10 - examples/blog-hackathonize/src/App.tsx | 226 ----- .../blog-hackathonize/src/authProvider.ts | 121 --- examples/blog-hackathonize/src/index.tsx | 12 - .../blog-hackathonize/src/interfaces/index.ts | 38 - examples/blog-hackathonize/src/meta.json | 4 - .../src/pages/criterias/create.tsx | 28 - .../src/pages/criterias/edit.tsx | 28 - .../src/pages/criterias/index.ts | 4 - .../src/pages/criterias/list.tsx | 76 -- .../src/pages/criterias/show.tsx | 28 - .../src/pages/dashboard/index.tsx | 172 ---- .../src/pages/hackathoners/create.tsx | 29 - .../src/pages/hackathoners/edit.tsx | 27 - .../src/pages/hackathoners/index.ts | 4 - .../src/pages/hackathoners/list.tsx | 74 -- .../src/pages/hackathoners/show.tsx | 28 - .../src/pages/hackathons/create.tsx | 25 - .../src/pages/hackathons/edit.tsx | 33 - .../src/pages/hackathons/index.ts | 4 - .../src/pages/hackathons/list.tsx | 64 -- .../src/pages/hackathons/show.tsx | 23 - .../src/pages/login/index.tsx | 130 --- .../src/pages/login/styles.css | 24 - .../src/pages/projects/create.tsx | 43 - .../src/pages/projects/edit.tsx | 43 - .../src/pages/projects/index.ts | 4 - .../src/pages/projects/list.tsx | 108 --- .../src/pages/projects/show.tsx | 41 - .../src/pages/teams/create.tsx | 19 - .../src/pages/teams/edit.tsx | 19 - .../src/pages/teams/index.ts | 4 - .../src/pages/teams/list.tsx | 38 - .../src/pages/teams/show.tsx | 24 - .../blog-hackathonize/src/react-app-env.d.ts | 1 - examples/blog-hackathonize/src/setupTests.ts | 5 - .../blog-hackathonize/src/utility/index.ts | 1 - .../src/utility/supabaseClient.ts | 14 - examples/blog-hackathonize/tsconfig.json | 21 - examples/blog-mail-subscription/.gitignore | 23 - examples/blog-mail-subscription/README.MD | 29 - examples/blog-mail-subscription/package.json | 48 -- .../blog-mail-subscription/public/favicon.ico | Bin 7406 -> 0 bytes .../blog-mail-subscription/public/index.html | 40 - .../public/refine-collapsed.svg | 3 - .../blog-mail-subscription/public/refine.svg | 10 - examples/blog-mail-subscription/src/App.tsx | 136 --- .../src/authProvider.ts | 96 --- .../src/components/footer/index.tsx | 3 - .../src/components/header/index.tsx | 40 - .../src/components/index.ts | 6 - .../src/components/layout/index.tsx | 24 - .../src/components/offLayoutArea/index.tsx | 3 - .../src/components/sider/index.tsx | 71 -- .../src/components/sider/styles.ts | 10 - .../src/components/title/index.tsx | 31 - examples/blog-mail-subscription/src/index.tsx | 12 - .../src/interfaces/index.d.ts | 25 - examples/blog-mail-subscription/src/meta.json | 4 - .../src/pages/mail/create.tsx | 45 - .../src/pages/mail/index.tsx | 2 - .../src/pages/mail/list.tsx | 28 - .../src/pages/subscriber/create.tsx | 34 - .../src/pages/subscriber/index.tsx | 2 - .../src/pages/subscriber/list.tsx | 39 - .../src/react-app-env.d.ts | 1 - .../blog-mail-subscription/src/setupTests.ts | 5 - examples/blog-mail-subscription/tsconfig.json | 21 - examples/blog-refeedback/.gitignore | 23 - examples/blog-refeedback/README.md | 29 - examples/blog-refeedback/package.json | 48 -- examples/blog-refeedback/public/favicon.ico | Bin 7406 -> 0 bytes examples/blog-refeedback/public/index.html | 40 - .../blog-refeedback/public/refeedback.png | Bin 4268 -> 0 bytes .../public/refine-collapsed.svg | 3 - examples/blog-refeedback/public/refine.svg | 10 - examples/blog-refeedback/src/App.tsx | 122 --- examples/blog-refeedback/src/authProvider.ts | 97 --- .../src/components/feedback/index.tsx | 92 --- .../src/components/feedback/inputPage.tsx | 67 -- .../src/components/feedback/typePage.tsx | 68 -- .../src/components/header/index.tsx | 26 - .../blog-refeedback/src/components/index.ts | 4 - .../src/components/layout/index.tsx | 22 - .../src/components/offLayoutArea/index.tsx | 5 - examples/blog-refeedback/src/index.tsx | 12 - .../blog-refeedback/src/interfaces/index.d.ts | 19 - examples/blog-refeedback/src/meta.json | 4 - .../src/pages/FeedbackList.tsx | 160 ---- .../blog-refeedback/src/react-app-env.d.ts | 1 - examples/blog-refeedback/src/setupTests.ts | 5 - .../blog-refeedback/src/styles/global.css | 26 - examples/blog-refeedback/tsconfig.json | 21 - examples/blog-refineflix/.gitignore | 23 - examples/blog-refineflix/README.MD | 29 - examples/blog-refineflix/package.json | 46 -- examples/blog-refineflix/public/favicon.ico | Bin 7406 -> 0 bytes examples/blog-refineflix/public/index.html | 37 - .../public/refine-collapsed.svg | 3 - examples/blog-refineflix/public/refine.svg | 10 - examples/blog-refineflix/src/App.tsx | 133 --- examples/blog-refineflix/src/authProvider.ts | 130 --- .../src/components/footer/index.tsx | 3 - .../src/components/header/index.tsx | 21 - .../blog-refineflix/src/components/index.ts | 6 - .../src/components/layout/index.tsx | 29 - .../src/components/offLayoutArea/index.tsx | 3 - .../src/components/sider/index.tsx | 71 -- .../src/components/sider/styles.ts | 10 - .../src/components/title/index.tsx | 32 - examples/blog-refineflix/src/index.tsx | 12 - .../blog-refineflix/src/interfaces/index.d.ts | 11 - examples/blog-refineflix/src/meta.json | 4 - .../src/pages/admin/movies/create.tsx | 90 -- .../src/pages/admin/movies/edit.tsx | 96 --- .../src/pages/admin/movies/index.tsx | 4 - .../src/pages/admin/movies/list.tsx | 65 -- .../src/pages/admin/movies/show.tsx | 70 -- .../blog-refineflix/src/pages/login/index.tsx | 130 --- .../src/pages/login/styles.css | 24 - .../blog-refineflix/src/pages/movies/index.ts | 2 - .../blog-refineflix/src/pages/movies/list.tsx | 62 -- .../blog-refineflix/src/pages/movies/show.tsx | 60 -- .../blog-refineflix/src/react-app-env.d.ts | 1 - examples/blog-refineflix/src/setupTests.ts | 5 - examples/blog-refineflix/src/utility/index.ts | 2 - .../blog-refineflix/src/utility/normalize.ts | 27 - .../src/utility/supabaseClient.ts | 15 - examples/blog-refineflix/tsconfig.json | 21 - 148 files changed, 42 insertions(+), 8179 deletions(-) delete mode 100644 documentation/blog/2021-10-25-mail-subscription-with-refine.md delete mode 100644 documentation/blog/2021-10-4-feedback-admin-panel.md delete mode 100644 documentation/blog/2021-10-4-manage-hackatons.md delete mode 100644 documentation/blog/2021-10-4-simple-web-application.md delete mode 100644 documentation/blog/2021-12-13-web3-refine.md delete mode 100644 documentation/blog/2022-02-12-implement-darkmode.md delete mode 100644 documentation/blog/2022-02-14-refine-ecommerce-blog.md delete mode 100644 documentation/blog/2022-02-21-become-production-hero.md delete mode 100644 documentation/blog/2022-02-21-build-low-code-customizable-and-authorization-ready-accesscontrol-admin-panel-with-nestjs.md delete mode 100644 documentation/blog/2022-04-29-create-full-stack-app.md delete mode 100644 examples/blog-hackathonize/.gitignore delete mode 100644 examples/blog-hackathonize/README.MD delete mode 100644 examples/blog-hackathonize/package.json delete mode 100644 examples/blog-hackathonize/public/favicon.ico delete mode 100644 examples/blog-hackathonize/public/index.html delete mode 100644 examples/blog-hackathonize/public/refine.svg delete mode 100644 examples/blog-hackathonize/src/App.tsx delete mode 100644 examples/blog-hackathonize/src/authProvider.ts delete mode 100644 examples/blog-hackathonize/src/index.tsx delete mode 100644 examples/blog-hackathonize/src/interfaces/index.ts delete mode 100644 examples/blog-hackathonize/src/meta.json delete mode 100644 examples/blog-hackathonize/src/pages/criterias/create.tsx delete mode 100644 examples/blog-hackathonize/src/pages/criterias/edit.tsx delete mode 100644 examples/blog-hackathonize/src/pages/criterias/index.ts delete mode 100644 examples/blog-hackathonize/src/pages/criterias/list.tsx delete mode 100644 examples/blog-hackathonize/src/pages/criterias/show.tsx delete mode 100644 examples/blog-hackathonize/src/pages/dashboard/index.tsx delete mode 100644 examples/blog-hackathonize/src/pages/hackathoners/create.tsx delete mode 100644 examples/blog-hackathonize/src/pages/hackathoners/edit.tsx delete mode 100644 examples/blog-hackathonize/src/pages/hackathoners/index.ts delete mode 100644 examples/blog-hackathonize/src/pages/hackathoners/list.tsx delete mode 100644 examples/blog-hackathonize/src/pages/hackathoners/show.tsx delete mode 100644 examples/blog-hackathonize/src/pages/hackathons/create.tsx delete mode 100644 examples/blog-hackathonize/src/pages/hackathons/edit.tsx delete mode 100644 examples/blog-hackathonize/src/pages/hackathons/index.ts delete mode 100644 examples/blog-hackathonize/src/pages/hackathons/list.tsx delete mode 100644 examples/blog-hackathonize/src/pages/hackathons/show.tsx delete mode 100644 examples/blog-hackathonize/src/pages/login/index.tsx delete mode 100644 examples/blog-hackathonize/src/pages/login/styles.css delete mode 100644 examples/blog-hackathonize/src/pages/projects/create.tsx delete mode 100644 examples/blog-hackathonize/src/pages/projects/edit.tsx delete mode 100644 examples/blog-hackathonize/src/pages/projects/index.ts delete mode 100644 examples/blog-hackathonize/src/pages/projects/list.tsx delete mode 100644 examples/blog-hackathonize/src/pages/projects/show.tsx delete mode 100644 examples/blog-hackathonize/src/pages/teams/create.tsx delete mode 100644 examples/blog-hackathonize/src/pages/teams/edit.tsx delete mode 100644 examples/blog-hackathonize/src/pages/teams/index.ts delete mode 100644 examples/blog-hackathonize/src/pages/teams/list.tsx delete mode 100644 examples/blog-hackathonize/src/pages/teams/show.tsx delete mode 100644 examples/blog-hackathonize/src/react-app-env.d.ts delete mode 100644 examples/blog-hackathonize/src/setupTests.ts delete mode 100644 examples/blog-hackathonize/src/utility/index.ts delete mode 100644 examples/blog-hackathonize/src/utility/supabaseClient.ts delete mode 100644 examples/blog-hackathonize/tsconfig.json delete mode 100644 examples/blog-mail-subscription/.gitignore delete mode 100644 examples/blog-mail-subscription/README.MD delete mode 100644 examples/blog-mail-subscription/package.json delete mode 100644 examples/blog-mail-subscription/public/favicon.ico delete mode 100644 examples/blog-mail-subscription/public/index.html delete mode 100644 examples/blog-mail-subscription/public/refine-collapsed.svg delete mode 100644 examples/blog-mail-subscription/public/refine.svg delete mode 100644 examples/blog-mail-subscription/src/App.tsx delete mode 100644 examples/blog-mail-subscription/src/authProvider.ts delete mode 100644 examples/blog-mail-subscription/src/components/footer/index.tsx delete mode 100644 examples/blog-mail-subscription/src/components/header/index.tsx delete mode 100644 examples/blog-mail-subscription/src/components/index.ts delete mode 100644 examples/blog-mail-subscription/src/components/layout/index.tsx delete mode 100644 examples/blog-mail-subscription/src/components/offLayoutArea/index.tsx delete mode 100644 examples/blog-mail-subscription/src/components/sider/index.tsx delete mode 100644 examples/blog-mail-subscription/src/components/sider/styles.ts delete mode 100644 examples/blog-mail-subscription/src/components/title/index.tsx delete mode 100644 examples/blog-mail-subscription/src/index.tsx delete mode 100644 examples/blog-mail-subscription/src/interfaces/index.d.ts delete mode 100644 examples/blog-mail-subscription/src/meta.json delete mode 100644 examples/blog-mail-subscription/src/pages/mail/create.tsx delete mode 100644 examples/blog-mail-subscription/src/pages/mail/index.tsx delete mode 100644 examples/blog-mail-subscription/src/pages/mail/list.tsx delete mode 100644 examples/blog-mail-subscription/src/pages/subscriber/create.tsx delete mode 100644 examples/blog-mail-subscription/src/pages/subscriber/index.tsx delete mode 100644 examples/blog-mail-subscription/src/pages/subscriber/list.tsx delete mode 100644 examples/blog-mail-subscription/src/react-app-env.d.ts delete mode 100644 examples/blog-mail-subscription/src/setupTests.ts delete mode 100644 examples/blog-mail-subscription/tsconfig.json delete mode 100644 examples/blog-refeedback/.gitignore delete mode 100644 examples/blog-refeedback/README.md delete mode 100644 examples/blog-refeedback/package.json delete mode 100644 examples/blog-refeedback/public/favicon.ico delete mode 100644 examples/blog-refeedback/public/index.html delete mode 100644 examples/blog-refeedback/public/refeedback.png delete mode 100644 examples/blog-refeedback/public/refine-collapsed.svg delete mode 100644 examples/blog-refeedback/public/refine.svg delete mode 100644 examples/blog-refeedback/src/App.tsx delete mode 100644 examples/blog-refeedback/src/authProvider.ts delete mode 100644 examples/blog-refeedback/src/components/feedback/index.tsx delete mode 100644 examples/blog-refeedback/src/components/feedback/inputPage.tsx delete mode 100644 examples/blog-refeedback/src/components/feedback/typePage.tsx delete mode 100644 examples/blog-refeedback/src/components/header/index.tsx delete mode 100644 examples/blog-refeedback/src/components/index.ts delete mode 100644 examples/blog-refeedback/src/components/layout/index.tsx delete mode 100644 examples/blog-refeedback/src/components/offLayoutArea/index.tsx delete mode 100644 examples/blog-refeedback/src/index.tsx delete mode 100644 examples/blog-refeedback/src/interfaces/index.d.ts delete mode 100644 examples/blog-refeedback/src/meta.json delete mode 100644 examples/blog-refeedback/src/pages/FeedbackList.tsx delete mode 100644 examples/blog-refeedback/src/react-app-env.d.ts delete mode 100644 examples/blog-refeedback/src/setupTests.ts delete mode 100644 examples/blog-refeedback/src/styles/global.css delete mode 100644 examples/blog-refeedback/tsconfig.json delete mode 100644 examples/blog-refineflix/.gitignore delete mode 100644 examples/blog-refineflix/README.MD delete mode 100644 examples/blog-refineflix/package.json delete mode 100644 examples/blog-refineflix/public/favicon.ico delete mode 100644 examples/blog-refineflix/public/index.html delete mode 100644 examples/blog-refineflix/public/refine-collapsed.svg delete mode 100644 examples/blog-refineflix/public/refine.svg delete mode 100644 examples/blog-refineflix/src/App.tsx delete mode 100644 examples/blog-refineflix/src/authProvider.ts delete mode 100644 examples/blog-refineflix/src/components/footer/index.tsx delete mode 100644 examples/blog-refineflix/src/components/header/index.tsx delete mode 100644 examples/blog-refineflix/src/components/index.ts delete mode 100644 examples/blog-refineflix/src/components/layout/index.tsx delete mode 100644 examples/blog-refineflix/src/components/offLayoutArea/index.tsx delete mode 100644 examples/blog-refineflix/src/components/sider/index.tsx delete mode 100644 examples/blog-refineflix/src/components/sider/styles.ts delete mode 100644 examples/blog-refineflix/src/components/title/index.tsx delete mode 100644 examples/blog-refineflix/src/index.tsx delete mode 100644 examples/blog-refineflix/src/interfaces/index.d.ts delete mode 100644 examples/blog-refineflix/src/meta.json delete mode 100644 examples/blog-refineflix/src/pages/admin/movies/create.tsx delete mode 100644 examples/blog-refineflix/src/pages/admin/movies/edit.tsx delete mode 100644 examples/blog-refineflix/src/pages/admin/movies/index.tsx delete mode 100644 examples/blog-refineflix/src/pages/admin/movies/list.tsx delete mode 100644 examples/blog-refineflix/src/pages/admin/movies/show.tsx delete mode 100644 examples/blog-refineflix/src/pages/login/index.tsx delete mode 100644 examples/blog-refineflix/src/pages/login/styles.css delete mode 100644 examples/blog-refineflix/src/pages/movies/index.ts delete mode 100644 examples/blog-refineflix/src/pages/movies/list.tsx delete mode 100644 examples/blog-refineflix/src/pages/movies/show.tsx delete mode 100644 examples/blog-refineflix/src/react-app-env.d.ts delete mode 100644 examples/blog-refineflix/src/setupTests.ts delete mode 100644 examples/blog-refineflix/src/utility/index.ts delete mode 100644 examples/blog-refineflix/src/utility/normalize.ts delete mode 100644 examples/blog-refineflix/src/utility/supabaseClient.ts delete mode 100644 examples/blog-refineflix/tsconfig.json diff --git a/documentation/blog/2021-10-25-mail-subscription-with-refine.md b/documentation/blog/2021-10-25-mail-subscription-with-refine.md deleted file mode 100644 index 18e34d28ce2d..000000000000 --- a/documentation/blog/2021-10-25-mail-subscription-with-refine.md +++ /dev/null @@ -1,451 +0,0 @@ ---- -title: Create E-mail Subscription Panel with Refine and Strapi -description: We will make a web application that allows you to quickly create subscribers and send emails to your subscribers in a simple way. We’ll use Refine to develop the frontend easily and strapi for backend solutions. -slug: e-mail-subscription-panel-with-refine -authors: melih -tags: [Refine, strapi, react, tutorial] -image: https://refine.ams3.cdn.digitaloceanspaces.com/website/static/img/placeholder.png -hide_table_of_contents: false ---- - -:::caution - -This post was created using version 3.x.x of **Refine**. Although we plan to update it with the latest version of **Refine** as soon as possible, you can still benefit from the post in the meantime. - -You should know that **Refine** version 4.x.x is backward compatible with version 3.x.x, so there is no need to worry. If you want to see the differences between the two versions, check out the [migration guide](https://refine.dev/docs/migration-guide/). - -Just be aware that the source code example in this post have been updated to version 4.x.x. - -::: - -We will make a web application that allows you to quickly create subscribers and send emails to your subscribers in a simple way. We’ll use Refine to develop the frontend easily and strapi for backend solutions. - - - -Let's start by creating our strapi and Refine projects. - -## Creating API with `Strapi` - -```bash -npx create-strapi-app strapi-email-subscription-api --quickstart -``` - -After the project is loaded, the admin panel will open automatically open in the browser. We need to create an admin user in order to log in to the strapi. - -strapi - -With the information we will create here, we can now enter the strapi and start shaping our backend. - -After logging into the Strapi interface, we have two collection models that we need to create for our e-mail subscription project. - -We will create these collections from the Collection-Types Builder part of the strapi. - -> Subscribers - -- `name` text field -- `email` Email - -subscribers -
- -> Messages - -- `subject` text field -- `text` text field - -messages -
- -With these collections and features we have created, we can now create subscribers, delete them and make changes to them. - -## Creating panel with `refine` - -Now let's Refine the subscription panel. With [superplate](https://github.com/pankod/superplate), we can quickly create a Refine project - -```bash -npm create refine-app@latest email-subscription-panel -- -b v3 -``` - -Select the following options to complete the CLI wizard: - -```bash -? Select your project type: -> refine-react - -? What will be the name of your app: -> email-subscription-panel - -? Package manager: -> Npm - -? Do you want to use a UI Framework?: -❯ Ant Design - -? Do you want a customized theme?: -> Default theme - -? Router Provider: -❯ React Router v6 - -? Data Provider: -> Strapi - -? Do you want a customized layout?: -> Yes - -? i18n - Internationalization: -> No -``` - -After the upload is finished, let's go into our project and see how it looks. - -```bash -cd email-subscription-panel -npm run dev -``` - -This is a example Refine project: - -refine_welcome -
- -Let's list our messages and subscribers with refine. Here are the changes we need to make: - -- Change Strapi API URL from Refine -- Adding resources according to the collection name we created in Strapi - -```tsx title="App.tsx" -import { Refine, Resource } from "@pankod/refine"; - -import "@pankod/refine/dist/styles.min.css"; -import { DataProvider } from "@refinedev/strapi"; -import strapiAuthProvider from "authProvider"; -import { Header, Layout, OffLayoutArea } from "components"; - - -function App() { - - const API_URL = "your-strapi-api-url"; - + const API_URL = "http://localhost:1337"; - - const { authProvider, axiosInstance } = strapiAuthProvider(API_URL); - const dataProvider = DataProvider(API_URL, axiosInstance); - return ( - - ); -} - -export default App; - -``` - -signin -
- -After adding the resources, we need to define a user in the strapi in order to be able to login to the refine. - -auth -
- -Let's login with this user we created - -login - -We can now list subscribers and messages and make changes to our list. Before doing this, let's create test users and messages on the strapi side. - -dummy_data -
- -Create SubscriberList.tsx and MessagesList.tsx file under the pages folder. Then, let's create our component as follows with the components and hooks that come with refine. - -## Subscriber List - -```tsx title="/src/pages/subscriber/SubscriberList.tsx" -import React from "react"; -import { useTable, List, Table, DateField, DeleteButton, IResourceComponentsProps } from "@pankod/refine"; - -import { ISubscriber } from "interfaces"; - -export const SubscriberList: React.FC = () => { - const { tableProps } = useTable(); - return ( - - - - - - } - /> - - title="Unsubscribe" - dataIndex="actions" - render={(_, record): React.ReactNode => { - return ; - }} - /> -
-
- ); -}; -``` - -## Message List - -```tsx title="/src/pages/mail/MessageList.tsx" -import React from "react"; -import { useTable, List, Table, DateField, IResourceComponentsProps } from "@pankod/refine"; - -import { IMail } from "interfaces"; - -export const MessageList: React.FC = () => { - const { tableProps } = useTable(); - return ( - - - - - - } - /> -
-
- ); -}; -``` - -```tsx title="/src/interfaces/intex.d.ts" -export interface ISubscriber { - id: any; - name: string; - email: string; - created_at: string; -} - -export interface IMail { - subject: string; - text: string; - to: string; - create_at: string; -} -``` - -In this component: - -We used Refine's [list](https://refine.dev/docs/examples/list/useSimpleList) and [table](https://refine.dev/docs/api-reference/core/hooks/useTable/) to show our subscribers and messages. - -Now let's see how our subscriber panel looks like: - -`Subscriber:` - -refine_subs -
- -`Messages:` - -refine_messages -
- -As you can see, we were able to list our subscribers and e-mails very simply with refine. Now let's examine how we can create subscribers and messages from our interface. - -## Create Subscriber - -```tsx title="/src/pages/subscriber/create.tsx" -import { Create, Form, Input, useForm, IResourceComponentsProps } from "@pankod/refine"; - -import { ICreateSubscriber } from "interfaces"; - -export const CreateSubscriber: React.FC = () => { - const { formProps, saveButtonProps } = useForm(); - - return ( - -
- - - - - - -
-
- ); -}; -``` - -## Create Message - -```tsx title="/src/pages/mail/create.tsx" -import React from "react"; -import { Create, Form, Input, useForm, IResourceComponentsProps } from "@pankod/refine"; - -import MDEditor from "@uiw/react-md-editor"; -import { IMail } from "interfaces"; - -export const MailCreate: React.FC = () => { - const { formProps, saveButtonProps } = useForm(); - - return ( - - {console.log("create")} -
- - - - - - - - - -
-
- ); -}; -``` - -Using Refine's [form](https://refine.dev/docs/api-reference/antd/hooks/form/useForm/) and [create](https://refine.dev/docs/ui-frameworks/antd/components/basic-views/create/) components, we can now create subscribers and messages with refine. - -create -
- -We're done with our panel. We can now list, create and delete subscribers. Finally, the step of sending real mails using our panel and strapi is left. Let's see how we do this. - -## Strapi E-mail Plugin - -In order to send mail via Strapi, we need to install the [strapi-email](https://strapi.io/documentation/developer-docs/latest/development/plugins/email.html#programmatic-usage) plugin in our api project that we created above. - -Let's open our API project that we created and download the email plugin. - -```bash -cd strapi-email-subscription-api -npm install strapi-provider-email-sendgrid --save -``` - -After installing your plugin you will need to add some settings in config/plugins.js. If this file doesn't exists, you'll need to create it. - -### Configure your provider - -`Path — ./config/plugins.js` - -```jsx -module.exports = ({ env }) => ({ - email: { - provider: "sendgrid", - providerOptions: { - apiKey: env("SENDGRID_API_KEY"), - }, - settings: { - defaultFrom: "your-email-address", - defaultReplyTo: "your-email-address", - testAddress: "your-email-address", - }, - }, -}); -``` - -:::tip - -Strapi sends emails via sendgrid. That's why you need to create a [SendGrid](https://sendgrid.com/) account and get an api-key. - -::: - -Now, let's send the text and subject in the collection of messages we created over the strapi as parameters to the send() function of the email plugin. - -```jsx title="api/messages/controllers/messages.js" -const { parseMultipartData, sanitizeEntity } = require("strapi-utils"); - -module.exports = { - async create(ctx) { - let entity; - if (ctx.is("multipart")) { - const { data, files } = parseMultipartData(ctx); - entity = await strapi.services.messages.create(data, { files }); - } else { - entity = await strapi.services.messages.create(ctx.request.body); - } - - entity = sanitizeEntity(entity, { model: strapi.models.messages }); - - const { subject, text } = entity; - - const worker = (await strapi.services.subscribers.find()).map((subscriber) => { - let to = subscriber.email; - - return strapi.plugins["email"].services.email.send({ - subject, - text, - to, - }); - }); - - await Promise.all(worker); - - return entity; - }, -}; -``` - -Our project is finished. Let's try it now. - -overview -
- -Let's send the same e-mail to our subscribers shown in the picture at once. - -
-
-send -
- -Sending mail was successful. As you can see, we were able to send the same email to all subscribers by sending a single email. - -[Here is repo](https://github.com/refinedev/refine/tree/master/examples/blog-mail-subscription) diff --git a/documentation/blog/2021-10-4-feedback-admin-panel.md b/documentation/blog/2021-10-4-feedback-admin-panel.md deleted file mode 100644 index dee0ea06b0bb..000000000000 --- a/documentation/blog/2021-10-4-feedback-admin-panel.md +++ /dev/null @@ -1,399 +0,0 @@ ---- -title: Create a Feedback Admin panel in 15 Minutes with Refine and Strapi -description: We will quickly create an api with Strapi and then develop its frontend with refine. Thus, let's see how an admin panel can be created in a very short time with the perfect harmony of Strapi and refine. -slug: create-a-feedback-admin-panel-with-refine-and-strapi -authors: salih -tags: [Refine, strapi, react, tutorial] -image: https://refine.ams3.cdn.digitaloceanspaces.com/website/static/img/placeholder.png -hide_table_of_contents: false ---- - -:::caution - -This post was created using version 3.x.x of **Refine**. Although we plan to update it with the latest version of **Refine** as soon as possible, you can still benefit from the post in the meantime. - -You should know that **Refine** version 4.x.x is backward compatible with version 3.x.x, so there is no need to worry. If you want to see the differences between the two versions, check out the [migration guide](https://refine.dev/docs/migration-guide/). - -::: - -In this article, we will create a panel where we can manage the feedback we receive from our web application. - - - -We will quickly create an api with [Strapi.io](https://strapi.io) and then develop its frontend with [Refine](https://refine.dev). Thus, let's see how an admin panel can be created in a very short time with the perfect harmony of Strapi and refine. - -Features that our panel will have: - -- Authentication with strapi.io -- A page to list feedbacks -- Mutation on Feedbacks - -### Creating api with `Strapi` - -Let's create our backend project with Strapi's [quick start guide](https:/strapi.io/documentation/developer-docs/latest/getting-started/quick-start.html). - -```bash -npx create-strapi-app strapi-feedback-api --quickstart -``` - -After the installation is complete, the tab will automatically open in the browser. Here, let's create a `feedback` collection with Content-Types Builder. - -Quite simply, a feedback should have a `description` text field, A `page` text field that shows the page the feedback was sent from, and a `type` enumeration field indicating the type of feedback (issue, idea, other, archive). - -content -
- -### Creating panel with `refine` - -Let's create our frontend project with Refine's [setting up guide](https://refine.dev/docs/#setting-up). - -There are two alternative methods to set up a Refine application. We will quickly create our application with [superplate](https://pankod.github.io/superplate). - -```bash -npm create refine-app@latest refine-feedback-client -- -b v3 -``` - -Select the following options to complete the CLI wizard: - -``` -? Select your project type: -❯ refine-react - -? What will be the name of your app: -> refine-strapi-web - -? Package manager: -❯ Npm - -? Do you want to use a UI Framework?: -❯ Ant Design - -? Do you want a customized theme?: -❯ Default theme - -? Router Provider: -❯ React Router v6 - -? Data Provider: -❯ Strapi v3 - -? Do you want a customized layout? -❯ Yes - -? i18n - Internationalization: -❯ No -``` - -After the installation is completed, Strapi-specific [data provider](https://github.com/refinedev/refine/blob/master/packages/strapi), auth provider, and also layout components that we can change the default view of Refine with the custom layout option will be included in our project. - -Now, bootstrap the app with the following command: - -```bash -npm run dev -``` - -welcome -
- -Now let's list the changes we will make: - -- Change our Strapi API URL -- Remove components that we will not use when changing the refinement look -- Adding resources according to the collection name we created in Strapi - -```diff -+ import { Refine } from "@pankod/refine"; -import "@pankod/refine/dist/styles.min.css"; -import { DataProvider } from "@refinedev/strapi"; -import strapiAuthProvider from "authProvider"; -import { -- Title, - Header, -- Sider, -- Footer, - Layout, - OffLayoutArea, -} from "components"; - -function App() { -- const API_URL = "your-strapi-api-url"; -+ const API_URL = "http://localhost:1337"; - - const { authProvider, axiosInstance } = strapiAuthProvider(API_URL); - const dataProvider = DataProvider(API_URL, axiosInstance); - return ( - - ); -} - - -export default App; -``` - -After adding the resource, our auth provider was activated. - -signin -
- -Now let's create a user on the Strapi to be able to login to the application. - -user -
- -We created a user and login to the application with this user. - -feedback -
- -Let's customize the layout component, remove the sider and add a header. - -### Custom Layout - -```tsx -import React from "react"; -import { Layout as AntLayout } from "antd"; - -import { LayoutProps } from "@pankod/refine"; - -export const Layout: React.FC = ({ children, Header, OffLayoutArea }) => { - return ( - - -
- - {children} - - - - - ); -}; -``` - -Let's customize the header component too - -### Custom Header - -```tsx -import React from "react"; -import { Layout } from "antd"; - -export const Header: React.FC = () => { - return ( - - refeedback - - ); -}; -``` - -In the new view, there are no siders anymore and the header we have customized is here. - -header -
- -Now we come to the part where we can list our feedback and make changes to it. Before that, let's create dummy feedback records on Strapi. - -feedbacks -
- -Create a `FeedbackList.tsx` file under the `pages` folder. Then, let's create our component as follows with the components and hooks that come with refine. - -### Create FeedbackList - -```tsx -import { - List, - Typography, - AntdList, - useSimpleList, - CrudFilters, - Form, - HttpError, - Row, - Col, - Tag, - Radio, - Space, - Descriptions, - Button, - DateField, - Card, - useUpdate, -} from "@pankod/refine"; - -import { IFeedback, IFeedbackFilterVariables, FeedBackType } from "interfaces"; - -const { Paragraph } = Typography; - -const addTagColor = (type: FeedBackType) => { - switch (type) { - case "issue": - return "error"; - case "idea": - return "orange"; - default: - return "default"; - } -}; - -export const FeedbackList: React.FC = () => { - const { listProps, searchFormProps } = useSimpleList({ - sorters: { - initial: [{ field: "created_at", order: "desc" }], - }, - onSearch: (params) => { - const filters: CrudFilters = []; - const { type } = params; - - filters.push({ - field: "type", - operator: "eq", - value: type || undefined, - }); - - return filters; - }, - }); - - const { mutate, isLoading } = useUpdate(); - - const renderItem = (item: IFeedback) => { - const { id, description, type, page, created_at } = item; - return ( - - - - - {type} - - - - } - /> - {description} - - {page} - -
- -
-
-
- ); - }; - - return ( - - - -
searchFormProps.form?.submit()} - initialValues={{ - type: "", - }} - > - - - - All - Issue - Idea - Other - Archive - - - -
- - - - -
-
- ); -}; -``` - -```ts -export type FeedBackType = "idea" | "issue" | "other" | "archive"; - -export interface IFeedback { - id: string; - description: string; - page: string; - user: string; - type: FeedBackType; - created_at: Date; -} - -export interface IFeedbackFilterVariables { - type: FeedBackType; -} -``` - -In this component - -- We listed our records using the [`useSimpleList`](https://refine.dev/docs/ui-frameworks/antd/hooks/list/useSimpleList/) and [Ant Design](https://ant.design) [``](https://ant.design/components/list) component. -- We used Antd [`
`](https://ant.design/components/form/) component to filter our records. -- We made it possible to change the `type` of our record with [`useUpdate`](https://refine.dev/docs/api-reference/core/hooks/data/useUpdate/) - -See detailed usage of useSimpleList for adding new filters, adding search entries, dynamic sorting operations and more [here](https://refine.dev/docs/ui-frameworks/antd/hooks/list/useSimpleList/). - -### Overview - -feedback_overview -
- -Let's develop feedback widget where we can get feedback to expand the application a little more. For this application, I will develop this component with Refine, but you can create this component with Strapi APIs in any way you want. - -You can look at the code of the component I developed [here](https://github.com/refinedev/refine-hackathon/tree/main/refeedback/src/components/feedback). - -Now let's add this component to the `OfflayouArea` component and create feedback on the page and see how it comes to our feedback list. - -widgets -
- -You can find the source code of the project here: https://github.com/refinedev/refine/tree/master/examples/blog-refeedback diff --git a/documentation/blog/2021-10-4-manage-hackatons.md b/documentation/blog/2021-10-4-manage-hackatons.md deleted file mode 100644 index 5c763b507fd8..000000000000 --- a/documentation/blog/2021-10-4-manage-hackatons.md +++ /dev/null @@ -1,226 +0,0 @@ ---- -title: Let's Build an App to Manage Your Hackathons with Refine -description: We'll be building a demo app to manage hackathons with refine. -slug: manage-hackathons-with-refine -authors: muharrem -tags: [Refine, supabase, react, tutorial] -image: https://refine.ams3.cdn.digitaloceanspaces.com/website/static/img/placeholder.png -hide_table_of_contents: false ---- - -:::caution - -This post was created using version 3.x.x of **Refine**. Although we plan to update it with the latest version of **Refine** as soon as possible, you can still benefit from the post in the meantime. - -You should know that **Refine** version 4.x.x is backward compatible with version 3.x.x, so there is no need to worry. If you want to see the differences between the two versions, check out the [migration guide](https://refine.dev/docs/migration-guide/). - -::: - -We'll be building a demo app to manage hackathons with [Refine](https://refine.dev/). We'll be able to create new hackathons, new project entries for a hackathon and criteria for a hackathon. - - - -hackathons -
- -We'll use [supabase](https://supabase.io/) 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 - -- criteria -- hackathons -- hackathoners -- projects -- projectscores - -These are reflected in our app as - -```ts -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; -}; -``` - -## Creating CRUD pages - -Creating crud pages is as easy like this: - -List page: - -```tsx -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(); - - return ( - - - - - } - /> - } - /> - { - return ( - - - - - ); - }} - /> -
-
- ); -}; -``` - -## Create page: - -```tsx -import { Create, Form, Input, useForm, DatePicker } from "@pankod/refine"; - -import { HackathonType } from "interfaces"; - -export const HackathonsCreate: React.FC = () => { - const { formProps, saveButtonProps } = useForm(); - - return ( - - - - - - - - - - - - - - ); -}; -``` - -Then use these pages as the corresponding crud component for the `hackathon` resource: - -```tsx -import { Refine } from "@pankod/refine"; - -import "@pankod/refine/dist/styles.min.css"; -import { dataProvider } from "@refinedev/supabase"; -import { supabaseClient } from "utility"; -import { HackathonsList, HackathonsCreate, HackathonsEdit, HackathonsShow } from "./pages/hackathons"; - -function App() { - return ( - - ); -} - -export default App; -``` - -create -
- -**Refine** comes with builtin hooks for Ant design components. You can find detailed usage for the hooks and supabase in the [documentation](https://refine.dev/docs/) - -## 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: - -```tsx -export const DashboardPage: React.FC = () => { - const currentHackathons = useList({ - resource: "hackathons", - filters: [ - { - field: "start", - operator: "lte", - value: now, - }, - { - field: "end", - operator: "gte", - value: now, - }, - ], - }); -}; -``` - -## Live Codesandbox Example - - - -We can get data from other resources in a similar fashion. You can find the [repo here](https://github.com/refinedev/refine/tree/master/examples/blog-hackathonize) - -## 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. diff --git a/documentation/blog/2021-10-4-simple-web-application.md b/documentation/blog/2021-10-4-simple-web-application.md deleted file mode 100644 index fbd0640db989..000000000000 --- a/documentation/blog/2021-10-4-simple-web-application.md +++ /dev/null @@ -1,775 +0,0 @@ ---- -title: Simple Web Application Example with Refine -description: Do you want to develop a web application quickly? You are at the right place! -slug: simple-web-application-with-refine -authors: aydin -tags: [Refine, supabase, react, tutorial] -image: https://refine.ams3.cdn.digitaloceanspaces.com/website/static/img/placeholder.png -hide_table_of_contents: false ---- - -:::caution - -This post was created using version 3.x.x of **Refine**. Although we plan to update it with the latest version of **Refine** as soon as possible, you can still benefit from the post in the meantime. - -You should know that **Refine** version 4.x.x is backward compatible with version 3.x.x, so there is no need to worry. If you want to see the differences between the two versions, check out the [migration guide](https://refine.dev/docs/migration-guide/). - -Just be aware that the source code example in this post have been updated to version 4.x.x. - -::: - -Do you want to develop a web application quickly? You are at the right place! I will develop a simple movie web application with **Refine** on the frontend and **Supabase** on the backend, you should continue reading. I will try to explain it step by step in a very simple way. - - - -## Refine setup - -There are two alternative methods to set up a Refine application. - -The recommended way is using the [superplate](https://github.com/pankod/superplate) tool. superplate's CLI wizard will let you create and customize your application in seconds. - -Alternatively, you may use the create-react-app tool to create an empty React application and then add Refine module via npm. - -I will use superplate-cli and select a Supabase. You can customize other options as you wish. - -cli -
- -## Create admin panel with Refine - -- We should add our Supabase url and key in _supabaseClient.tsx_ -- Add custom login page in _App.tsx_ - -_App.tsx_ - -```tsx -import { Refine } from "@pankod/refine"; -import { dataProvider } from "@refinedev/supabase"; -import authProvider from "./authProvider"; -import { supabaseClient } from "utility"; - -import "@pankod/refine/dist/styles.min.css"; - -import { Login } from "./pages/login"; - -function App() { - return ; -} - -export default App; -``` - -## Login page - -```tsx -import React from "react"; -import { Row, Col, AntdLayout, Card, Typography, Form, Input, Button, Checkbox } from "@pankod/refine"; -import "./styles.css"; - -import { useLogin } from "@pankod/refine"; - -const { Text, Title } = Typography; - -export interface ILoginForm { - username: string; - password: string; - remember: boolean; -} - -export const Login: React.FC = () => { - const [form] = Form.useForm(); - - const { mutate: login } = useLogin(); - - const CardTitle = ( - - Sign in your account - - ); - - return ( - - - -
-
- Refine Logo -
- - - layout="vertical" - form={form} - onFinish={(values) => { - login(values); - }} - requiredMark={false} - initialValues={{ - remember: false, - email: "info+refineflix@refine.dev", - password: "refineflix", - }} - > - - - - - - -
- - - Remember me - - - - - Forgot password? - -
- - -
- - Don’t have an account?{" "} - - Sign up - - -
-
-
- -
-
- ); -}; -``` - -```css -.layout { - background: radial-gradient(50% 50% at 50% 50%, #63386a 0%, #310438 100%); - background-size: "cover"; -} - -.container { - max-width: 408px; - margin: auto; -} - -.title { - text-align: center; - color: #626262; - font-size: 30px; - letter-spacing: -0.04em; -} - -.imageContainer { - display: flex; - align-items: center; - justify-content: center; - margin-bottom: 16px; -} -``` - -You can use default user for login. - -signin -
- -- Create movies list page with add a resource in _App.tsx_ - -```tsx -import { Refine, Resource } from "@pankod/refine"; - -import "@pankod/refine/dist/styles.min.css"; -import { dataProvider } from "@refinedev/supabase"; - -import authProvider from "./authProvider"; -import { supabaseClient } from "utility"; - -import { AdminMovieList } from "./pages/admin/movies"; -import { Login } from "./pages/login"; - -function App() { - return ( - - ); -} - -export default App; -``` - -- AdminMovieList page - -```tsx -import { - List, - Table, - useTable, - IResourceComponentsProps, - Space, - EditButton, - ShowButton, - getDefaultSortOrder, - CreateButton, - DeleteButton, -} from "@pankod/refine"; - -import { IMovies } from "interfaces"; - -export const AdminMovieList: React.FC = () => { - const { tableProps, sorter } = useTable({ - sorters: { - initial: [ - { - field: "id", - order: "asc", - }, - ], - }, - }); - - return ( - }}> - - - - - - title="Actions" - dataIndex="actions" - render={(_, record) => ( - - - - - - )} - /> -
-
- ); -}; -``` - -- Movies interface - -```tsx -export interface IMovies { - id: string; - name: string; - description: string; - preload: string; - director: string; - stars: string; - premiere: string; - trailer: string; - images: IFile[]; -} -``` - -movies -
- -- Now we will add create page - -## Create page - -```tsx - resources={[ - { - name: "movies", - list: AdminMovieList, - create: AdminMovieCreate, - meta: { - route: "admin/movies", - }, - }, - ]} -``` - -```tsx -import { Create, Form, Input, IResourceComponentsProps, Upload, useForm, RcFile } from "@pankod/refine"; -import { IMovies } from "interfaces"; -import { supabaseClient, normalizeFile } from "utility"; - -export const AdminMovieCreate: React.FC = () => { - const { formProps, saveButtonProps } = useForm(); - - return ( - -
- - - - - - - - - - - - - - - - - - - { - try { - const rcFile = file as RcFile; - - await supabaseClient.storage.from("refineflix").upload(`public/${rcFile.name}`, file, { - cacheControl: "3600", - upsert: true, - }); - - const { data } = supabaseClient.storage.from("refineflix").getPublicUrl(`public/${rcFile.name}`); - - const xhr = new XMLHttpRequest(); - onSuccess && onSuccess({ url: data?.publicUrl }, xhr); - } catch (error) { - onError && onError(new Error("Upload Error")); - } - }} - > -

Drag & drop a file in this area

-
-
-
-
-
- ); -}; -``` - -- normalize file in utility folder - -```tsx -import { UploadFile } from "@pankod/refine"; - -interface UploadResponse { - url: string; -} -interface EventArgs { - file: UploadFile; - fileList: Array>; -} - -export const normalizeFile = (event: EventArgs) => { - const { fileList } = event; - - return fileList.map((item) => { - const { uid, name, type, size, response, percent, status } = item; - - return { - uid, - name, - url: item.url || response?.url, - type, - size, - percent, - status, - }; - }); -}; -``` - -create -
- -## Edit page - -```tsx -import React from "react"; -import { Edit, Form, Input, IResourceComponentsProps, RcFile, Upload, useForm } from "@pankod/refine"; - -import { IMovies } from "interfaces"; -import { supabaseClient, normalizeFile } from "utility"; - -export const AdminMovieEdit: React.FC = () => { - const { formProps, saveButtonProps } = useForm(); - - return ( - -
- - - - - - - - - - - - - - - - - - - - - { - try { - const rcFile = file as RcFile; - - await supabaseClient.storage.from("refineflix").upload(`public/${rcFile.name}`, file, { - cacheControl: "3600", - upsert: true, - }); - - const { data } = supabaseClient.storage.from("refineflix").getPublicUrl(`public/${rcFile.name}`); - - const xhr = new XMLHttpRequest(); - onSuccess && onSuccess({ url: data?.publicUrl }, xhr); - } catch (error) { - onError && onError(new Error("Upload Error")); - } - }} - > -

Drag & drop a file in this area

-
-
-
-
-
- ); -}; -``` - -edit -
- -## Show page - -```tsx -import { - useShow, - Show, - Typography, - IResourceComponentsProps, - Space, - ImageField, - RefreshButton, - EditButton, - useNavigation, -} from "@pankod/refine"; - -import { IMovies } from "interfaces"; - -const { Title, Text } = Typography; - -export const AdminMovieShow: React.FC = () => { - const { queryResult } = useShow(); - const { data, isLoading } = queryResult; - const record = data?.data; - - const { push } = useNavigation(); - - return ( - - push(`/admin/movies/edit/${record?.id}`)} /> - - - ), - }} - > - Director - {record?.director || "-"} - - Stars - {record?.stars || "-"} - - Trailer - {record?.trailer && ( - - )} - - Images - - {record?.images ? ( - record.images.map((img) => ) - ) : ( - Not found any images - )} - - - ); -}; -``` - -show -
- -Final version of our ``. - -```tsx - resources={[ - { - name: "movies", - list: AdminMovieList, - create: AdminMovieCreate, - show: AdminMovieShow, - edit: AdminMovieEdit, - meta: { - route: "admin/movies", - }, - }, - ]} -``` - -## Create list page for movies - -We will create custom list and show pages for the unauthorized users because of that, we should add custom routes for these pages. - -_App.tsx_ - -```tsx -import { Refine, Resource } from "@pankod/refine"; - -import "@pankod/refine/dist/styles.min.css"; -import { dataProvider } from "@refinedev/supabase"; - -import authProvider from "./authProvider"; -import { supabaseClient } from "utility"; - -import { AdminMovieList, AdminMovieCreate, AdminMovieShow, AdminMovieEdit } from "./pages/admin/movies"; -import { MoviesList, MovieShow } from "./pages/movies"; -import { Login } from "./pages/login"; - -function App() { - return ( - - ); -} - -export default App; -``` - -### Movies list page - -```tsx -import { IResourceComponentsProps, Card, Space, useList, useNavigation } from "@pankod/refine"; -import { Layout } from "components"; - -import { IMovies } from "interfaces"; - -export const MoviesList: React.FC = () => { - const { Meta } = Card; - - const { data, isLoading } = useList({ - resource: "movies", - queryOptions: { - staleTime: 0, - }, - }); - - const { push } = useNavigation(); - - const renderMovies = () => { - if (data) { - return data.data.map((movie) => { - return ( - 0 ? ( - {movie.images[0].name} - ) : ( - default - ) - } - loading={isLoading} - onClick={() => push(`/movies/show/${movie.id}`)} - > - - - ); - }); - } - }; - - return ( - - {renderMovies()} - - ); -}; -``` - -movies_all -
- -### Movies detail page - -```tsx -import { useShow, Show, Typography, IResourceComponentsProps, Space, ImageField } from "@pankod/refine"; -import { Layout } from "components"; - -import { IMovies } from "interfaces"; - -const { Title, Text } = Typography; - -export const MovieShow: React.FC = () => { - const { queryResult } = useShow(); - const { data, isLoading } = queryResult; - const record = data?.data; - - const renderDetail = () => ( - <> - Director - {record?.director || "-"} - - Stars - {record?.stars || "-"} - Trailer - {record?.trailer && ( - - )} - Images - - {record?.images ? ( - record.images.map((img) => ) - ) : ( - Not found any images - )} - - - ); - - return ( - - - {renderDetail()} - - - ); -}; -``` - -detailed -
- -## Example - - - -[here is repo](https://github.com/refinedev/refine/tree/master/examples/blog-refineflix) diff --git a/documentation/blog/2021-12-13-web3-refine.md b/documentation/blog/2021-12-13-web3-refine.md deleted file mode 100644 index 68ca473c3e96..000000000000 --- a/documentation/blog/2021-12-13-web3-refine.md +++ /dev/null @@ -1,67 +0,0 @@ ---- -title: Web3 with Refine -description: Sign-in Ethereum with Web3 and Refine -slug: web3-with-refine -authors: melih -tags: [Refine, web3, tutorial] -image: https://refine.ams3.cdn.digitaloceanspaces.com/website/static/img/placeholder.png -hide_table_of_contents: false ---- - -In this article, we will talk about what is web3 and a simple ethereum wallet login application with **Refine**. - - - -## What is Web3? - -Web 3.0 eliminates intermediates. There’s no centralized database that stores the application state. - -In web3, developers don't usually build and deploy applications that run on a single server or that store their data in a single database. -Instead of, Web3 applications run on blockchains, decentralized networks of many peer to peer nodes - -Features provided by Web3: - -- Verifiable -- Self-governing -- Permissionless -- Stateful -- Trustless -- Native built-in payments -- Anonymity - -## What is dApps(Dapps)? - -Dapps is short for "Decentralized Applications" and refers to any application that is decentralized in nature, built on a blockchain, and may use tokens for transactions. - -Dapps is just like any other software application you use. It could be a website or an app on your phone. What makes a Dapp different than a traditional app is that it's built on a decentralized network, like Ethereum. - -Many applications on the logic of dApp have been developed and continue to be developed. - -[Here you can browse some dapps](https://ethereum.org/en/dapps/) - -We have developed a simple app where you can login with ethereum and send ethereum over the network using Metamask Wallet and **Refine**. - -This application allows you to login with your web3 wallet and you can also send ethereum over the ethereum network. - -This example is simple intro to dApps development built with web3 and **Refine**. - -login -
- -overview -
- -You can develop many fast and functional dApps using web3 and **Refine**. - -[View Source](https://github.com/refinedev/refine/tree/master/examples/with-web3) - -[View Guide](https://refine.dev/docs/guides-and-concepts/web3/ethereum-signin/) - -## Live Codesandbox Example - - diff --git a/documentation/blog/2022-02-12-implement-darkmode.md b/documentation/blog/2022-02-12-implement-darkmode.md deleted file mode 100644 index 1757bc5702cc..000000000000 --- a/documentation/blog/2022-02-12-implement-darkmode.md +++ /dev/null @@ -1,307 +0,0 @@ ---- -title: Implementing Dark Mode In Ant Design Using gulp -description: In this article, we’ll learn how to efficiently implement dark mode in a refine/Ant Design app, using gulp library and leveraging some React features like hooks -slug: how-to-add-darkmode-in-ant-design -authors: vmalep -tags: [Refine, react, css, ant-design] -image: https://refine.ams3.cdn.digitaloceanspaces.com/website/static/img/placeholder.png -hide_table_of_contents: false ---- - -:::caution - -This post was created using version 3.x.x of **Refine**. Although we plan to update it with the latest version of **Refine** as soon as possible, you can still benefit from the post in the meantime. - -You should know that **Refine** version 4.x.x is backward compatible with version 3.x.x, so there is no need to worry. If you want to see the differences between the two versions, check out the [migration guide](https://refine.dev/docs/migration-guide/). - -::: - -In this article, we will provide an example on how to implement darkmode with **Refine**. In order to switch between light and dark mode, we need 2 different styles and the possibility to switch between one and the other without restarting the application. Since the Less stylesheets with React doesn't allow variables to be modified without compilation and therefore a restart of the application. To solve this, we are going to use **gulp** that will compile the Less files into swappable CSS, directly accessible to the running application. - - - -The solution was presented in this [blog](https://jfelix.info/blog/dynamic-themes-in-ant-design-how-to-change-between-light-and-dark-theme) and lightly adapted to **Refine**. - -## Initial setup - -For this article, we started from a basic Refine app with Ant Design: - -```tsx -npm create refine-app@latest tutorial -- -p refine-react -b v3 -``` - -Select the following options to complete the CLI wizard: - -```tsx -Cloned remote source successfully. -✔ What will be the name of your app · tutorial -✔ Package manager: · Npm -✔ Do you want to use a UI Framework?: · Ant Design -✔ Do you want a customized theme?: · Yes (Custom Variables) -✔ Router Provider: · React Router v6 -✔ Data Provider: · REST API -✔ Auth Provider: · None -✔ Do you want to add example pages? · Yes (Recommended) -✔ Do you want a customized layout? · Yes -✔ i18n - Internationalization: · No -``` - -From there, install the following packages: - -```tsx -npm install -s gulp gulp-less gulp-postcss gulp-debug gulp-csso autoprefixer less-plugin-npm-import -npm install -s react-redux react-css-theme-switcher -``` - -## Create the Less and then CSS files - -### Copy the `antd.less` file - -Make a copy of the `src/styles/antd.less` file into `antd.light-theme.less` and add the following lines inside (because this setting will be removed from the Header/index.tsx file later on): - -```tsx -// Header -@layout-header-background:#fff; -``` - -### Create a Less file for the dark mode - -Create the following file `src/styles/antd.dark-theme.less` with this content: - -```tsx title="src/styles/antd.dark-theme.less" -// Run 'npx gulp less' after modifying this file - -@import '~antd/lib/style/color/colorPalette.less'; -@import '~antd/dist/antd.less'; -@import '~antd/lib/style/themes/dark.less'; - -@primary-color: rgba(255, 255, 255, 0.75); -@border-radius-base: 4px; -@icon-color: rgba(255, 255, 255, 0.75); - -@component-background: #303030; -@body-background: #303030; -@popover-background: #303030; -@border-color-base: #6f6c6c; -@border-color-split: #424242; -@table-header-sort-active-bg: #424242; -@card-skeleton-bg: #424242; -@skeleton-color: #424242; -@table-header-sort-active-bg: #424242; -@layout-header-background:#424242; -``` - -### Compile the CSS files with `gulp` - -Create the following `gulpfile.js` in the root of the repo: - -```tsx title="gulpfile.js" -const gulp = require("gulp"); -const gulpless = require("gulp-less"); -const postcss = require("gulp-postcss"); -const debug = require("gulp-debug"); -var csso = require("gulp-csso"); -const autoprefixer = require("autoprefixer"); -const NpmImportPlugin = require("less-plugin-npm-import"); - -gulp.task("less", function () { - const plugins = [autoprefixer()]; - - return gulp - .src("src/styles/*-theme.less") - .pipe(debug({ title: "Less files:" })) - .pipe( - gulpless({ - javascriptEnabled: true, - plugins: [new NpmImportPlugin({ prefix: "~" })], - }), - ) - .pipe(postcss(plugins)) - .pipe( - csso({ - debug: true, - }), - ) - .pipe(gulp.dest("./public")); -}); - -exports.sync = gulp.series("less"); -``` - -And run `npx gulp less` - -```tsx -▶npx gulp less -[22:36:28] Using gulpfile ./gulpfile.js -[22:36:28] Starting 'less'... -[22:36:28] Less files: src/styles/antd.dark-theme.less -[22:36:28] Less files: src/styles/antd.light-theme.less -[22:36:28] Less files: 2 items -## parsing done in 165 ms - -Compress block #1 -[0.028s] init -[0.038s] clean -[0.068s] replace -[0.076s] prepare -[0.011s] mergeAtrule -[0.052s] initialMergeRuleset -[0.011s] disjoinRuleset -[0.068s] restructShorthand -[0.076s] restructBlock -[0.015s] mergeRuleset -[0.075s] restructRuleset -## compress done in 522 ms - -## generate done in 44 ms - -## parsing done in 114 ms - -Compress block #1 -[0.007s] init -[0.020s] clean -[0.057s] replace -[0.067s] prepare -[0.006s] mergeAtrule -[0.068s] initialMergeRuleset -[0.012s] disjoinRuleset -[0.045s] restructShorthand -[0.033s] restructBlock -[0.010s] mergeRuleset -[0.061s] restructRuleset -## compress done in 389 ms - -## generate done in 15 ms - -[22:36:33] Finished 'less' after 5 s -``` - -:::info - -this command must be repeated each time the Less files are modified and the application restarted to see the changes) - -::: - -You should now have 2 CSS files inside the public folder: `antd.dark-theme.css`and `antd.light-theme.css` -signin - -## Adapt the Refine application to be able to switch between the 2 styles - -### App.tsx file - -// highlight-start -// highlight-end -In App.tsx, adapt the file so it looks like this : - -```tsx -import { Refine } from "@refinedev/core"; -import { useNotificationProvider } from "@refinedev/antd"; -import routerProvider from "@refinedev/react-router-v6"; -import "styles/antd.less"; -import dataProvider from "@refinedev/simple-rest"; -import { PostList, PostCreate, PostEdit, PostShow } from "pages/posts"; -import { Title, Header, Sider, Footer, Layout, OffLayoutArea } from "components/layout"; -// highlight-start -import { ThemeSwitcherProvider } from "react-css-theme-switcher"; -// highlight-end - -function App() { - // highlight-start - const currThemes = { - dark: `${process.env.PUBLIC_URL}/antd.dark-theme.css`, - light: `${process.env.PUBLIC_URL}/antd.light-theme.css`, - }; - // highlight-end - - return ( - // highlight-start - - // highlight-end - - // highlight-start - - // highlight-end - ); -} - -export default App; -``` - -### Header - -Add a theme switcher in the Header (`src/components/layout/header/index.tsx`) with the added lines so it looks like this (the Header has been simplified for the sake of clarity and the switch can be installed somewhere else in the application obviously): - -```tsx -import { useState } from "react"; -// highlight-start -import { useThemeSwitcher } from "react-css-theme-switcher"; -// highlight-end -import { - AntdLayout, - // highlight-start - Switch, - // highlight-end -} from "@refinedev/antd"; - -export const Header: React.FC = () => { - // highlight-start - const [isDarkMode, setIsDarkMode] = useState(); - const { switcher, themes } = useThemeSwitcher(); - - function toggleTheme(isChecked: boolean) { - // added - setIsDarkMode(isChecked); - switcher({ theme: isChecked ? themes.dark : themes.light }); - } - // highlight-end - - return ( - - // highlight-start -
- {" "} - // added - -
- // highlight-end -
- ); -}; -``` - -You should now have a light/dark mode switcher in the header: -signin -
- -signin -
diff --git a/documentation/blog/2022-02-14-refine-ecommerce-blog.md b/documentation/blog/2022-02-14-refine-ecommerce-blog.md deleted file mode 100644 index 57ee65a0eac5..000000000000 --- a/documentation/blog/2022-02-14-refine-ecommerce-blog.md +++ /dev/null @@ -1,708 +0,0 @@ ---- -title: Next.js E-commerce App with Strapi and Chakra UI -description: Learn the power of Refine for e-commerce with this quick & easy example. This step-by-step Refine SPA tutorial will get you started in no time. -slug: handcrafted-nextjs-e-commerce-app-tutorial-strapi-chakra-ui -authors: melih -tags: [Refine, strapi, chakra-ui, nextjs] -image: https://refine.ams3.cdn.digitaloceanspaces.com/website/static/img/placeholder.png -hide_table_of_contents: false ---- - -:::caution - -This post was created using version 3.x.x of **Refine**. Although we plan to update it with the latest version of **Refine** as soon as possible, you can still benefit from the post in the meantime. - -You should know that **Refine** version 4.x.x is backward compatible with version 3.x.x, so there is no need to worry. If you want to see the differences between the two versions, check out the [migration guide](https://refine.dev/docs/migration-guide/). - -Just be aware that the source code example in this post have been updated to version 4.x.x. - -::: - -basket -
- -In this article, we will create the e-commerce client of our [Strapi-Multitenancy](/docs/guides-concepts/multi-tenancy/#strapi) admin panel that we have done before. - -It is now used **headless** with the **Refine** 3 version. You can use any UI library you want with the **headless** feature. - -We will use [Strapi](https://strapi.io/) and [Chakra-UI](https://chakra-ui.com/) together with [**Next.js**](/docs/packages/list-of-packages) in our E-commerce client example application. - - - -## Refine Project Setup - -Let's start by creating our **Refine** project. You can use the [superplate](https://github.com/pankod/superplate) to create a Refine project. - -```bash -npm create refine-app@latest refine-ecommerce-example -- -p refine-nextjs -b v3 -``` - -```bash -✔ What will be the name of your app · refine-ecommerce-example -✔ Package manager: · npm -✔ Do you want to using UI Framework? > No(headless) -✔ Data Provider: Strapi -✔ i18n - Internationalization: · no -``` - -superplate will quickly create our **Refine** project according to the features we choose. Let's continue by install the [**Refine** Strapi-v4 Data Provider](/docs/packages/list-of-packages) and Chakra-UI packages that we will use later. - -## Installation - -```bash -cd refine-ecommerce-example - -npm i @refinedev/strapi-v4 @chakra-ui/react @emotion/react@^11 @emotion/styled@^11 framer-motion@^6 -``` - -Our **Refine** project and installations are now ready! Let's start using it. - -## Usage - -### Configure Refine for Strapi-v4 - -```tsx title="pages/_app.tsx" -import React from "react"; -import { AppProps } from "next/app"; -import Head from "next/head"; -import { Refine } from "@refinedev/core"; -import routerProvider from "@refinedev/nextjs-router"; -//highlight-next-line -import { DataProvider } from "@refinedev/strapi-v4"; - -const API_URL = "https://api.strapi-multi-tenant.refine.dev/api"; - -function MyApp({ Component, pageProps }: AppProps): JSX.Element { - //highlight-next-line - const dataProvider = DataProvider(API_URL); - - return ( - - - - ); -} -``` - -### Chakra-UI Provider Setup - -```tsx title="pages/_app.tsx" -import React from "react"; -import { AppProps } from "next/app"; -import Head from "next/head"; -import { Refine } from "@refinedev/core"; -import routerProvider from "@refinedev/nextjs-router"; -import { DataProvider } from "@refinedev/strapi-v4"; - -//highlight-next-line -import { ChakraProvider } from "@chakra-ui/react"; - -const API_URL = "https://api.strapi-multi-tenant.refine.dev/api"; - -function MyApp({ Component, pageProps }: AppProps): JSX.Element { - const dataProvider = DataProvider(API_URL); - - return ( - - //highlight-start - - - - //highlight-end - - ); -} -``` - -## Create Strapi Collections - -We created three collections on Strapi as `store`, `product` and `order` and added a relation between them. For detailed information on how to create a collection, you can check [here](https://docs.strapi.io/developer-docs/latest/getting-started/quick-start.html). - -We created our collections in the previous Strapi Multitenancy guide. Now we will use the same collections. - -[Refer to the Project Collections for detailed information. →](https://refine.dev/docs/guides-and-concepts/multi-tenancy/strapi-v4/#create-collections) - -## Create Refine Layout - -**Refine** **headless** is not affiliated with any UI. It is entirely up to you to customize your UI. Let's create a simple layout for this example. - -The Layout we've created now will only show the **Refine** logo. In the following steps, we will edit our Layout. - -```tsx title="components/Layout.tsx" -import { LayoutProps } from "@refinedev/core"; -import { Box, Container, Flex, Image } from "@chakra-ui/react"; - -export const Layout: React.FC = ({ children }) => { - return ( - - - - - Refine Logo - - - {children} - - - ); -}; -``` - -```tsx title="pages/_app.tsx" -import React from "react"; -import { AppProps } from "next/app"; -import Head from "next/head"; -import { Refine } from "@refinedev/core"; -import routerProvider from "@refinedev/nextjs-router"; -import { DataProvider } from "@refinedev/strapi-v4"; - -import { ChakraProvider } from "@chakra-ui/react"; -//highlight-next-line -import { Layout } from "src/components"; - -const API_URL = "https://api.strapi-multi-tenant.refine.dev/api"; - -function MyApp({ Component, pageProps }: AppProps): JSX.Element { - const dataProvider = DataProvider(API_URL); - - return ( - - - - - - ); -} -``` - -layout -
- -## Product Card Design with Chakra-UI - -Let's design our product cards with Chakra-UI. - -```tsx title="src/components/ProductCard.tsx" -import React from "react"; -//highlight-next-line -import { Box, Image, Badge, Button } from "@chakra-ui/react"; - -export type ProductProps = { - id: string; - title: string; - description: string; - cardImage: string; -}; - -export const ProductCard: React.FC = ({ id, title, description, cardImage }) => { - return ( - - - - - - New Product - - - - - {title} - - - {} - - - - ); -}; -``` - -sample_product -
- -We created our Product Card component. Now let's move on to the process of fetch and showing our products from the Strapi. - -## Fetch Products with SSR - -First, let's fetch our products with the nextjs `getServerSideProps` function. - -### `GetServerSideProps` - -```tsx title="pages/index.tsx" -//highlight-next-line -import { GetServerSideProps } from "next"; -import { DataProvider } from "@refinedev/strapi-v4"; - -import { IProduct } from "interfaces"; - -const API_URL = "https://api.strapi-multi-tenant.refine.dev/api"; - -//highlight-start -export const getServerSideProps: GetServerSideProps = async (context) => { - const data = await DataProvider(API_URL).getList({ - resource: "products", - meta: { populate: ["image"] }, - }); - - return { - props: { products: data }, - }; -}; -//highlight-end -``` - -### Create Product List with Refine - -Let's process the data we fetch above using **Refine**'s `useTable` hook. Then let's put our data in our ProductCard component. - -```tsx title="pages/index.tsx" -import { GetServerSideProps } from "next"; -//highlight-next-line -import { LayoutWrapper, GetListResponse, useTable } from "@refinedev/core"; -import { DataProvider } from "@refinedev/strapi-v4"; - -import { IProduct } from "interfaces"; -import { SimpleGrid } from "@chakra-ui/react"; -import { ProductCard } from "src/components"; - -const API_URL = "https://api.strapi-multi-tenant.refine.dev/api"; - -//highlight-start -type ItemProps = { - products: GetListResponse; -}; -//highlight-end - -export const ProductList: React.FC = ({ products }) => { - //highlight-start - const { tableQueryResult } = useTable({ - resource: "products", - queryOptions: { - initialData: products, - }, - meta: { populate: ["image"] }, - }); - //highlight-end - - return ( - //highlight-start - - - {tableQueryResult.data?.data.map((item) => ( - - ))} - - - //highlight-end - ); -}; - -export default ProductList; - -export const getServerSideProps: GetServerSideProps = async (context) => { - const data = await DataProvider(API_URL).getList({ - resource: "products", - meta: { populate: ["image"] }, - }); - - return { - props: { products: data }, - }; -}; -``` - -products -
- -## Adding Store-based Filtering - -We have fetch all the products above. Now, let's fetch the stores and list the store-specific products separately. - -First, let's fetch our stores by using the **Refine** `useMany` hook within the `getServerSideProps` function. Next we will create buttons for the stores. When these buttons are clicked, a store is selected, we will do a filtering with `useTable` `setFilters` and list the products specific to that store. - -```tsx title="pages/index.tsx" -export const getServerSideProps: GetServerSideProps = async (context) => { - const data = await DataProvider(API_URL).getList({ - resource: "products", - meta: { populate: ["image"] }, - pagination: { current: 1, pageSize: 9 }, - }); - - //highlight-start - const { data: storesData } = await DataProvider(API_URL).getMany({ - resource: "stores", - ids: ["1", "2", "3"], - }); - //highlight-end - - return { - props: { - products: data, - //highlight-next-line - stores: storesData, - }, - }; -}; -``` - -```tsx title="pages/index.tsx" -import { GetServerSideProps } from "next"; -import { LayoutWrapper, GetListResponse, useTable } from "@refinedev/core"; -import { DataProvider } from "@refinedev/strapi-v4"; - -import { IProduct, IStore } from "interfaces"; -import { Button, SimpleGrid, Flex, Text } from "@chakra-ui/react"; -import { ProductCard, FilterButton } from "src/components"; - -const API_URL = "https://api.strapi-multi-tenant.refine.dev/api"; - -type ItemProps = { - products: GetListResponse; - //highlight-next-line - stores: IStore[]; -}; - -export const ProductList: React.FC = ({ products, stores }) => { - const { tableQueryResult, setFilters } = useTable({ - resource: "products", - queryOptions: { - initialData: products, - }, - meta: { populate: ["image"] }, - }); - - return ( - - //highlight-start - - - setFilters([ - { - field: "stores][id]", - operator: "eq", - value: undefined, - }, - ]) - } - > - All Products - - {stores?.map((item) => { - return ( - - setFilters([ - { - field: "stores][id]", - operator: "eq", - value: item.id, - }, - ]) - } - > - - {item.title} - - - ); - })} - - //highlight-end - - {tableQueryResult.data?.data.map((item) => ( - - ))} - - - ); -}; - -export default ProductList; - -export const getServerSideProps: GetServerSideProps = async (context) => { - const data = await DataProvider(API_URL).getList({ - resource: "products", - meta: { populate: ["image"] }, - pagination: { current: 1, pageSize: 9 }, - }); - - const { data: storesData } = await DataProvider(API_URL).getMany({ - resource: "stores", - ids: ["1", "2", "3"], - }); - - return { - props: { - products: data, - stores: storesData, - }, - }; -}; -``` - -pagination -
- -## Adding Pagination - -We list all products on our `All Products` page. Let's add pagination to this page and divide the products into pages. We will perform pagination using the `pageSize`, `current` and setCurrent properties from the useTable hook. - -[Refer to the useTable documentation for detailed information. →](https://refine.dev/docs/core/hooks/useTable/#pagination) - -```tsx title="pages/index.tsx" -import { GetServerSideProps } from "next"; -import { LayoutWrapper, GetListResponse, useTable } from "@refinedev/core"; -import { DataProvider } from "@refinedev/strapi-v4"; - -import { IProduct, IStore } from "interfaces"; -import { Button, SimpleGrid, Flex, Text } from "@chakra-ui/react"; -import { ProductCard, FilterButton } from "src/components"; - -const API_URL = "https://api.strapi-multi-tenant.refine.dev/api"; - -type ItemProps = { - products: GetListResponse; - stores: IStore[]; -}; - -export const ProductList: React.FC = ({ products, stores }) => { - //highlight-start - const { tableQueryResult, setFilters, current, setCurrent, pageSize } = useTable({ - resource: "products", - queryOptions: { - initialData: products, - }, - initialPageSize: 9, - meta: { populate: ["image"] }, - }); - //highlight-end - - //highlight-next-line - const totalPageCount = Math.ceil(tableQueryResult.data?.total!! / pageSize); - - return ( - - - - setFilters([ - { - field: "stores][id]", - operator: "eq", - value: undefined, - }, - ]) - } - > - All Products - - {stores?.map((item) => { - return ( - - setFilters([ - { - field: "stores][id]", - operator: "eq", - value: item.id, - }, - ]) - } - > - - {item.title} - - - ); - })} - - - {tableQueryResult.data?.data.map((item) => ( - - ))} - - //highlight-start - - {Array.from(Array(totalPageCount), (e, i) => { - if (current > totalPageCount) { - setCurrent(i); - } - return ( - - ); - })} - - //highlight-end - - ); -}; - -export default ProductList; - -export const getServerSideProps: GetServerSideProps = async (context) => { - const data = await DataProvider(API_URL).getList({ - resource: "products", - meta: { populate: ["image"] }, - pagination: { current: 1, pageSize: 9 }, - }); - - const { data: storesData } = await DataProvider(API_URL).getMany({ - resource: "stores", - ids: ["1", "2", "3"], - }); - - return { - props: { products: data, stores: storesData }, - }; -}; -``` - -page_size -
- -## Adding Basket and Payment features with Snipcart - -One of the steps that should be in an E-commerce application is the cart and payment transactions. In our example, we will use [Snipcart](https://snipcart.com/) for this process. - -[Refer to the Snipcart documentation for detailed information. →](https://docs.snipcart.com/v3/) - -### Installation Snipcart Widget - -```tsx title="pages/_app.tsx" -function MyApp({ Component, pageProps }: AppProps): JSX.Element { - const dataProvider = DataProvider(API_URL); - - return ( - <> - //highlight-start - - - -