Refine과 Strapi로 15분 안에 피드백 관리자 패널 만들기

이 문서에서는 웹 애플리케이션에서 받은 피드백을 관리할 수 있는 패널을 만듭니다.

Strapi.io으로 API를 신속하게 생성한 다음 refine으로 프런트엔드를 개발합니다. 따라서 Strapi와 Refine의 완벽한 조화로 매우 짧은 시간에 관리자 패널을 만들 수 있는 방법을 살펴보겠습니다.

패널이 갖게 될 기능:
  • strapi.io로 인증
  • 피드백을 나열하는 페이지
  • 피드백에 대한 돌연변이

  • Strapi로 API 만들기



    Strapi의 백엔드 프로젝트quick start guide를 생성해 보겠습니다.

    npx create-strapi-app strapi-feedback-api --quickstart
    


    설치가 완료되면 브라우저에서 탭이 자동으로 열립니다. 여기서는 Content-Types Builder를 사용하여 feedback 컬렉션을 생성해 보겠습니다.

    간단히 말해서, 피드백에는 description 텍스트 필드, 피드백이 전송된 페이지를 표시하는 A page 텍스트 필드 및 피드백 유형(이슈, 아이디어, 기타, 아카이브)을 나타내는 type 열거형 필드가 있어야 합니다. ).



    구체화로 패널 만들기



    구체화setting up guide를 사용하여 프런트엔드 프로젝트를 생성해 보겠습니다.

    구체화 응용 프로그램을 설정하는 두 가지 대체 방법이 있습니다. superplate 으로 애플리케이션을 빠르게 생성합니다.

    npx superplate-cli refine-feedback-client
    


    CLI 마법사를 완료하려면 다음 옵션을 선택하십시오.

    ? Select your project type:
    ❯ refine
    
    ? What will be the name of your app:
    refine-strapi-web
    
    ? Package manager:
    ❯ Npm
    
    ? Do you want to customize the theme?:
    ❯ No (Ant Design default theme)
    
    ? Data Provider :
    ❯ Strapi
    
    ? Do you want to customize layout?
    ❯ Yes, I want
    
    ? i18n - Internationalization:
    ❯ No
    


    설치가 완료되면 Strapi 특정data provider, 인증 공급자 및 사용자 지정 레이아웃 옵션을 사용하여 Refine의 기본 보기를 변경할 수 있는 레이아웃 구성 요소가 프로젝트에 포함됩니다.

    이제 다음 명령을 사용하여 앱을 부트스트랩합니다.

    npm run dev
    




    이제 변경 사항을 나열해 보겠습니다.
  • Strapi API URL 변경
  • 미세 조정 모양을 변경할 때 사용하지 않을 구성 요소를 제거합니다
  • .
  • Strapi에서 생성한 컬렉션 이름에 따라 리소스 추가

  • + import { Refine } from "@pankod/refine";
    import "@pankod/refine/dist/styles.min.css";
    import { DataProvider } from "@pankod/refine-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 (
        <Refine
          dataProvider={dataProvider}
          authProvider={authProvider}
    -     Title={Title}
          Header={Header}
    -     Sider={Sider}
    -     Footer={Footer}
          Layout={Layout}
          OffLayoutArea={OffLayoutArea}
          routerProvider={routerProvider}
          resources={[
            {
              name: "feedbacks",
            },
          ]}
        />
      );
    }
    
    export default App;
    


    리소스를 추가한 후 인증 공급자가 활성화되었습니다.



    이제 애플리케이션에 로그인할 수 있도록 Strapi에서 사용자를 생성해 보겠습니다.



    사용자를 생성하고 이 사용자로 애플리케이션에 로그인했습니다.



    레이아웃 구성 요소를 사용자 지정하고 사이더를 제거하고 헤더를 추가해 보겠습니다.

    import React from "react";
    import { Layout as AntLayout } from "antd";
    
    import { LayoutProps } from "@pankod/refine";
    
    export const Layout: React.FC<LayoutProps> = ({
      children,
      Header,
      OffLayoutArea,
    }) => {
      return (
        <AntLayout style={{ minHeight: "100vh", flexDirection: "row" }}>
          <AntLayout>
            <Header />
            <AntLayout.Content>
              {children}
              <OffLayoutArea />
            </AntLayout.Content>
          </AntLayout>
        </AntLayout>
      );
    };
    


    헤더 구성요소도 맞춤설정해 보겠습니다.

    import React from "react";
    import { Layout } from "antd";
    
    export const Header: React.FC = () => {
      return (
        <Layout.Header
          style={{
            display: "flex",
            justifyContent: "center",
            alignItems: "center",
            height: "64px",
            backgroundColor: "#FFF",
            borderBottom: "1px solid #f0f0f0",
          }}
        >
          <img src="./refeedback.png" alt="refeedback" style={{ width: "250px" }} />
        </Layout.Header>
      );
    };
    


    새 보기에는 더 이상 사이드가 없으며 사용자 정의한 헤더가 여기에 있습니다.



    이제 피드백을 나열하고 변경할 수 있는 부분에 도달했습니다. 그 전에 Strapi에서 더미 피드백 레코드를 생성해 보겠습니다.


    FeedbackList.tsx 폴더 아래에 pages 파일을 만듭니다. 그런 다음 구체화와 함께 제공되는 구성 요소 및 후크를 사용하여 다음과 같이 구성 요소를 생성해 보겠습니다.

    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<
        IFeedback,
        HttpError,
        IFeedbackFilterVariables
      >({
        initialSorter: [{ 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 (
          <AntdList.Item>
            <Card hoverable>
              <AntdList.Item.Meta
                description={
                  <div style={{ display: "flex", justifyContent: "space-between" }}>
                    <Tag
                      color={addTagColor(type)}
                      style={{ textTransform: "capitalize" }}
                    >
                      {type}
                    </Tag>
                    <DateField format="LLL" value={created_at} />
                  </div>
                }
              />
              <Paragraph strong>{description}</Paragraph>
              <Descriptions labelStyle={{ color: "grey", fontWeight: 600 }}>
                <Descriptions.Item label="Path">{page}</Descriptions.Item>
              </Descriptions>
              <div style={{ display: "flex", justifyContent: "end", gap: "4px" }}>
                <Button
                  size="small"
                  loading={isLoading}
                  onClick={() =>
                    mutate({
                      id,
                      resource: "feedbacks",
                      values: {
                        type: "archive",
                      },
                    })
                  }
                >
                  Archive
                </Button>
              </div>
            </Card>
          </AntdList.Item>
        );
      };
    
      return (
        <List title="" pageHeaderProps={{ style: { height: "100%" } }}>
          <Row gutter={[64, 0]} justify="center">
            <Col xs={24} sm={24} md={4} lg={4} xl={4}>
              <Form
                {...searchFormProps}
                layout="vertical"
                onValuesChange={() => searchFormProps.form?.submit()}
                initialValues={{
                  type: "",
                }}
              >
                <Form.Item label="FILTERS" name="type">
                  <Radio.Group>
                    <Space direction="vertical">
                      <Radio.Button value="">All</Radio.Button>
                      <Radio.Button value="issue">Issue</Radio.Button>
                      <Radio.Button value="idea">Idea</Radio.Button>
                      <Radio.Button value="other">Other</Radio.Button>
                      <Radio.Button value="archive">Archive</Radio.Button>
                    </Space>
                  </Radio.Group>
                </Form.Item>
              </Form>
            </Col>
            <Col xs={24} sm={24} md={14} lg={14} xl={14}>
              <AntdList
                {...listProps}
                split={false}
                renderItem={renderItem}
                itemLayout="vertical"
              />
            </Col>
          </Row>
        </List>
      );
    };
    



    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;
    }
    


    이 구성 요소에서
  • useSimpleList Ant Design <List> 구성 요소를 사용하여 레코드를 나열했습니다.
  • Antd <Form> 구성 요소를 사용하여 레코드를 필터링했습니다.
  • type 으로 기록의 useUpdate를 변경할 수 있도록 했습니다.

  • 새 필터 추가, 검색 항목 추가, 동적 정렬 작업 등에 대한 useSimpleList의 자세한 사용법을 참조하십시오here.



    응용 프로그램을 조금 더 확장하기 위해 피드백을 받을 수 있는 피드백 위젯을 개발해 봅시다. 이 애플리케이션의 경우 이 구성 요소를 구체화하여 개발하지만 원하는 방식으로 Strapi API를 사용하여 이 구성 요소를 만들 수 있습니다.

    제가 개발한 컴포넌트here의 코드를 보시면 됩니다.

    이제 이 구성 요소를 OfflayouArea 구성 요소에 추가하고 페이지에서 피드백을 생성하고 피드백 목록에 어떻게 반영되는지 살펴보겠습니다.



    여기에서 프로젝트의 소스 코드를 찾을 수 있습니다: https://github.com/pankod/refine/tree/master/examples/blog/refeedback

    좋은 웹페이지 즐겨찾기