diff --git a/.github/workflows/example-previews-pr.yml b/.github/workflows/example-previews-pr.yml index 90c07b17cdc1..828c147e6c0a 100644 --- a/.github/workflows/example-previews-pr.yml +++ b/.github/workflows/example-previews-pr.yml @@ -6,7 +6,6 @@ on: - "examples/finefoods-antd/**" - "examples/finefoods-client/**" - "examples/finefoods-material-ui/**" - - "examples/app-crm/**" - "examples/pixels/**" - "examples/invoicer/**" types: @@ -24,25 +23,24 @@ jobs: examples: ${{ steps.filter.outputs.changes }} all_examples: ${{ steps.deploy-previews-label.outputs.all_examples }} steps: - - uses: actions/checkout@v4 - - name: Get PR labels - id: pr-labels - uses: joerick/pr-labels-action@v1.0.9 - - name: 'Check deploy previews label' - if: ${{ contains(steps.pr-labels.outputs.labels, ' deploy-previews ') }} - id: deploy-previews-label - run: echo 'all_examples=["finefoods-antd", "finefoods-client", "finefoods-material-ui", "app-crm", "pixels", "invoicer"]' >> $GITHUB_OUTPUT - - uses: dorny/paths-filter@v3 - if: ${{ !contains(steps.pr-labels.outputs.labels, ' deploy-previews ') }} - id: filter - with: - filters: | - 'finefoods-antd': 'examples/finefoods-antd/**' - 'finefoods-client': 'examples/finefoods-client/**' - 'finefoods-material-ui': 'examples/finefoods-material-ui/**' - 'app-crm': 'examples/app-crm/**' - 'pixels': 'examples/pixels/**' - 'invoicer': 'examples/invoicer/**' + - uses: actions/checkout@v4 + - name: Get PR labels + id: pr-labels + uses: joerick/pr-labels-action@v1.0.9 + - name: "Check deploy previews label" + if: ${{ contains(steps.pr-labels.outputs.labels, ' deploy-previews ') }} + id: deploy-previews-label + run: echo 'all_examples=["finefoods-antd", "finefoods-client", "finefoods-material-ui", "app-crm", "pixels", "invoicer"]' >> $GITHUB_OUTPUT + - uses: dorny/paths-filter@v3 + if: ${{ !contains(steps.pr-labels.outputs.labels, ' deploy-previews ') }} + id: filter + with: + filters: | + 'finefoods-antd': 'examples/finefoods-antd/**' + 'finefoods-client': 'examples/finefoods-client/**' + 'finefoods-material-ui': 'examples/finefoods-material-ui/**' + 'pixels': 'examples/pixels/**' + 'invoicer': 'examples/invoicer/**' deploy_previews: runs-on: ubuntu-latest diff --git a/documentation/blog/2023-03-22-react-admin-templates.md b/documentation/blog/2023-03-22-react-admin-templates.md index 228a14cf9d1f..47b030965828 100644 --- a/documentation/blog/2023-03-22-react-admin-templates.md +++ b/documentation/blog/2023-03-22-react-admin-templates.md @@ -57,7 +57,7 @@ Overall, the Refine CRM admin template is an excellent choice for businesses tha **Live example:** https://example.crm.refine.dev/ -**Source code**: https://github.com/refinedev/refine/tree/master/examples/app-crm +**Template**: https://refine.dev/templates/crm-application/ ## 2. Elstar diff --git a/documentation/blog/2023-10-02-refine-crm-overview.md b/documentation/blog/2023-10-02-refine-crm-overview.md index 94e6f94edb5a..e85ccd57d57c 100644 --- a/documentation/blog/2023-10-02-refine-crm-overview.md +++ b/documentation/blog/2023-10-02-refine-crm-overview.md @@ -14,7 +14,7 @@ I want to introduce our newest example app – a full-fledged React CRM (Custome 👉 [Live Demo](https://example.crm.refine.dev/) -👉 [You can find the source code on GitHub here](https://github.com/refinedev/refine/tree/master/examples/app-crm) +👉 [Template](https://refine.dev/templates/crm-application/) This example is open-source, which means anyone can freely utilize and customize the source code as they see fit. It's not just another application; it's a comprehensive solution that boasts all the features and functionalities required for an accurate enterprise-level application. @@ -33,10 +33,24 @@ We'll explore the key features of our CRM app, the technologies we used, and how Step we'll cover: +- [Introduction](#introduction) - [Key Features of the CRM App](#key-features-of-the-crm-app) + - [Dashboard](#dashboard) + - [Calendar Integration](#calendar-integration) + - [Scrumboard-Project Kanban](#scrumboard-project-kanban) + - [Sales Pipeline](#sales-pipeline) + - [Companies](#companies) + - [Contacts](#contacts) + - [Quotes](#quotes) + - [Administration](#administration) + - [Authentication \& Authorization](#authentication--authorization) - [Technologies Used](#technologies-used) + - [1. Refine](#1-refine) + - [2. Ant Design](#2-ant-design) + - [3. GraphQL](#3-graphql) - [Best Practices and Ecosystem Integration](#best-practices-and-ecosystem-integration) - [Where Can You Use This CRM As A Reference Template?](#where-can-you-use-this-crm-as-a-reference-template) +- [Conclusion](#conclusion) ## Key Features of the CRM App diff --git a/documentation/blog/2024-03-26-react-hook-form.md b/documentation/blog/2024-03-26-react-hook-form.md index 4fa9e7e4819b..84145c5a94f5 100644 --- a/documentation/blog/2024-03-26-react-hook-form.md +++ b/documentation/blog/2024-03-26-react-hook-form.md @@ -539,7 +539,7 @@ Notice, we have multiple validation rules for the `content` field. React Hook Fo ### Handling Submission in React Hook Formxx -In React Hook Form, registered field data are accummulated in a `data` object with their `name` and field values. We handle submission of the form data with the `handleSubmit` method of the form instance. +In React Hook Form, registered field data are accumulated in a `data` object with their `name` and field values. We handle submission of the form data with the `handleSubmit` method of the form instance. Let's now deal with submitting the data by making changes to the form we have so far. Update the `App.js` to the following code with `formInstance.handleSubmit` passed to `onSubmit` event on `
` element: diff --git a/documentation/blog/2024-07-23-react-dashboard-libraries.md b/documentation/blog/2024-07-23-react-dashboard-libraries.md index 1c6997c934e9..fffda3ee5a2d 100644 --- a/documentation/blog/2024-07-23-react-dashboard-libraries.md +++ b/documentation/blog/2024-07-23-react-dashboard-libraries.md @@ -67,7 +67,7 @@ npm create refine-app@latest - GitHub stars: +27K - License: MIT -- Links: [Demo](https://example.crm.refine.dev/) | [Documentation](https://refine.dev/tutorial) | [GitHub](https://github.com/refinedev/refine/tree/master/examples/app-crm) +- Links: [Demo](https://example.crm.refine.dev/) | [Documentation](https://refine.dev/tutorial) | [Template](https://refine.dev/templates/crm-application/) ## Ant Design pro diff --git a/documentation/docs/ui-integrations/ant-design/migration-guide/index.md b/documentation/docs/ui-integrations/ant-design/migration-guide/index.md index 5465e98cf004..7a8fd917a859 100644 --- a/documentation/docs/ui-integrations/ant-design/migration-guide/index.md +++ b/documentation/docs/ui-integrations/ant-design/migration-guide/index.md @@ -167,7 +167,7 @@ Ant Design removed `less`, uses and recommends `CSS-in-JS` instead. You need to ### Compile errors -Some users repored ([issue#1](https://discord.com/channels/837692625737613362/1056236230641209396/1056236230641209396), [issue#2](https://discord.com/channels/837692625737613362/1056592183702061177/1056592183702061177)) compile errors after upgrading from `@refinedev/antd@3.x.x` to `@refinedev/antd@4.x.x`. They also provided solutions. +Some users reported ([issue#1](https://discord.com/channels/837692625737613362/1056236230641209396/1056236230641209396), [issue#2](https://discord.com/channels/837692625737613362/1056592183702061177/1056592183702061177)) compile errors after upgrading from `@refinedev/antd@3.x.x` to `@refinedev/antd@4.x.x`. They also provided solutions. #### Solution 1 diff --git a/examples/app-crm-minimal/package.json b/examples/app-crm-minimal/package.json index 03ff991cc66b..35af2d2843e2 100644 --- a/examples/app-crm-minimal/package.json +++ b/examples/app-crm-minimal/package.json @@ -30,6 +30,7 @@ "classnames": "^2.3.2", "cross-env": "^7.0.3", "dayjs": "^1.10.7", + "graphql": "^15.6.1", "graphql-tag": "^2.12.6", "graphql-ws": "^5.9.1", "react": "^18.0.0", diff --git a/examples/app-crm/.eslintrc b/examples/app-crm/.eslintrc deleted file mode 100644 index 88e66ea40311..000000000000 --- a/examples/app-crm/.eslintrc +++ /dev/null @@ -1,28 +0,0 @@ -{ - "env": { "browser": true, "es6": true }, - "parser": "@typescript-eslint/parser", - "parserOptions": { - "sourceType": "module" - }, - "plugins": ["@typescript-eslint", "simple-import-sort", "import"], - "extends": ["plugin:@typescript-eslint/recommended", "prettier"], - "rules": { - "simple-import-sort/imports": [ - "error", - { - "groups": [ - ["^react"], - ["^@refine"], - ["^@?\\w"], - ["^"], - ["^\\."], - ["^\\u0000"] - ] - } - ], - "simple-import-sort/exports": "error", - "import/first": "error", - "import/newline-after-import": "error", - "import/no-duplicates": "error" - } -} diff --git a/examples/app-crm/.gitignore b/examples/app-crm/.gitignore deleted file mode 100644 index 4d29575de804..000000000000 --- a/examples/app-crm/.gitignore +++ /dev/null @@ -1,23 +0,0 @@ -# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. - -# dependencies -/node_modules -/.pnp -.pnp.js - -# testing -/coverage - -# production -/build - -# misc -.DS_Store -.env.local -.env.development.local -.env.test.local -.env.production.local - -npm-debug.log* -yarn-debug.log* -yarn-error.log* diff --git a/examples/app-crm/README.md b/examples/app-crm/README.md index 80276a1cd18d..284692b1e0af 100644 --- a/examples/app-crm/README.md +++ b/examples/app-crm/README.md @@ -1,3 +1,5 @@ +> 🚨 This example has been moved to the Enterprise Edition. However, we still have a version available for the Community Edition. You can check it out [here](https://github.com/refinedev/refine/tree/master/examples/app-crm-minimal). + [![Cover Image](https://refine.ams3.cdn.digitaloceanspaces.com/example-readmes/CRM/crm-readme-temp.png "Cover Image")](https://github.com/refinedev/refine)
diff --git a/examples/app-crm/codegen.ts b/examples/app-crm/codegen.ts deleted file mode 100644 index dae50caccfac..000000000000 --- a/examples/app-crm/codegen.ts +++ /dev/null @@ -1,19 +0,0 @@ -import type { CodegenConfig } from "@graphql-codegen/cli"; - -const config: CodegenConfig = { - schema: "https://api.crm.refine.dev/graphql", - generates: { - "./src/interfaces/graphql.ts": { - plugins: ["typescript"], - documents: ["./src/**/*.tsx"], - config: { - skipTypename: true, - enumsAsTypes: true, - }, - hooks: { afterOneFileWrite: ["eslint --fix", "prettier --write"] }, - }, - }, - ignoreNoDocuments: true, -}; - -export default config; diff --git a/examples/app-crm/graphql.config.ts b/examples/app-crm/graphql.config.ts deleted file mode 100644 index a0028e6ca39c..000000000000 --- a/examples/app-crm/graphql.config.ts +++ /dev/null @@ -1,37 +0,0 @@ -import type { IGraphQLConfig } from "graphql-config"; - -const config: IGraphQLConfig = { - schema: "https://api.crm.refine.dev/graphql", - extensions: { - codegen: { - hooks: { - afterOneFileWrite: ["eslint --fix", "prettier --write"], - }, - generates: { - "src/graphql/schema.types.ts": { - plugins: ["typescript"], - config: { - skipTypename: true, - enumsAsTypes: true, - }, - }, - "src/graphql/types.ts": { - preset: "import-types", - documents: ["src/**/*.{ts,tsx}"], - plugins: ["typescript-operations"], - config: { - skipTypename: true, - enumsAsTypes: true, - preResolveTypes: false, - useTypeImports: true, - }, - presetConfig: { - typesPath: "./schema.types", - }, - }, - }, - }, - }, -}; - -export default config; diff --git a/examples/app-crm/index.html b/examples/app-crm/index.html deleted file mode 100644 index 155a2ba73ad0..000000000000 --- a/examples/app-crm/index.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - refine CRM App - - -
- - - diff --git a/examples/app-crm/jest.config.js b/examples/app-crm/jest.config.js deleted file mode 100644 index 47ef7280fe92..000000000000 --- a/examples/app-crm/jest.config.js +++ /dev/null @@ -1,30 +0,0 @@ -const { pathsToModuleNameMapper } = require("ts-jest"); -const { compilerOptions } = require("./tsconfig.json"); - -const paths = compilerOptions.paths ? compilerOptions.paths : {}; - -/** @type {import('ts-jest').JestConfigWithTsJest} */ -module.exports = { - preset: "ts-jest", - rootDir: "./", - testEnvironment: "jsdom", - setupFilesAfterEnv: ["/jest.setup.ts"], - testPathIgnorePatterns: ["/node_modules/"], - moduleNameMapper: { - ...pathsToModuleNameMapper(paths, { prefix: "/" }), - "\\.css$": "identity-obj-proxy", - }, - transform: { - "^.+\\.tsx?$": [ - "ts-jest", - { - tsconfig: "tsconfig.test.json", - }, - ], - }, - displayName: "app-crm", - coveragePathIgnorePatterns: [ - "/src/main.tsx", - "/src/interfaces/", - ], -}; diff --git a/examples/app-crm/jest.setup.ts b/examples/app-crm/jest.setup.ts deleted file mode 100644 index d1cbaf6df4dc..000000000000 --- a/examples/app-crm/jest.setup.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { configure } from "@testing-library/dom"; - -import "@testing-library/jest-dom"; -import "@testing-library/jest-dom/extend-expect"; - -configure({ - asyncUtilTimeout: 10000, -}); - -/** Antd mocks */ -window.matchMedia = jest.fn().mockImplementation((query) => { - return { - matches: false, - media: query, - onchange: null, - addListener: jest.fn(), - removeListener: jest.fn(), - }; -}); - -window.scroll = jest.fn(); -window.alert = jest.fn(); - -jest.setTimeout(20000); diff --git a/examples/app-crm/netlify.toml b/examples/app-crm/netlify.toml deleted file mode 100644 index b9e0f32e8651..000000000000 --- a/examples/app-crm/netlify.toml +++ /dev/null @@ -1,4 +0,0 @@ -[[redirects]] -from = "/*" -to = "/index.html" -status = 404 \ No newline at end of file diff --git a/examples/app-crm/package.json b/examples/app-crm/package.json deleted file mode 100644 index 72e18f4dbda6..000000000000 --- a/examples/app-crm/package.json +++ /dev/null @@ -1,87 +0,0 @@ -{ - "name": "app-crm", - "version": "1.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc && cross-env NODE_OPTIONS=--max_old_space_size=4096 refine build", - "codegen": "graphql-codegen", - "dev": "refine dev", - "format": "prettier src --write", - "lint": "eslint src --fix", - "refine": "refine", - "start": "refine start", - "test": "jest --passWithNoTests --runInBand" - }, - "dependencies": { - "@ant-design/icons": "5.0.1", - "@ant-design/plots": "^1.2.5", - "@dnd-kit/core": "^6.0.8", - "@dnd-kit/modifiers": "^6.0.1", - "@dnd-kit/sortable": "^7.0.2", - "@fullcalendar/core": "^6.1.8", - "@fullcalendar/daygrid": "^6.1.8", - "@fullcalendar/list": "^6.1.8", - "@fullcalendar/react": "^6.1.8", - "@fullcalendar/timegrid": "^6.1.8", - "@react-pdf/renderer": "^3.1.8", - "@refinedev/antd": "^5.43.1", - "@refinedev/cli": "^2.16.38", - "@refinedev/core": "^4.54.1", - "@refinedev/devtools": "^1.2.8", - "@refinedev/nestjs-query": "^1.3.3", - "@refinedev/react-router-v6": "^4.6.0", - "@uiw/react-md-editor": "^3.19.5", - "algoliasearch": "^4.19.1", - "antd": "^5.17.0", - "axios": "^1.6.2", - "classnames": "^2.3.2", - "cross-env": "^7.0.3", - "dayjs": "^1.10.7", - "graphql": "^15.6.1", - "graphql-tag": "^2.12.6", - "graphql-ws": "^5.9.1", - "leaflet": "^1.9.4", - "lodash": "^4.17.21", - "react": "^18.0.0", - "react-dom": "^18.0.0", - "react-instantsearch": "^7.0.1", - "react-leaflet": "^4.2.1", - "react-leaflet-cluster": "^2.1.0", - "react-router-dom": "^6.8.1" - }, - "devDependencies": { - "@graphql-codegen/cli": "^5.0.0", - "@graphql-codegen/import-types-preset": "^3.0.0", - "@graphql-codegen/typescript": "^4.0.1", - "@graphql-codegen/typescript-operations": "^4.0.1", - "@testing-library/jest-dom": "^5.16.4", - "@testing-library/react": "^13.1.1", - "@testing-library/user-event": "^14.1.1", - "@types/jest": "^29.2.4", - "@types/leaflet": "^1.9.3", - "@types/lodash": "^4.14.171", - "@types/node": "^18.16.2", - "@types/react": "^18.0.0", - "@types/react-dom": "^18.0.0", - "@types/testing-library__jest-dom": "^5.14.3", - "@typescript-eslint/eslint-plugin": "5.48.0", - "@typescript-eslint/parser": "5.48.0", - "@vitejs/plugin-react": "^4.2.1", - "autoprefixer": "^10.4.1", - "eslint": "^8.24.0", - "eslint-config-prettier": "^8.5.0", - "eslint-plugin-import": "^2.29.1", - "eslint-plugin-simple-import-sort": "^10.0.0", - "identity-obj-proxy": "^3.0.0", - "jest": "^29.3.1", - "jest-environment-jsdom": "^29.3.1", - "postcss": "^8.1.4", - "postcss-nesting": "^12.0.1", - "prettier": "^2.7.1", - "ts-jest": "^29.1.2", - "typescript": "^5.4.2", - "vite": "^5.1.6", - "vite-tsconfig-paths": "^4.2.1" - } -} diff --git a/examples/app-crm/postcss.config.cjs b/examples/app-crm/postcss.config.cjs deleted file mode 100644 index d47373e13ac7..000000000000 --- a/examples/app-crm/postcss.config.cjs +++ /dev/null @@ -1,6 +0,0 @@ -module.exports = { - plugins: { - autoprefixer: {}, - "postcss-nesting": {}, - }, -}; diff --git a/examples/app-crm/public/refine_favicon.png b/examples/app-crm/public/refine_favicon.png deleted file mode 100644 index e002695b2b0e..000000000000 Binary files a/examples/app-crm/public/refine_favicon.png and /dev/null differ diff --git a/examples/app-crm/sandbox.config.json b/examples/app-crm/sandbox.config.json deleted file mode 100644 index fb3271d9849a..000000000000 --- a/examples/app-crm/sandbox.config.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "port": 5173, - "container": { - "node": 16, - "port": 5173, - "startScript": "start" - } -} diff --git a/examples/app-crm/src/App.tsx b/examples/app-crm/src/App.tsx deleted file mode 100644 index d8b16a6eb13d..000000000000 --- a/examples/app-crm/src/App.tsx +++ /dev/null @@ -1,298 +0,0 @@ -import { BrowserRouter, Outlet, Route, Routes } from "react-router-dom"; - -import { ErrorComponent, useNotificationProvider } from "@refinedev/antd"; -import { Authenticated, Refine } from "@refinedev/core"; -import { DevtoolsPanel, DevtoolsProvider } from "@refinedev/devtools"; -import routerProvider, { - CatchAllNavigate, - DocumentTitleHandler, - NavigateToResource, - UnsavedChangesNotifier, -} from "@refinedev/react-router-v6"; - -import { App as AntdApp, ConfigProvider } from "antd"; - -import { resources, themeConfig } from "@/config"; -import { authProvider, dataProvider, liveProvider } from "@/providers"; - -import { AlgoliaSearchWrapper, FullScreenLoading, Layout } from "./components"; -import { useAutoLoginForDemo } from "./hooks"; -import { AuditLogPage, SettingsPage } from "./routes/administration"; -import { - CalendarCreatePage, - CalendarEditPage, - CalendarPageWrapper, - CalendarShowPage, -} from "./routes/calendar"; -import { - CompanyCreatePage, - CompanyEditPage, - CompanyListPage, -} from "./routes/companies"; -import { - ContactCreatePage, - ContactShowPage, - ContactsListPage, -} from "./routes/contacts"; -import { DashboardPage } from "./routes/dashboard"; -import { ForgotPasswordPage } from "./routes/forgot-password"; -import { LoginPage } from "./routes/login"; -import { - QuotesCreatePage, - QuotesEditPage, - QuotesListPage, - QuotesShowPage, -} from "./routes/quotes"; -import { RegisterPage } from "./routes/register"; -import { - KanbanCreatePage, - KanbanCreateStage, - KanbanEditPage, - KanbanEditStage, - KanbanPage, -} from "./routes/scrumboard/kanban"; -import { - SalesCreatePage, - SalesCreateStage, - SalesEditPage, - SalesEditStage, - SalesFinalizeDeal, - SalesPage, -} from "./routes/scrumboard/sales"; -import { UpdatePasswordPage } from "./routes/update-password"; - -import "./utilities/init-dayjs"; -import "@refinedev/antd/dist/reset.css"; -import "./styles/antd.css"; -import "./styles/fc.css"; -import "./styles/index.css"; - -const App: React.FC = () => { - // This hook is used to automatically login the user. - // We use this hook to skip the login page and demonstrate the application more quickly. - const { loading } = useAutoLoginForDemo(); - - if (loading) { - return ; - } - - return ( - - - - - - - - } - > - - - - - } - > - } /> - - - - } - > - - } /> - } /> - } /> - - }> - - - - } - > - } /> - } /> - } - /> - } - /> - - - - - } - > - - - - } - > - } - /> - - } /> - } - /> - } - /> - } - /> - - - - - - } - > - } /> - - } - /> - - - - } - > - - } /> - - - - } - > - } - /> - - - - - - } - > - - - - } - > - } - /> - - - - - } - > - } - /> - - - } - /> - }> - } /> - } /> - - } /> - - } - > - - - } - > - } /> - } /> - } - /> - } - /> - - - - - - - - - - - - ); -}; - -export default App; diff --git a/examples/app-crm/src/components/calendar/index.ts b/examples/app-crm/src/components/calendar/index.ts deleted file mode 100644 index 978fb81edbb6..000000000000 --- a/examples/app-crm/src/components/calendar/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./upcoming-events"; diff --git a/examples/app-crm/src/components/calendar/upcoming-events/event/index.tsx b/examples/app-crm/src/components/calendar/upcoming-events/event/index.tsx deleted file mode 100644 index c38a21edb737..000000000000 --- a/examples/app-crm/src/components/calendar/upcoming-events/event/index.tsx +++ /dev/null @@ -1,70 +0,0 @@ -import React from "react"; - -import { useNavigation } from "@refinedev/core"; -import type { GetFieldsFromList } from "@refinedev/nestjs-query"; - -import { Badge } from "antd"; -import dayjs from "dayjs"; - -import type { UpcomingEventsQuery } from "@/graphql/types"; - -import { Text } from "../../../text"; -import styles from "../index.module.css"; - -type CalendarUpcomingEventProps = { - item: GetFieldsFromList; -}; - -export const CalendarUpcomingEvent: React.FC = ({ - item, -}) => { - const { show } = useNavigation(); - const { id, title, startDate, endDate, color } = item; - const isToday = dayjs.utc(startDate).isSame(dayjs.utc(), "day"); - const isTomorrow = dayjs - .utc(startDate) - .isSame(dayjs.utc().add(1, "day"), "day"); - const isAllDayEvent = - dayjs.utc(startDate).startOf("day").isSame(startDate) && - dayjs.utc(endDate).endOf("day").isSame(endDate); - - const renderDate = () => { - if (isToday) { - return "Today"; - } - - if (isTomorrow) { - return "Tomorrow"; - } - - return dayjs(startDate).format("MMM DD"); - }; - - const renderTime = () => { - if (isAllDayEvent) { - return "All day"; - } - - return `${dayjs(startDate).format("HH:mm")} - ${dayjs(endDate).format( - "HH:mm", - )}`; - }; - - return ( -
{ - show("events", item.id); - }} - key={id} - className={styles.item} - > -
- - {`${renderDate()}, ${renderTime()}`} -
- - {title} - -
- ); -}; diff --git a/examples/app-crm/src/components/calendar/upcoming-events/index.module.css b/examples/app-crm/src/components/calendar/upcoming-events/index.module.css deleted file mode 100644 index 03cda6f45b12..000000000000 --- a/examples/app-crm/src/components/calendar/upcoming-events/index.module.css +++ /dev/null @@ -1,21 +0,0 @@ -.item { - padding: 1rem 0; - border-bottom: 1px solid rgba(0, 0, 0, 0.06); - cursor: pointer; - - .date { - margin-bottom: 0.25rem; - } - - .badge { - margin-right: 1.1rem; - } - - .title { - padding-left: 1.5rem; - } -} - -.item:last-child { - border-bottom: none; -} diff --git a/examples/app-crm/src/components/calendar/upcoming-events/index.tsx b/examples/app-crm/src/components/calendar/upcoming-events/index.tsx deleted file mode 100644 index 5112b3299332..000000000000 --- a/examples/app-crm/src/components/calendar/upcoming-events/index.tsx +++ /dev/null @@ -1,140 +0,0 @@ -import React from "react"; - -import { useList, useNavigation } from "@refinedev/core"; -import type { GetFieldsFromList } from "@refinedev/nestjs-query"; - -import { CalendarOutlined, RightCircleOutlined } from "@ant-design/icons"; -import type { CardProps } from "antd"; -import { Button, Card, Skeleton as AntdSkeleton } from "antd"; -import dayjs from "dayjs"; - -import type { UpcomingEventsQuery } from "@/graphql/types"; - -import { Text } from "../../text"; -import { CalendarUpcomingEvent } from "./event"; -import styles from "./index.module.css"; -import { CALENDAR_UPCOMING_EVENTS_QUERY } from "./queries"; - -type CalendarUpcomingEventsProps = { - limit?: number; - cardProps?: CardProps; - showGoToListButton?: boolean; -}; - -const NoEvent: React.FC = () => ( - - No Upcoming Event - -); - -const Skeleton: React.FC = () => { - return ( -
-
- - -
-
- ); -}; - -export const CalendarUpcomingEvents: React.FC = ({ - limit = 5, - cardProps, - showGoToListButton, -}) => { - const { list } = useNavigation(); - - const { data, isLoading } = useList>({ - resource: "events", - pagination: { - pageSize: limit, - }, - sorters: [ - { - field: "startDate", - order: "asc", - }, - ], - filters: [ - { - field: "startDate", - operator: "gte", - value: dayjs().format("YYYY-MM-DD"), - }, - ], - meta: { - gqlQuery: CALENDAR_UPCOMING_EVENTS_QUERY, - }, - }); - - return ( - - {/* @ts-expect-error Ant Design Icon's v5.0.1 has an issue with @types/react@^18.2.66 */} - - - Upcoming events - -
- } - extra={ - showGoToListButton && ( - // @ts-expect-error Ant Design Icon's v5.0.1 has an issue with @types/react@^18.2.66 - - ) - } - {...cardProps} - > - {isLoading && - Array.from({ length: limit }).map((_, index) => ( - - ))} - {!isLoading && - data?.data.map((item) => ( - - ))} - {!isLoading && data?.data.length === 0 && } - - ); -}; diff --git a/examples/app-crm/src/components/calendar/upcoming-events/queries.ts b/examples/app-crm/src/components/calendar/upcoming-events/queries.ts deleted file mode 100644 index 52c4fb747299..000000000000 --- a/examples/app-crm/src/components/calendar/upcoming-events/queries.ts +++ /dev/null @@ -1,20 +0,0 @@ -import gql from "graphql-tag"; - -export const CALENDAR_UPCOMING_EVENTS_QUERY = gql` - query UpcomingEvents( - $filter: EventFilter! - $sorting: [EventSort!] - $paging: OffsetPaging! - ) { - events(filter: $filter, sorting: $sorting, paging: $paging) { - nodes { - id - title - color - startDate - endDate - } - totalCount - } - } -`; diff --git a/examples/app-crm/src/components/custom-avatar.tsx b/examples/app-crm/src/components/custom-avatar.tsx deleted file mode 100644 index 3ebbcb4cacd7..000000000000 --- a/examples/app-crm/src/components/custom-avatar.tsx +++ /dev/null @@ -1,38 +0,0 @@ -import { type FC, memo } from "react"; - -import type { AvatarProps } from "antd"; -import { Avatar as AntdAvatar } from "antd"; - -import { getNameInitials, getRandomColorFromString } from "@/utilities"; - -type Props = AvatarProps & { - name?: string; -}; - -const CustomAvatarComponent: FC = ({ name = "", style, ...rest }) => { - return ( - - {getNameInitials(name)} - - ); -}; - -export const CustomAvatar = memo( - CustomAvatarComponent, - (prevProps, nextProps) => { - return prevProps.name === nextProps.name && prevProps.src === nextProps.src; - }, -); diff --git a/examples/app-crm/src/components/fullscreen-loading/index.tsx b/examples/app-crm/src/components/fullscreen-loading/index.tsx deleted file mode 100644 index 05e680de2ef8..000000000000 --- a/examples/app-crm/src/components/fullscreen-loading/index.tsx +++ /dev/null @@ -1,16 +0,0 @@ -import { Spin } from "antd"; - -export const FullScreenLoading = () => { - return ( - - ); -}; diff --git a/examples/app-crm/src/components/icon/TextIcon.tsx b/examples/app-crm/src/components/icon/TextIcon.tsx deleted file mode 100644 index 88c7b1df7553..000000000000 --- a/examples/app-crm/src/components/icon/TextIcon.tsx +++ /dev/null @@ -1,33 +0,0 @@ -import Icon from "@ant-design/icons"; -import type { CustomIconComponentProps } from "@ant-design/icons/lib/components/Icon"; - -export const TextIconSvg = () => ( - - - - - -); - -export const TextIcon = (props: Partial) => ( - // @ts-expect-error Ant Design Icon's v5.0.1 has an issue with @types/react@^18.2.66 - -); diff --git a/examples/app-crm/src/components/icon/index.ts b/examples/app-crm/src/components/icon/index.ts deleted file mode 100644 index 5d0922a94f76..000000000000 --- a/examples/app-crm/src/components/icon/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./TextIcon"; diff --git a/examples/app-crm/src/components/index.ts b/examples/app-crm/src/components/index.ts deleted file mode 100644 index 7c8bf8f8ada2..000000000000 --- a/examples/app-crm/src/components/index.ts +++ /dev/null @@ -1,15 +0,0 @@ -export * from "./calendar"; -export * from "./custom-avatar"; -export * from "./fullscreen-loading"; -export * from "./icon"; -export * from "./layout"; -export * from "./layout/algolia-search/wrapper"; -export * from "./layout/logo"; -export * from "./layout/title"; -export * from "./list-title-button"; -export * from "./pagination-total"; -export * from "./participants"; -export * from "./select-option-with-avatar"; -export * from "./single-element-form"; -export * from "./tags"; -export * from "./text"; diff --git a/examples/app-crm/src/components/layout/account-settings/index.module.css b/examples/app-crm/src/components/layout/account-settings/index.module.css deleted file mode 100644 index 3c121f4f9214..000000000000 --- a/examples/app-crm/src/components/layout/account-settings/index.module.css +++ /dev/null @@ -1,45 +0,0 @@ -.header { - display: flex; - justify-content: space-between; - align-items: center; - background-color: #fff; - padding: 16px; -} - -.container { - display: flex; - flex-direction: column; - gap: 32px; - padding: 24px; - - .title { - display: block; - margin: 0 !important; - - .titleEditIcon { - visibility: hidden; - opacity: 0; - transition: all 0.2s ease-in-out; - } - - &:hover { - .titleEditIcon { - opacity: 1; - visibility: visible !important; - } - } - } - - .name { - display: flex; - align-items: center; - justify-content: flex-start; - padding: 1rem; - } - - .form { - background-color: #fff; - border-radius: 0.5rem; - margin-bottom: 1.75rem; - } -} diff --git a/examples/app-crm/src/components/layout/account-settings/index.tsx b/examples/app-crm/src/components/layout/account-settings/index.tsx deleted file mode 100644 index 17ad761bcb87..000000000000 --- a/examples/app-crm/src/components/layout/account-settings/index.tsx +++ /dev/null @@ -1,295 +0,0 @@ -import { useState } from "react"; - -import { type HttpError, useOne, useUpdate } from "@refinedev/core"; -import type { GetFields, GetVariables } from "@refinedev/nestjs-query"; - -import { - CloseOutlined, - EditOutlined, - GlobalOutlined, - IdcardOutlined, - MailOutlined, - PhoneOutlined, - SafetyCertificateOutlined, - UserOutlined, -} from "@ant-design/icons"; -import { - Button, - Card, - Drawer, - Input, - Select, - Space, - Spin, - Typography, -} from "antd"; - -import { TimezoneEnum } from "@/enums"; -import type { - AccountSettingsGetUserQuery, - AccountSettingsUpdateUserMutation, - AccountSettingsUpdateUserMutationVariables, -} from "@/graphql/types"; - -import { CustomAvatar } from "../../custom-avatar"; -import { SingleElementForm } from "../../single-element-form"; -import { Text } from "../../text"; -import styles from "./index.module.css"; -import { - ACCOUNT_SETTINGS_GET_USER_QUERY, - ACCOUNT_SETTINGS_UPDATE_USER_MUTATION, -} from "./queries"; - -const timezoneOptions = Object.keys(TimezoneEnum).map((key) => ({ - label: TimezoneEnum[key as keyof typeof TimezoneEnum], - value: TimezoneEnum[key as keyof typeof TimezoneEnum], -})); - -type Props = { - opened: boolean; - setOpened: (opened: boolean) => void; - userId: string; -}; - -type FormKeys = "email" | "jobTitle" | "phone" | "timezone"; - -export const AccountSettings = ({ opened, setOpened, userId }: Props) => { - const [activeForm, setActiveForm] = useState(); - - const { data, isLoading, isError } = useOne< - GetFields - >({ - resource: "users", - id: userId, - queryOptions: { - enabled: opened, - }, - meta: { - gqlQuery: ACCOUNT_SETTINGS_GET_USER_QUERY, - }, - }); - - const { mutate: updateMutation } = useUpdate< - GetFields, - HttpError, - GetVariables - >(); - - const closeModal = () => { - setOpened(false); - }; - - if (isError) { - closeModal(); - return null; - } - - if (isLoading) { - return ( - - - - ); - } - - const { id, name, email, jobTitle, phone, timezone, avatarUrl } = - data?.data ?? {}; - - const getActiveForm = (key: FormKeys) => { - if (activeForm === key) { - return "form"; - } - - if (!data?.data[key]) { - return "empty"; - } - - return "view"; - }; - - return ( - -
- Account Settings -
-
-
- - , - }} - > - {name} - -
- - {/* @ts-expect-error Ant Design Icon's v5.0.1 has an issue with @types/react@^18.2.66 */} - - User profile - - } - headStyle={{ padding: "0 12px" }} - bodyStyle={{ padding: "0" }} - > - } - state={getActiveForm("jobTitle")} - itemProps={{ - name: "jobTitle", - label: "Title", - }} - view={{jobTitle}} - onClick={() => setActiveForm("jobTitle")} - onUpdate={() => setActiveForm(undefined)} - onCancel={() => setActiveForm(undefined)} - > - - - } - state={getActiveForm("phone")} - itemProps={{ - name: "phone", - label: "Phone", - }} - view={{phone}} - onClick={() => setActiveForm("phone")} - onUpdate={() => setActiveForm(undefined)} - onCancel={() => setActiveForm(undefined)} - > - - - } - state={getActiveForm("timezone")} - itemProps={{ - name: "timezone", - label: "TimezoneEnum", - }} - view={{timezone}} - onClick={() => setActiveForm("timezone")} - onUpdate={() => setActiveForm(undefined)} - onCancel={() => setActiveForm(undefined)} - > - - - -
-
- ); -}; diff --git a/examples/app-crm/src/components/layout/account-settings/queries.ts b/examples/app-crm/src/components/layout/account-settings/queries.ts deleted file mode 100644 index fe48bfd97a04..000000000000 --- a/examples/app-crm/src/components/layout/account-settings/queries.ts +++ /dev/null @@ -1,29 +0,0 @@ -import gql from "graphql-tag"; - -export const ACCOUNT_SETTINGS_GET_USER_QUERY = gql` - query AccountSettingsGetUser($id: ID!) { - user(id: $id) { - id - name - email - avatarUrl - jobTitle - phone - timezone - } - } -`; - -export const ACCOUNT_SETTINGS_UPDATE_USER_MUTATION = gql` - mutation AccountSettingsUpdateUser($input: UpdateOneUserInput!) { - updateOneUser(input: $input) { - id - name - email - avatarUrl - jobTitle - phone - timezone - } - } -`; diff --git a/examples/app-crm/src/components/layout/algolia-search/index.module.css b/examples/app-crm/src/components/layout/algolia-search/index.module.css deleted file mode 100644 index 39b0e8e49b56..000000000000 --- a/examples/app-crm/src/components/layout/algolia-search/index.module.css +++ /dev/null @@ -1,54 +0,0 @@ -.container { - display: flex; - justify-content: center; - align-items: center; -} - -.popover { - .ant-input-affix-wrapper, - .ant-input-affix-wrapper-lg { - padding: 0 !important; - } -} - -.input { - min-width: 256px !important; - min-height: 30px !important; - max-height: 30px !important; - font-size: 14px !important; -} - -.inputPrefix { - margin-right: 4px; - font-size: 12px !important; -} - -.inputSuffix { - user-select: none; - width: 20px; - height: 20px; - display: flex; - align-items: center; - justify-content: center; - background-color: #f0f0f0; - color: #b4b4b4; - border-radius: 4px; - font-size: 12px !important; -} - -.list { - height: auto; - max-height: 60vh; - overflow: auto; -} - -.listItem { - cursor: pointer; - border-block-end: 1px solid rgba(72, 48, 24, 0.04) !important; -} - -.title { - display: flex; - justify-content: space-between; - text-transform: capitalize; -} diff --git a/examples/app-crm/src/components/layout/algolia-search/index.tsx b/examples/app-crm/src/components/layout/algolia-search/index.tsx deleted file mode 100644 index 211294aed4f6..000000000000 --- a/examples/app-crm/src/components/layout/algolia-search/index.tsx +++ /dev/null @@ -1,199 +0,0 @@ -import { type FC, useState } from "react"; -import { useHits, useSearchBox } from "react-instantsearch"; -import { Link } from "react-router-dom"; - -import { useNavigation, useResource } from "@refinedev/core"; - -import { SearchOutlined } from "@ant-design/icons"; -import { Input, List, Popover, Tag, Typography } from "antd"; -import cn from "classnames"; - -import type { - Company, - Contact, - Deal, - Event, - Quote, - Task, - User, -} from "@/graphql/schema.types"; - -import { CustomAvatar } from "../../custom-avatar"; -import styles from "./index.module.css"; - -export const AlgoliaSearch: React.FC = () => { - const [open, setOpen] = useState(false); - const { query, refine } = useSearchBox(); - const [inputValue, setInputValue] = useState(query); - - const setQuery = (newQuery: string) => { - setInputValue(newQuery); - refine(newQuery); - }; - - return ( -
- { - setOpen(false); - setInputValue(""); - }} - /> - } - trigger="click" - open={!!inputValue || open} - onOpenChange={(open) => { - setOpen(open); - }} - > - - } - suffix={
/
} - placeholder="Search" - autoComplete="off" - autoCorrect="off" - autoCapitalize="off" - spellCheck={false} - maxLength={512} - type="search" - value={inputValue} - onChange={(event) => { - setQuery(event.currentTarget.value); - }} - /> -
-
- ); -}; - -type Hit = (User | Deal | Task | Company | Contact | Quote | Event) & { - resource: string; -}; - -type SearchResultProps = { - onHitClick: () => void; -}; - -export const AlgoliaSearchResult: FC = ({ onHitClick }) => { - const { showUrl, editUrl } = useNavigation(); - const { hits } = useHits() as { hits: Hit[] }; - const { select } = useResource(); - - const getTitle = (item: Hit) => { - if ("name" in item) { - return item.name; - } - - if ("title" in item) { - return item.title; - } - - return ""; - }; - - const getDescription = (item: Hit) => { - if ("description" in item) { - return item.description; - } - - if ("jobTitle" in item) { - return item.jobTitle; - } - - if ("email" in item) { - return item.email; - } - - if ("industry" in item) { - return `${item.industry}`; - } - }; - - const getResourceLabel = (resource: string) => { - const label = select(resource).resource.meta?.label ?? resource; - return label; - }; - - const getResourceLink = (item: Hit) => { - if (["contacts", "quotes", "events", "user"].includes(item.resource)) { - return showUrl(item.resource, item.id); - } - - if (["tasks", "deals", "companies"].includes(item.resource)) { - return editUrl(item.resource, item.id); - } - - return ""; - }; - - return ( - { - return ( - - - - {item.name} - - ) : null - } - title={ -
- - {getTitle(item)} - - - {getResourceLabel(item.resource)} - -
- } - description={ - - {getDescription(item)} - - } - /> -
- - ); - }} - /> - ); -}; diff --git a/examples/app-crm/src/components/layout/algolia-search/wrapper.tsx b/examples/app-crm/src/components/layout/algolia-search/wrapper.tsx deleted file mode 100644 index 0931177009e4..000000000000 --- a/examples/app-crm/src/components/layout/algolia-search/wrapper.tsx +++ /dev/null @@ -1,18 +0,0 @@ -import type { PropsWithChildren } from "react"; -import { InstantSearch } from "react-instantsearch"; - -import { indexName, searchClient } from "@/providers"; - -export const AlgoliaSearchWrapper: React.FC = ({ - children, -}) => { - if (!searchClient) { - return <>{children}; - } - - return ( - - {children} - - ); -}; diff --git a/examples/app-crm/src/components/layout/current-user.tsx b/examples/app-crm/src/components/layout/current-user.tsx deleted file mode 100644 index 03ce8421a6d0..000000000000 --- a/examples/app-crm/src/components/layout/current-user.tsx +++ /dev/null @@ -1,93 +0,0 @@ -import { useState } from "react"; - -import { useGetIdentity, useLogout } from "@refinedev/core"; - -import { LogoutOutlined, SettingOutlined } from "@ant-design/icons"; -import { Button, Popover } from "antd"; - -import type { User } from "@/graphql/schema.types"; - -import { CustomAvatar } from "../custom-avatar"; -import { Text } from "../text"; -import { AccountSettings } from "./account-settings"; - -export const CurrentUser: React.FC = () => { - const [opened, setOpened] = useState(false); - const { data: user } = useGetIdentity(); - const { mutate: logout } = useLogout(); - - const content = ( -
- - {user?.name} - -
- - -
-
- ); - - return ( - <> - - - - {user && ( - - )} - - ); -}; diff --git a/examples/app-crm/src/components/layout/gh-banner/index.tsx b/examples/app-crm/src/components/layout/gh-banner/index.tsx deleted file mode 100644 index 4495a2cd2220..000000000000 --- a/examples/app-crm/src/components/layout/gh-banner/index.tsx +++ /dev/null @@ -1,248 +0,0 @@ -import React, { type SVGProps, useEffect } from "react"; - -import { CSSRules } from "./styles"; - -export const GitHubBanner = () => { - useEffect(() => { - const styleTag = document.createElement("style"); - document.head.appendChild(styleTag); - CSSRules.forEach((rule) => - styleTag.sheet?.insertRule(rule, styleTag.sheet.cssRules.length), - ); - }, []); - - return ( -
-
-
-
-
- - - -
- -
- - - -
-
-
- -
-
- ); -}; - -const Text = () => { - return ( - -
- - 💡 - - - This example is open-source! Get the full source code. - -
-
- ); -}; - -const GlowSmall = ({ style, ...props }: SVGProps) => { - return ( - - - - - - - - - - ); -}; - -const GlowBig = ({ style, ...props }: SVGProps) => ( - - - - - - - - - -); diff --git a/examples/app-crm/src/components/layout/gh-banner/styles.ts b/examples/app-crm/src/components/layout/gh-banner/styles.ts deleted file mode 100644 index 6a9e6f6e77c5..000000000000 --- a/examples/app-crm/src/components/layout/gh-banner/styles.ts +++ /dev/null @@ -1,46 +0,0 @@ -export const CSSRules = [ - ` - .bg-top-announcement { - border-bottom: 1px solid rgba(71, 235, 235, 0.15); - background: radial-gradient( - 218.19% 111.8% at 0% 0%, - rgba(71, 235, 235, 0.1) 0%, - rgba(71, 235, 235, 0.2) 100% - ), - #14141f; - } - `, - ` - .top-announcement-mask { - mask-image: url(https://refine.ams3.cdn.digitaloceanspaces.com/website/static/assets/hexagon.svg); - -webkit-mask-image: url(https://refine.ams3.cdn.digitaloceanspaces.com/website/static/assets/hexagon.svg); - mask-repeat: repeat; - -webkit-mask-repeat: repeat; - background: rgba(71, 235, 235, 0.25); - } - `, - ` - .banner { - display: flex; - @media (max-width: 1100px) { - display: none; - } - }`, - ` - .gh-link, .gh-link:hover, .gh-link:active, .gh-link:visited, .gh-link:focus { - text-decoration: none; - z-index: 9; - } - `, - ` - @keyframes top-announcement-glow { - 0% { - opacity: 1; - } - - 100% { - opacity: 0; - } - } - `, -]; diff --git a/examples/app-crm/src/components/layout/header.tsx b/examples/app-crm/src/components/layout/header.tsx deleted file mode 100644 index 5d00dd3ef938..000000000000 --- a/examples/app-crm/src/components/layout/header.tsx +++ /dev/null @@ -1,37 +0,0 @@ -import React from "react"; - -import { Layout, Space, theme } from "antd"; - -import { searchClient } from "@/providers"; - -import { AlgoliaSearch } from "./algolia-search"; -import { CurrentUser } from "./current-user"; -import { Notifications } from "./notifications"; - -const { useToken } = theme; - -export const Header: React.FC = () => { - const { token } = useToken(); - - const headerStyles: React.CSSProperties = { - backgroundColor: token.colorBgElevated, - display: "flex", - justifyContent: searchClient ? "space-between" : "flex-end", - alignItems: "center", - padding: "0px 24px", - height: "64px", - position: "sticky", - top: 0, - zIndex: 999, - }; - - return ( - - {searchClient ? : null} - - - - - - ); -}; diff --git a/examples/app-crm/src/components/layout/index.tsx b/examples/app-crm/src/components/layout/index.tsx deleted file mode 100644 index c727e4ecb0c6..000000000000 --- a/examples/app-crm/src/components/layout/index.tsx +++ /dev/null @@ -1,33 +0,0 @@ -import React from "react"; - -import { ThemedLayoutContextProvider } from "@refinedev/antd"; - -import { Grid, Layout as AntdLayout } from "antd"; - -import { GitHubBanner } from "./gh-banner"; -import { Header } from "./header"; -import { Sider } from "./sider"; - -export const Layout: React.FC = ({ children }) => { - const breakpoint = Grid.useBreakpoint(); - const isSmall = typeof breakpoint.sm === "undefined" ? true : breakpoint.sm; - - return ( - - - - - -
- - {children} - - - - - ); -}; diff --git a/examples/app-crm/src/components/layout/logo.tsx b/examples/app-crm/src/components/layout/logo.tsx deleted file mode 100644 index 81fb28697d09..000000000000 --- a/examples/app-crm/src/components/layout/logo.tsx +++ /dev/null @@ -1,19 +0,0 @@ -import React from "react"; - -export const Logo = (props: React.SVGProps) => ( - - - -); diff --git a/examples/app-crm/src/components/layout/notification-message.tsx b/examples/app-crm/src/components/layout/notification-message.tsx deleted file mode 100644 index f0c14f9a83ff..000000000000 --- a/examples/app-crm/src/components/layout/notification-message.tsx +++ /dev/null @@ -1,42 +0,0 @@ -import type { GetFieldsFromList } from "@refinedev/nestjs-query"; - -import type { - NotificationsDealsQuery, - NotificationsQuery, -} from "@/graphql/types"; - -import { Text } from "../text"; - -type Props = { - audit: GetFieldsFromList; - deal?: GetFieldsFromList; -}; - -export const NotificationMessage = ({ audit, deal }: Props) => { - if (!deal) return Loading...; - - if (audit.action === "UPDATE") { - return ( - - {audit.user?.name} - {" moved "} - {deal.title} - {" deal to "} - {deal.stage?.title || "Unassigned"}. - - ); - } - if (audit.action === "CREATE") { - return ( - - {audit.user?.name} - {" created "} - {deal.title} - {" deal in "} - {deal.stage?.title || "Unassigned"}. - - ); - } - - return Unknown action; -}; diff --git a/examples/app-crm/src/components/layout/notifications.tsx b/examples/app-crm/src/components/layout/notifications.tsx deleted file mode 100644 index a0b041643cc9..000000000000 --- a/examples/app-crm/src/components/layout/notifications.tsx +++ /dev/null @@ -1,115 +0,0 @@ -import React, { useState } from "react"; - -import { useList, useMany } from "@refinedev/core"; -import type { GetFieldsFromList } from "@refinedev/nestjs-query"; - -import { BellOutlined } from "@ant-design/icons"; -import { Badge, Button, Divider, Popover, Space, Spin } from "antd"; -import dayjs from "dayjs"; - -import type { - NotificationsDealsQuery, - NotificationsQuery, -} from "@/graphql/types"; - -import { CustomAvatar } from "../custom-avatar"; -import { Text } from "../text"; -import { NotificationMessage } from "./notification-message"; -import { NOTIFICATIONS_DEALS_QUERY, NOTIFICATIONS_QUERY } from "./queries"; - -export const Notifications: React.FC = () => { - const [open, setOpen] = useState(false); - - const { data, isLoading } = useList>({ - resource: "audits", - pagination: { - pageSize: 5, - }, - sorters: [{ field: "createdAt", order: "desc" }], - filters: [ - { - field: "action", - operator: "in", - value: ["CREATE", "UPDATE"], - }, - { - field: "targetEntity", - operator: "eq", - value: "Deal", - }, - ], - meta: { - gqlQuery: NOTIFICATIONS_QUERY, - }, - queryOptions: { - enabled: open, - }, - }); - - const targetIds = data?.data?.map((audit) => audit.targetId); - const { data: dealData } = useMany< - GetFieldsFromList - >({ - resource: "deals", - ids: targetIds ?? [], - meta: { - gqlQuery: NOTIFICATIONS_DEALS_QUERY, - }, - queryOptions: { - enabled: Boolean(targetIds?.length), - }, - }); - - const getDeal = (id: string | number) => { - return dealData?.data?.find((deal) => deal.id === id); - }; - - const content = ( - }> - {data?.data?.map((audit) => ( - - - - - - {dayjs(audit?.createdAt).fromNow()} - - - - ))} - - ); - - const loadingContent = ( -
- -
- ); - - return ( - setOpen(newOpen)} - overlayStyle={{ width: 400 }} - > - - {/* @ts-expect-error Ant Design Icon's v5.0.1 has an issue with @types/react@^18.2.66 */} -