diff --git a/.github/workflows/build-remote.js b/.github/workflows/build-remote.js index e1bd32bda..d102e7ccb 100644 --- a/.github/workflows/build-remote.js +++ b/.github/workflows/build-remote.js @@ -22,6 +22,12 @@ const buildRemote = async () => { hasura: ["keycloak", "custom"], }; + const uiFrameworkToExampleMap = { + antd: "antd-example", + mui: "mui-example", + no: "headless-example", + }; + let AUTH_PROVIDER = dataProviderMap[DATA_PROVIDER]; if (Array.isArray(AUTH_PROVIDER)) { @@ -47,11 +53,9 @@ const buildRemote = async () => { icon: "refine.svg", "data-provider": `data-provider-${DATA_PROVIDER}`, "ui-framework": UI_FRAMEWORK, - [UI_FRAMEWORK === "no" ? "inferencer-headless" : "inferencer"]: - UI_FRAMEWORK === "no" ? "inferencer-headless" : "inferencer", + [uiFrameworkToExampleMap[UI_FRAMEWORK]]: + uiFrameworkToExampleMap[UI_FRAMEWORK], "auth-provider": `auth-provider-${AUTH_PROVIDER}`, - [`i18n-${UI_FRAMEWORK}`]: - UI_FRAMEWORK === "no" ? "i18n" : `i18n-${UI_FRAMEWORK}`, }, }; diff --git a/.github/workflows/build-template.js b/.github/workflows/build-template.js index 0f5159d19..9911de2a1 100644 --- a/.github/workflows/build-template.js +++ b/.github/workflows/build-template.js @@ -29,6 +29,12 @@ const buildTemplate = async () => { hasura: ["keycloak", "custom"], }; + const uiFrameworkToExampleMap = { + antd: "antd-example", + mui: "mui-example", + no: "headless-example", + }; + let AUTH_PROVIDER = dataProviderMap[DATA_PROVIDER]; if (Array.isArray(AUTH_PROVIDER)) { @@ -55,11 +61,9 @@ const buildTemplate = async () => { icon: "refine.svg", "data-provider": `data-provider-${DATA_PROVIDER}`, "ui-framework": UI_FRAMEWORK, - [UI_FRAMEWORK === "no" ? "inferencer-headless" : "inferencer"]: - UI_FRAMEWORK === "no" ? "inferencer-headless" : "inferencer", + [uiFrameworkToExampleMap[UI_FRAMEWORK]]: + uiFrameworkToExampleMap[UI_FRAMEWORK], "auth-provider": `auth-provider-${AUTH_PROVIDER}`, - [`i18n-${UI_FRAMEWORK}`]: - UI_FRAMEWORK === "no" ? "i18n" : `i18n-${UI_FRAMEWORK}`, }, }; diff --git a/.github/workflows/test-local.yaml b/.github/workflows/test-local.yaml index 95f220e7a..cfef95cc3 100644 --- a/.github/workflows/test-local.yaml +++ b/.github/workflows/test-local.yaml @@ -21,8 +21,9 @@ jobs: airtable, supabase, appwrite, + hasura, ] - ui_framework: [antd, chakra, mantine, mui, no] + ui_framework: [antd, mui, no] steps: - name: Checkout uses: actions/checkout@v3 @@ -79,7 +80,7 @@ jobs: appwrite, hasura, ] - ui_framework: [antd, chakra, mantine, mui, no] + ui_framework: [antd, mui, no] steps: - name: Checkout uses: actions/checkout@v3 @@ -137,7 +138,7 @@ jobs: appwrite, hasura, ] - ui_framework: [antd, chakra, mantine, mui, no] + ui_framework: [antd, mui, no] steps: - name: Checkout uses: actions/checkout@v3 diff --git a/.github/workflows/test-remote.yaml b/.github/workflows/test-remote.yaml index 30c26d4e5..20a9aa40c 100644 --- a/.github/workflows/test-remote.yaml +++ b/.github/workflows/test-remote.yaml @@ -23,7 +23,7 @@ jobs: appwrite, hasura, ] - ui_framework: [antd, chakra, mantine, mui, no] + ui_framework: [antd, mui, no] steps: - name: Checkout uses: actions/checkout@v3 @@ -81,7 +81,7 @@ jobs: appwrite, hasura, ] - ui_framework: [antd, chakra, mantine, mui, no] + ui_framework: [antd, mui, no] steps: - name: Checkout uses: actions/checkout@v3 @@ -140,7 +140,7 @@ jobs: appwrite, hasura, ] - ui_framework: [antd, chakra, mantine, mui, no] + ui_framework: [antd, mui, no] steps: - name: Checkout uses: actions/checkout@v3 diff --git a/cypress/e2e/build-test.cy.js b/cypress/e2e/build-test.cy.js index 0d5df5e4a..c42b2cb6e 100644 --- a/cypress/e2e/build-test.cy.js +++ b/cypress/e2e/build-test.cy.js @@ -77,7 +77,9 @@ describe("build test", () => { cy.wait(1000); - cy.visit("http://localhost:3000/i-dont-exist").wait(1000); + cy.visit("http://localhost:3000/i-dont-exist", { + failOnStatusCode: false, + }).wait(1000); cy.url().should("be.oneOf", [ "http://localhost:3000/login?to=%2Fi-dont-exist", @@ -115,9 +117,12 @@ describe("build test", () => { cy.contains("Blog Posts", { matchCase: false }).should("exist"); // document title check - // ignore remix - if (Cypress.env("FRAMEWORK") !== "remix") { - cy.title().should("eq", "Blog Posts | refine"); + // ignore remix and nextjs + if ( + Cypress.env("FRAMEWORK") !== "remix" && + Cypress.env("FRAMEWORK") !== "nextjs" + ) { + cy.title().should("eq", "Blog posts | refine"); } if (Cypress.env("UI_FRAMEWORK") !== "no") { @@ -125,30 +130,6 @@ describe("build test", () => { cy.contains("Logout").should("exist"); } - - // hide language name and name on mui custom-json-rest - if (Cypress.env("UI_FRAMEWORK") === "mui") { - if (Cypress.env("FRAMEWORK") !== "remix") { - cy.get(".MuiPaper-elevation4 > .MuiToolbar-root").contains( - "English", - ); - - cy.viewport(375, 667) - .get(".MuiPaper-elevation4 > .MuiToolbar-root") - .contains("English") - .should("have.css", "display", "none"); - } - - if (Cypress.env("DATA_PROVIDER") === "custom-json-rest") { - cy.get(".MuiPaper-elevation4 > .MuiToolbar-root").contains( - "John Doe", - ); - cy.viewport(375, 667) - .get(".MuiPaper-elevation4 > .MuiToolbar-root") - .contains("John Doe") - .should("have.css", "display", "none"); - } - } } }); }); diff --git a/package.json b/package.json index 8ead8514b..b729b5fd4 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,7 @@ "test": "echo \"Error: no test specified\" && exit 1", "lint": "ejslint ./refine-*/**/*", "prepare": "husky install", - "cypress": "cypress open --env=AUTH_PROVIDER=custom,UI_FRAMEWORK=mui,FRAMEWORK=react,DATA_PROVIDER=custom-json-rest" + "cypress": "cypress open --env=AUTH_PROVIDER=keycloak,UI_FRAMEWORK=antd,FRAMEWORK=nextjs,DATA_PROVIDER=custom-json-rest" }, "repository": { "type": "git", diff --git a/presets.js b/presets.js index 4e2621bcb..db7e097e4 100644 --- a/presets.js +++ b/presets.js @@ -8,12 +8,9 @@ module.exports = { "router-provider": "react-router-v6", "data-provider": "data-provider-custom-json-rest", "auth-provider": "none", - "antd-example-pages": "no", - "mui-example-pages": "no", - "i18n-no": "no", - "i18n-antd": "no", - "i18n-mui": "no", - inferencer: "no", + "antd-example": "no", + "mui-example": "no", + "headless-example": "no", }, }, { @@ -24,12 +21,9 @@ module.exports = { "router-provider": "react-router-v6", "data-provider": "data-provider-custom-json-rest", "auth-provider": "none", - "antd-example-pages": "no", - "mui-example-pages": "no", - "i18n-no": "no", - "i18n-antd": "no", - "i18n-mui": "no", - inferencer: "no", + "antd-example": "no", + "mui-example": "no", + "headless-example": "no", }, }, { @@ -40,50 +34,9 @@ module.exports = { "router-provider": "react-router-v6", "data-provider": "data-provider-custom-json-rest", "auth-provider": "none", - "antd-example-pages": "no", - "mui-example-pages": "no", - "i18n-no": "no", - "i18n-antd": "no", - "i18n-mui": "no", - inferencer: "no", - }, - }, - { - name: "refine-mantine", - type: "refine-vite", - answers: { - "ui-framework": "mantine", - "router-provider": "react-router-v6", - "data-provider": "data-provider-custom-json-rest", - "auth-provider": "none", - "antd-example-pages": "no", - "mui-example-pages": "no", - "mantine-example-pages": "no", - "i18n-no": "no", - "i18n-antd": "no", - "i18n-mui": "no", - "i18n-mantine": "no", - inferencer: "no", - }, - }, - { - name: "refine-chakra-ui", - type: "refine-vite", - answers: { - "ui-framework": "chakra", - "router-provider": "react-router-v6", - "data-provider": "data-provider-custom-json-rest", - "auth-provider": "none", - "antd-example-pages": "no", - "mui-example-pages": "no", - "mantine-example-pages": "no", - "chakra-example-pages": "no", - "i18n-no": "no", - "i18n-antd": "no", - "i18n-mui": "no", - "i18n-mantine": "no", - "i18n-chakra": "no", - inferencer: "no", + "antd-example": "no", + "mui-example": "no", + "headless-example": "no", }, }, { @@ -93,9 +46,9 @@ module.exports = { "ui-framework": "no", "data-provider": "data-provider-custom-json-rest", "auth-provider": "none", - "antd-example-pages": "no", - "mui-example-pages": "no", - inferencer: "no", + "antd-example": "no", + "mui-example": "no", + "headless-example": "no", }, }, { @@ -105,12 +58,9 @@ module.exports = { "ui-framework": "antd", "data-provider": "data-provider-custom-json-rest", "auth-provider": "none", - "antd-example-pages": "no", - "mui-example-pages": "no", - "i18n-no": "no", - "i18n-antd": "no", - "i18n-mui": "no", - inferencer: "no", + "antd-example": "no", + "mui-example": "no", + "headless-example": "no", }, }, { @@ -120,12 +70,9 @@ module.exports = { "ui-framework": "antd", "router-provider": "react-router-v6", "data-provider": "data-provider-supabase", - "auth-provider": "none", - "antd-example-pages": "no", - "mui-example-pages": "no", - "i18n-no": "no", - "i18n-antd": "no", - "i18n-mui": "no", + "antd-example": "no", + "mui-example": "no", + "headless-example": "no", }, }, { @@ -135,8 +82,9 @@ module.exports = { "ui-framework": "no", "router-provider": "react-router-v6", "data-provider": "data-provider-supabase", - "i18n-no": "no", - inferencer: "no", + "antd-example": "no", + "mui-example": "no", + "headless-example": "no", }, }, { @@ -146,9 +94,9 @@ module.exports = { "ui-framework": "antd", "router-provider": "react-router-v6", "data-provider": "data-provider-appwrite", - "antd-example-pages": "no", - "i18n-antd": "no", - inferencer: "no", + "antd-example": "no", + "mui-example": "no", + "headless-example": "no", }, }, ], diff --git a/refine-nextjs/plugins/_base/extend.js b/refine-nextjs/plugins/_base/extend.js index 83194d4e0..74d6e096a 100644 --- a/refine-nextjs/plugins/_base/extend.js +++ b/refine-nextjs/plugins/_base/extend.js @@ -1,24 +1,31 @@ const base = { _app: { + nextjsInner: [], + nextjsImport: [], + refineContextProps: [], isNextAuthCheck: false, isAuthProviderCheck: false, + hasRoutes: true, refineAntdImports: [], - refineMantineImports: [], refineMuiImports: [], - refineChakraImports: [], localImport: [], authPageProps: [], }, selectedTheme: "Blue", selectedTitle: undefined, selectedSvg: undefined, + isGraphQL: false, + blogPostCategoryFieldName: "category", + blogPostCategoryTableField: `"category"`, + blogPostCategoryIdFormField: `["category", "id"]`, + blogPostStatusOptions: [], + blogPostStatusDefaultValue: `"draft"`, }; module.exports = { extend(answers) { const uiFramework = answers["ui-framework"]; const dataProvider = answers["data-provider"]; - const inferencer = answers["inferencer"]; const authProvider = answers["auth-provider"]; // ## isNextAuthCheck @@ -50,8 +57,8 @@ module.exports = { defaultValues = `email: "info@refine.dev", password: "refine-supabase"`; } - // mui || chakra - if (uiFramework === "mui" || uiFramework === "chakra") { + // mui + if (uiFramework === "mui") { defaultValuePropsName = "defaultValues"; } @@ -84,7 +91,15 @@ module.exports = { `, ]; } - // ## authPageProps + + // ## hasRoutes + if ( + ["headless-example", "antd-example", "mui-example"].every( + (item) => answers[item] === "no", + ) + ) { + base._app.hasRoutes = false; + } // ## selected theme const themeFromAnswers = answers["theme"]; @@ -109,15 +124,9 @@ module.exports = { if (answers["ui-framework"] === "antd") { base._app.refineAntdImports.push("ThemedTitleV2"); } - if (answers["ui-framework"] === "mantine") { - base._app.refineMantineImports.push("ThemedTitleV2"); - } if (answers["ui-framework"] === "mui") { base._app.refineMuiImports.push("ThemedTitleV2"); } - if (answers["ui-framework"] === "chakra") { - base._app.refineChakraImports.push("ThemedTitleV2"); - } } if ( @@ -136,6 +145,99 @@ module.exports = { base._app.localImport.push(`import "@styles/global.css";`); } + // this impementation required for getting default ColorModeContextProvider's theme from cookie + if (answers["ui-framework"] !== "no") { + base._app.nextjsInner.push( + `const cookieStore = cookies();`, + `const theme = cookieStore.get("theme");`, + `const defaultMode = theme?.value === "dark" ? "dark" : "light";`, + ); + base._app.nextjsImport.push( + `import { cookies } from "next/headers";`, + ); + + // this means RefineContext is seperated from layout.tsx file to wrap with SessionProvider + // so we need to pass defaultMode to RefineContext + if (base._app.isNextAuthCheck === true) { + base._app.refineContextProps.push("defaultMode={defaultMode}"); + } + } + + // ## isGraphQL + if ( + ["data-provider-hasura", "data-provider-nestjs-query"].includes( + dataProvider, + ) + ) { + base.isGraphQL = true; + } + + // ## blogPostCategoryFieldName + if (dataProvider === "data-provider-supabase") { + base.blogPostCategoryFieldName = "categories"; + } else { + base.blogPostCategoryFieldName = "category"; + } + + // ## blogPostCategoryIdFormField + if (dataProvider === "data-provider-hasura") { + base.blogPostCategoryIdFormField = `"category_id"`; + } else if (dataProvider === "data-provider-nestjs-query") { + base.blogPostCategoryIdFormField = `"categoryId"`; + } else if (dataProvider === "data-provider-supabase") { + base.blogPostCategoryIdFormField = `"categoryId"`; + } else { + if (uiFramework === "mui" || uiFramework === "no") { + base.blogPostCategoryIdFormField = `"category.id"`; + } else { + base.blogPostCategoryIdFormField = `["category", "id"]`; + } + } + + // ## blogPostCategoryTableField + if (base.isGraphQL) { + if (uiFramework === "no") { + base.blogPostCategoryTableField = `"category.title"`; + } + if (uiFramework === "antd") { + base.blogPostCategoryTableField = `['category', 'title']`; + } + if (uiFramework === "mui") { + base.blogPostCategoryTableField = `"category"`; + } + } else { + if (dataProvider === "data-provider-supabase") { + base.blogPostCategoryTableField = `"categories"`; + } else { + base.blogPostCategoryTableField = `"category"`; + } + } + + // ## blogPostStatusOptions + if (dataProvider === "data-provider-nestjs-query") { + base.blogPostStatusOptions = JSON.stringify([ + { value: "DRAFT", label: "Draft" }, + { value: "PUBLISHED", label: "Published" }, + { value: "REJECTED", label: "Rejected" }, + ]); + } else { + base.blogPostStatusOptions = JSON.stringify([ + { value: "draft", label: "Draft" }, + { value: "published", label: "Published" }, + { value: "rejected", label: "Rejected" }, + ]); + } + if (uiFramework === "no" || uiFramework === "mui") { + base.blogPostStatusOptions = JSON.parse(base.blogPostStatusOptions); + } + + // ## blogPostStatusDefaultValue + if (dataProvider === "data-provider-nestjs-query") { + base.blogPostStatusDefaultValue = `"DRAFT"`; + } else { + base.blogPostStatusDefaultValue = `"draft"`; + } + return base; }, }; diff --git a/refine-nextjs/plugins/_base/public/images/flags/de.svg b/refine-nextjs/plugins/_base/public/images/flags/de.svg deleted file mode 100644 index 949404e5b..000000000 --- a/refine-nextjs/plugins/_base/public/images/flags/de.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/refine-nextjs/plugins/_base/public/images/flags/en.svg b/refine-nextjs/plugins/_base/public/images/flags/en.svg deleted file mode 100644 index 76b105652..000000000 --- a/refine-nextjs/plugins/_base/public/images/flags/en.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/refine-nextjs/plugins/_base/public/locales/de/common.json b/refine-nextjs/plugins/_base/public/locales/de/common.json deleted file mode 100644 index ee59c3d39..000000000 --- a/refine-nextjs/plugins/_base/public/locales/de/common.json +++ /dev/null @@ -1,204 +0,0 @@ -{ - "pages": { - "login": { - "title": "Melden Sie sich bei Ihrem Konto an", - "signin": "Einloggen", - "signup": "Anmelden", - "divider": "oder", - "fields": { - "email": "Email", - "password": "Passwort" - }, - "errors": { - "validEmail": "Ungültige E-Mail-Adresse" - }, - "buttons": { - "submit": "Anmeldung", - "forgotPassword": "Passwort vergessen?", - "noAccount": "Sie haben kein Konto?", - "rememberMe": "Erinnere dich an mich" - } - }, - "forgotPassword": { - "title": "Haben Sie Ihr Passwort vergessen?", - "fields": { - "email": "Email" - }, - "errors": { - "validEmail": "Ungültige E-Mail-Adresse" - }, - "buttons": { - "submit": "Anweisungen zum Zurücksetzen senden" - } - }, - "register": { - "title": "Registrieren Sie sich für Ihr Konto", - "fields": { - "email": "Email", - "password": "Passwort" - }, - "errors": { - "validEmail": "Ungültige E-Mail-Adresse" - }, - "buttons": { - "submit": "Registrieren", - "haveAccount": "Ein Konto haben?" - } - }, - "updatePassword": { - "title": "Kennwort aktualisieren", - "fields": { - "password": "Neues Passwort", - "confirmPassword": "Bestätige neues Passwort" - }, - "errors": { - "confirmPasswordNotMatch": "Passwörter stimmen nicht überein" - }, - "buttons": { - "submit": "Aktualisieren" - } - }, - "error": { - "info": "Sie haben vergessen, {{action}} component zu {{resource}} hinzufügen.", - "404": "Leider existiert diese Seite nicht.", - "resource404": "Haben Sie die {{resource}} resource erstellt?", - "backHome": "Zurück" - } - }, - "actions": { - "list": "Aufführen", - "create": "Erstellen", - "edit": "Bearbeiten", - "show": "Zeigen" - }, - "buttons": { - "create": "Erstellen", - "save": "Speichern", - "logout": "Abmelden", - "delete": "Löschen", - "edit": "Bearbeiten", - "cancel": "Abbrechen", - "confirm": "Sicher?", - "filter": "Filter", - "clear": "Löschen", - "refresh": "Erneuern", - "show": "Zeigen", - "undo": "Undo", - "import": "Importieren", - "clone": "Klon", - "notAccessTitle": "Sie haben keine zugriffsberechtigung" - }, - "warnWhenUnsavedChanges": "Nicht gespeicherte Änderungen werden nicht übernommen.", - "notifications": { - "success": "Erfolg", - "error": "Fehler (status code: {{statusCode}})", - "undoable": "Sie haben {{seconds}} Sekunden Zeit für Undo.", - "createSuccess": "{{resource}} erfolgreich erstellt.", - "createError": "Fehler beim Erstellen {{resource}} (status code: {{statusCode}})", - "deleteSuccess": "{{resource}} erfolgreich gelöscht.", - "deleteError": "Fehler beim Löschen {{resource}} (status code: {{statusCode}})", - "editSuccess": "{{resource}} erfolgreich bearbeitet.", - "editError": "Fehler beim Bearbeiten {{resource}} (status code: {{statusCode}})", - "importProgress": "{{processed}}/{{total}} importiert" - }, - "loading": "Wird geladen", - "tags": { - "clone": "Klon" - }, - "dashboard": { - "title": "Dashboard" - }, - <%_ if (answers["data-provider"] === 'data-provider-strapi-v4') { _%> - "blog-posts": { - "blog-posts": "Blogbeiträge", - <%_ } else { _%> - "blog_posts": { - "blog_posts": "Blogbeiträge", - <%_ } _%> - "fields": { - "id": "Id", - "title": "Titel", - "content": "Inhalt", - "status": "Status", - <%_ if (answers["data-provider"] === "data-provider-appwrite" || answers["data-provider"] === "data-provider-supabase" || answers["data-provider"] === "data-provider-hasura") { _%> - "created_at": "Erstellt am", - <%_ } else { _%> - "createdAt": "Erstellt am", - <%_ } _%> - <%_ if (answers["data-provider"] === "data-provider-appwrite" || answers["data-provider"] === "data-provider-nestjsx-crud") { _%> - "updatedAt": "Aktualisiert am", - <%_ } _%> - <%_ if (answers["data-provider"] === "data-provider-supabase" || answers["data-provider"] === "data-provider-appwrite") { _%> - "categoryId": "Kategorien" - <%_ } else if (answers["data-provider"] === "data-provider-hasura") { _%> - "category_id": "Kategorien", - "category": "Kategorien" - <%_ } else { _%> - "category": "Kategorien" - <%_ } _%> - }, - "titles": { - "create": "Erstellen", - "edit": "Bearbeiten", - "list": "Einträge", - "show": "Eintrag zeigen" - } - }, - "categories": { - "categories": "Kategorien", - "fields": { - "id": "Id", - "title": "Titel", - <%_ if (answers["data-provider"] === "data-provider-airtable") { _%> - "Posts": "Einträge", - <%_ } _%> - <%_ if (answers["data-provider"] === "data-provider-appwrite" || answers["data-provider"] === "data-provider-nestjsx-crud") { _%> - "updatedAt": "Aktualisiert am", - <%_ } _%> - <%_ if (answers["data-provider"] === "data-provider-appwrite" || answers["data-provider"] === "data-provider-supabase" || answers["data-provider"] === "data-provider-hasura") { _%> - "created_at": "Erstellt am" - <%_ } else { _%> - "createdAt": "Erstellt am" - <%_ } _%> - }, - "titles": { - "create": "Erstellen", - "edit": "Bearbeiten", - "list": "Einträge", - "show": "Eintrag zeigen" - } - }, - "documentTitle": { - "default": "refine", - "suffix": " | refine", - <%_ if (answers["data-provider"] === 'data-provider-strapi-v4') { _%> - "blog-posts": { - <%_ } else { _%> - "blog_posts": { - <%_ } _%> - "list": "Blogbeiträge | refine", - "show": "#{{id}} Show Blogeintrag | refine", - "edit": "#{{id}} Edit Blogeintrag | refine", - "create": "Create new Blogeintrag | refine", - "clone": "#{{id}} Clone Blogeintrag | refine" - }, - "categories": { - "list": "Kategorien | refine", - "show": "#{{id}} Zeigen Kategorien | refine", - "edit": "#{{id}} Bearbeiten Kategorien | refine", - "create": "Neue Kategorie Erstellen | refine", - "clone": "#{{id}} Klon Kategorie | refine" - } - }, - "table": { - "actions": "Aktionen" - <%_ if (answers["ui-framework"] === "no") { _%> - }, - "pagination": { - "go": "Gehen Sie zur Seite", - "show": "Zeigen" - } - <%_ } else { _%> - } - <%_ } _%> -} diff --git a/refine-nextjs/plugins/_base/public/locales/en/common.json b/refine-nextjs/plugins/_base/public/locales/en/common.json deleted file mode 100644 index 744a4a6b2..000000000 --- a/refine-nextjs/plugins/_base/public/locales/en/common.json +++ /dev/null @@ -1,205 +0,0 @@ -{ - "pages": { - "login": { - "title": "Sign in to your account", - "signin": "Sign in", - "signup": "Sign up", - "divider": "or", - "fields": { - "email": "Email", - "password": "Password" - }, - "errors": { - "validEmail": "Invalid email address" - }, - "buttons": { - "submit": "Login", - "forgotPassword": "Forgot password?", - "noAccount": "Don’t have an account?", - "rememberMe": "Remember me" - } - }, - "forgotPassword": { - "title": "Forgot your password?", - "fields": { - "email": "Email" - }, - "errors": { - "validEmail": "Invalid email address" - }, - "buttons": { - "submit": "Send reset instructions" - } - }, - "register": { - "title": "Sign up for your account", - "fields": { - "email": "Email", - "password": "Password" - }, - "errors": { - "validEmail": "Invalid email address" - }, - "buttons": { - "submit": "Register", - "haveAccount": "Have an account?" - } - }, - "updatePassword": { - "title": "Update password", - "fields": { - "password": "New Password", - "confirmPassword": "Confirm new password" - }, - "errors": { - "confirmPasswordNotMatch": "Passwords do not match" - }, - "buttons": { - "submit": "Update" - } - }, - "error": { - "info": "You may have forgotten to add the {{action}} component to {{resource}} resource.", - "404": "Sorry, the page you visited does not exist.", - "resource404": "Are you sure you have created the {{resource}} resource.", - "backHome": "Back Home" - } - }, - "actions": { - "list": "List", - "create": "Create", - "edit": "Edit", - "show": "Show" - }, - "buttons": { - "create": "Create", - "save": "Save", - "logout": "Logout", - "delete": "Delete", - "edit": "Edit", - "cancel": "Cancel", - "confirm": "Are you sure?", - "filter": "Filter", - "clear": "Clear", - "refresh": "Refresh", - "show": "Show", - "undo": "Undo", - "import": "Import", - "clone": "Clone", - "notAccessTitle": "You don't have permission to access" - }, - "warnWhenUnsavedChanges": "Are you sure you want to leave? You have unsaved changes.", - "notifications": { - "success": "Successful", - "error": "Error (status code: {{statusCode}})", - "undoable": "You have {{seconds}} seconds to undo", - "createSuccess": "Successfully created {{resource}}", - "createError": "There was an error creating {{resource}} (status code: {{statusCode}})", - "deleteSuccess": "Successfully deleted {{resource}}", - "deleteError": "Error when deleting {{resource}} (status code: {{statusCode}})", - "editSuccess": "Successfully edited {{resource}}", - "editError": "Error when editing {{resource}} (status code: {{statusCode}})", - "importProgress": "Importing: {{processed}}/{{total}}" - }, - "loading": "Loading", - "tags": { - "clone": "Clone" - }, - "dashboard": { - "title": "Dashboard" - }, - <%_ if (answers["data-provider"] === 'data-provider-strapi-v4') { _%> - "blog-posts": { - "blog-posts": "Blog Posts", - <%_ } else { _%> - "blog_posts": { - "blog_posts": "Blog Posts", - <%_ } _%> - "fields": { - "id": "Id", - "title": "Title", - "content": "Content", - "status": "Status", - <%_ if (answers["data-provider"] === "data-provider-appwrite" || answers["data-provider"] === "data-provider-supabase" || answers["data-provider"] === "data-provider-hasura") { _%> - "created_at": "Created At", - <%_ } else { _%> - "createdAt": "Created At", - <%_ } _%> - <%_ if (answers["data-provider"] === "data-provider-appwrite" || answers["data-provider"] === "data-provider-nestjsx-crud") { _%> - "updatedAt": "Updated At", - <%_ } _%> - <%_ if (answers["data-provider"] === "data-provider-supabase" || answers["data-provider"] === "data-provider-appwrite") { _%> - "categoryId": "Category" - <%_ } else if (answers["data-provider"] === "data-provider-hasura") { _%> - "category_id": "Category", - "category": "Category" - <%_ } else { _%> - "category": "Category" - <%_ } _%> - }, - "titles": { - "create": "Create Blog Post", - "edit": "Edit Blog Post", - "list": "Blog Posts", - "show": "Show Blog Post" - } - }, - "categories": { - "categories": "Categories", - "fields": { - "id": "Id", - "title": "Title", - <%_ if (answers["data-provider"] === "data-provider-airtable") { _%> - "Posts": "Posts", - <%_ } _%> - <%_ if (answers["data-provider"] === "data-provider-appwrite" || answers["data-provider"] === "data-provider-nestjsx-crud") { _%> - "updatedAt": "Updated At", - <%_ } _%> - <%_ if (answers["data-provider"] === "data-provider-appwrite" || answers["data-provider"] === "data-provider-supabase" || answers["data-provider"] === "data-provider-hasura") { _%> - "created_at": "Created At" - <%_ } else { _%> - "createdAt": "Created At" - <%_ } _%> - }, - "titles": { - "create": "Create Category", - "edit": "Edit Category", - "list": "Categories", - "show": "Show Category" - } - }, - "documentTitle": { - "default": "refine", - "suffix": " | refine", - <%_ if (answers["data-provider"] === 'data-provider-strapi-v4') { _%> - "blog-posts": { - <%_ } else { _%> - "blog_posts": { - <%_ } _%> - "list": "Blog Posts | refine", - "show": "#{{id}} Show Blog Post | refine", - "edit": "#{{id}} Edit Blog Post | refine", - "create": "Create new Blog Post | refine", - "clone": "#{{id}} Clone Blog Post | refine" - }, - "categories": { - "list": "Categories | refine", - "show": "#{{id}} Show Category | refine", - "edit": "#{{id}} Edit Category | refine", - "create": "Create new Category | refine", - "clone": "#{{id}} Clone Category | refine" - } - - }, - "table": { - "actions": "Actions" - <%_ if (answers["ui-framework"] === "no") { _%> - }, - "pagination": { - "go": "Go to Page", - "show": "Show" - } - <%_ } else { _%> - } - <%_ } _%> -} diff --git a/refine-nextjs/plugins/_base/src/components/app-icon/index.tsx b/refine-nextjs/plugins/_base/src/components/app-icon/index.tsx index 7c6d8b375..619b27144 100644 --- a/refine-nextjs/plugins/_base/src/components/app-icon/index.tsx +++ b/refine-nextjs/plugins/_base/src/components/app-icon/index.tsx @@ -1,3 +1,5 @@ +'use client' + import React from "react"; export const AppIcon: React.FC = () => { diff --git a/refine-nextjs/plugins/_base/src/components/auth-page/index.tsx b/refine-nextjs/plugins/_base/src/components/auth-page/index.tsx new file mode 100644 index 000000000..7357f33e8 --- /dev/null +++ b/refine-nextjs/plugins/_base/src/components/auth-page/index.tsx @@ -0,0 +1,49 @@ +"use client"; +<%_ if (answers["ui-framework"] === 'antd') { _%> + import { + AuthPage as AuthPageBase, + <%_ if (selectedSvg || selectedTitle) { _%> + ThemedTitleV2, + <%_ } _%> + } from "@refinedev/antd"; + <%_ } _%> + <%_ if (answers["ui-framework"] === 'mui') { _%> + import { + AuthPage as AuthPageBase, + <%_ if (selectedSvg || selectedTitle) { _%> + ThemedTitleV2, + <%_ } _%> + } from "@refinedev/mui"; + <%_ } _%> + <%_ if (answers[`ui-framework`] === "no") { _%> + import { AuthPage as AuthPageBase } from "@refinedev/core"; + <%_ } _%> + import type { AuthPageProps } from '@refinedev/core' + <%_ if (selectedSvg && answers["ui-framework"] !== "no") { _%> + import { AppIcon } from '@components/app-icon' + <%_ } _%> + + + export const AuthPage = (props: AuthPageProps) => { + + return ( + + <%_ if ((selectedSvg || selectedTitle) && answers["ui-framework"] !== "no") { _%> + title={( + + text="<%= selectedTitle %>" + <%_ } _%> + <%_ if (selectedSvg) { _%> + icon={} + <%_ } _%> + /> + )} + <%_ } _%> + /> + ); + } + \ No newline at end of file diff --git a/refine-nextjs/plugins/_base/src/components/breadcrumb/index.tsx b/refine-nextjs/plugins/_base/src/components/breadcrumb/index.tsx index 701555f50..129f1ae2e 100644 --- a/refine-nextjs/plugins/_base/src/components/breadcrumb/index.tsx +++ b/refine-nextjs/plugins/_base/src/components/breadcrumb/index.tsx @@ -1,3 +1,5 @@ +"use client"; + import { useBreadcrumb } from "@refinedev/core"; import Link from "next/link"; diff --git a/refine-nextjs/plugins/_base/src/components/layout/index.tsx b/refine-nextjs/plugins/_base/src/components/layout/index.tsx index affd84296..05ad61243 100644 --- a/refine-nextjs/plugins/_base/src/components/layout/index.tsx +++ b/refine-nextjs/plugins/_base/src/components/layout/index.tsx @@ -1,5 +1,6 @@ -import { PropsWithChildren } from "react"; +"use client"; +import { PropsWithChildren } from "react"; import { Breadcrumb } from "../breadcrumb"; import { Menu } from "../menu"; diff --git a/refine-nextjs/plugins/_base/src/components/menu/index.tsx b/refine-nextjs/plugins/_base/src/components/menu/index.tsx index 47209d649..746f214a6 100644 --- a/refine-nextjs/plugins/_base/src/components/menu/index.tsx +++ b/refine-nextjs/plugins/_base/src/components/menu/index.tsx @@ -1,3 +1,5 @@ +'use client' + import { <%_ if (_app.isAuthProviderCheck || _app.isNextAuthCheck) { _%> useLogout, diff --git a/refine-nextjs/plugins/_base/src/providers/devtools/index.tsx b/refine-nextjs/plugins/_base/src/providers/devtools/index.tsx new file mode 100644 index 000000000..de65a0519 --- /dev/null +++ b/refine-nextjs/plugins/_base/src/providers/devtools/index.tsx @@ -0,0 +1,13 @@ +'use client' + +import React from 'react' +import { DevtoolsPanel, DevtoolsProvider as DevtoolsProviderBase } from '@refinedev/devtools' + +export const DevtoolsProvider = (props: React.PropsWithChildren) => { + return ( + + {props.children} + + + ) +} diff --git a/refine-nextjs/plugins/antd-example/src/app/blog-posts/create/page.tsx b/refine-nextjs/plugins/antd-example/src/app/blog-posts/create/page.tsx new file mode 100644 index 000000000..79dd8da07 --- /dev/null +++ b/refine-nextjs/plugins/antd-example/src/app/blog-posts/create/page.tsx @@ -0,0 +1,98 @@ +"use client"; + +import { Create, useForm, useSelect } from "@refinedev/antd"; +import { IResourceComponentsProps } from "@refinedev/core"; +import { Form, Input, Select } from "antd"; +import React from "react"; +<%_ if (answers["data-provider"] === "data-provider-hasura") { _%> + import { BLOG_POSTS_QUERY, BLOG_POSTS_CATEGORIES_SELECT_QUERY } from "@queries/blog-posts"; +<%_ } _%> +<%_ if (answers["data-provider"] === "data-provider-nestjs-query") { _%> + import { POST_CREATE_MUTATION, CATEGORIES_SELECT_QUERY } from "@queries/blog-posts"; +<%_ } _%> + +export default function BlogPostCreate() { + const { formProps, saveButtonProps } = useForm({ +<%_ if (answers["data-provider"] === "data-provider-hasura") { _%> + meta: { + fields: BLOG_POSTS_QUERY, + }, +<%_ } _%> +<%_ if (answers["data-provider"] === "data-provider-nestjs-query") { _%> + meta: { + gqlMutation: POST_CREATE_MUTATION, + }, +<%_ } _%> + }); + + const { selectProps: categorySelectProps } = useSelect({ + resource: "categories", +<%_ if (answers["data-provider"] === "data-provider-hasura") { _%> + meta: { + fields: BLOG_POSTS_CATEGORIES_SELECT_QUERY, + }, +<%_ } _%> +<%_ if (answers["data-provider"] === "data-provider-nestjs-query") { _%> + meta: { + gqlQuery: CATEGORIES_SELECT_QUERY, + }, +<%_ } _%> + }); + + return ( + +
+ + + + + + + } + rules={[ + { + required: true, + }, + ]} + > + } + options={<%- blogPostStatusOptions %>} + style={{ width: 120 }} + /> + +
+
+ ); +}; + diff --git a/refine-nextjs/plugins/antd-example/src/app/blog-posts/edit/[id]/page.tsx b/refine-nextjs/plugins/antd-example/src/app/blog-posts/edit/[id]/page.tsx new file mode 100644 index 000000000..6767a5993 --- /dev/null +++ b/refine-nextjs/plugins/antd-example/src/app/blog-posts/edit/[id]/page.tsx @@ -0,0 +1,111 @@ +"use client"; + +import { Edit, useForm, useSelect } from "@refinedev/antd"; +import { IResourceComponentsProps } from "@refinedev/core"; +import { Form, Input, Select } from "antd"; +import React from "react"; +<%_ if (answers["data-provider"] === "data-provider-hasura") { _%> + import { BLOG_POSTS_QUERY, BLOG_POSTS_CATEGORIES_SELECT_QUERY } from "@queries/blog-posts"; +<%_ } _%> +<%_ if (answers["data-provider"] === "data-provider-nestjs-query") { _%> + import { POST_EDIT_MUTATION, CATEGORIES_SELECT_QUERY } from "@queries/blog-posts"; +<%_ } _%> + +export default function BlogPostEdit() { + const { formProps, saveButtonProps, queryResult } = useForm({ +<%_ if (answers["data-provider"] === "data-provider-hasura") { _%> + meta: { + fields: BLOG_POSTS_QUERY, + }, +<%_ } _%> +<%_ if (answers["data-provider"] === "data-provider-strapi-v4") { _%> + meta: { + populate: ['category'], + }, +<%_ } _%> +<%_ if (answers["data-provider"] === "data-provider-nestjs-query") { _%> + meta: { + gqlMutation: POST_EDIT_MUTATION, + }, +<%_ } _%> +<%_ if (answers["data-provider"] === "data-provider-supabase") { _%> + meta: { + select: '*, categories(id,title)', + }, +<%_ } _%> + }); + + const blogPostsData = queryResult?.data?.data; + + const { selectProps: categorySelectProps } = useSelect({ + resource: "categories", + defaultValue: blogPostsData?.<%- blogPostCategoryFieldName %>?.id, +<%_ if (answers["data-provider"] === "data-provider-hasura") { _%> + meta: { + fields: BLOG_POSTS_CATEGORIES_SELECT_QUERY, + }, +<%_ } _%> +<%_ if (answers["data-provider"] === "data-provider-nestjs-query") { _%> + meta: { + gqlQuery: CATEGORIES_SELECT_QUERY, + }, +<%_ } _%> + }); + + return ( + +
+ + + + + + + } + initialValue={formProps?.initialValues?.<%- blogPostCategoryFieldName %>?.id} + rules={[ + { + required: true, + }, + ]} + > + } + options={<%- blogPostStatusOptions %>} + style={{ width: 120 }} + /> + +
+
+ ); +}; diff --git a/refine-nextjs/plugins/antd-example/src/app/blog-posts/layout.tsx b/refine-nextjs/plugins/antd-example/src/app/blog-posts/layout.tsx new file mode 100644 index 000000000..8cb7254b0 --- /dev/null +++ b/refine-nextjs/plugins/antd-example/src/app/blog-posts/layout.tsx @@ -0,0 +1,53 @@ +import React from "react"; +import { ThemedLayout } from "@components/themed-layout"; +<%_ if (_app.isNextAuthCheck) { _%> + import authOptions from "@app/api/auth/[...nextauth]/options"; + import { getServerSession } from 'next-auth/next' + import { redirect } from 'next/navigation' +<%_ } _%> +<%_ if (_app.isAuthProviderCheck) { _%> + import { authProviderServer } from '@providers/auth-provider' + import { redirect } from 'next/navigation' +<%_ } _%> + +export default async function Layout({ children }: React.PropsWithChildren) { + <%_ if (_app.isNextAuthCheck || _app.isAuthProviderCheck) { _%> + const data = await getData() + + <%_ if (_app.isAuthProviderCheck) { _%> + if (!data.authenticated) { + return redirect(data?.redirectTo || '/login') + } + <%_ } _%> + + <%_ if (_app.isNextAuthCheck) { _%> + if (!data.session?.user) { + return redirect('/login') + } + <%_ } _%> + + <%_ } _%> + + return {children}; +} + + +<%_ if (_app.isNextAuthCheck) { _%> + async function getData() { + const session = await getServerSession(authOptions) + return { + session, + } + } +<%_ } _%> + +<%_ if (_app.isAuthProviderCheck) { _%> + async function getData() { + const { authenticated, redirectTo } = await authProviderServer.check() + + return { + authenticated, + redirectTo, + } + } +<%_ } _%> \ No newline at end of file diff --git a/refine-nextjs/plugins/antd-example/src/app/blog-posts/page.tsx b/refine-nextjs/plugins/antd-example/src/app/blog-posts/page.tsx new file mode 100644 index 000000000..ac8e64835 --- /dev/null +++ b/refine-nextjs/plugins/antd-example/src/app/blog-posts/page.tsx @@ -0,0 +1,122 @@ +"use client"; + +import { + DateField, + DeleteButton, + EditButton, + List, + MarkdownField, + ShowButton, + useTable, +} from "@refinedev/antd"; +import { BaseRecord, IResourceComponentsProps, useMany } from "@refinedev/core"; +import { Space, Table } from "antd"; +import React from "react"; + +<%_ if (answers["data-provider"] === "data-provider-hasura") { _%> +import { BLOG_POSTS_QUERY } from "@queries/blog-posts"; +<%_ } _%> +<%_ if (answers["data-provider"] === "data-provider-nestjs-query") { _%> + import { POSTS_LIST_QUERY } from "@queries/blog-posts"; +<%_ } _%> + +export default function BlogPostList() { + const { tableProps } = useTable({ + syncWithLocation: true, +<%_ if (answers["data-provider"] === "data-provider-hasura") { _%> + meta: { + fields: BLOG_POSTS_QUERY, + }, +<%_ } _%> +<%_ if (answers["data-provider"] === "data-provider-strapi-v4") { _%> + meta: { + populate: ['category'], + }, +<%_ } _%> +<%_ if (answers["data-provider"] === "data-provider-nestjs-query") { _%> + meta: { + gqlQuery: POSTS_LIST_QUERY, + }, +<%_ } _%> +<%_ if (answers["data-provider"] === "data-provider-supabase") { _%> + meta: { + select: '*, categories(id,title)', + }, +<%_ } _%> + }); + +<%_ if (!isGraphQL) { _%> + const { data: categoryData, isLoading: categoryIsLoading } = useMany({ + resource: "categories", + ids: tableProps?.dataSource?.map((item) => item?.<%- blogPostCategoryFieldName %>?.id).filter(Boolean) ?? [], + queryOptions: { + enabled: !!tableProps?.dataSource, + }, + }); +<%_ } _%> + + return ( + + + + + { + if (!value) return '-' + return + }} + /> + } + title={"Category"} + <%_ if (!isGraphQL) { _%> + render={(value) => + categoryIsLoading ? ( + <>Loading... + ) : ( + categoryData?.data?.find( + (item) => item.id === value?.id, + )?.title + ) + } + <%_ } _%> + /> + + + dataIndex={["created_at"]} +<%_ } else { _%> + dataIndex={["createdAt"]} +<%_ } _%> + title={"Created at"} + render={(value: any) => } + /> + ( + + + + + + )} + /> +
+
+ ); +}; diff --git a/refine-nextjs/plugins/antd-example/src/app/blog-posts/show/[id]/page.tsx b/refine-nextjs/plugins/antd-example/src/app/blog-posts/show/[id]/page.tsx new file mode 100644 index 000000000..f6f037b94 --- /dev/null +++ b/refine-nextjs/plugins/antd-example/src/app/blog-posts/show/[id]/page.tsx @@ -0,0 +1,83 @@ +"use client"; + +import { + DateField, + MarkdownField, + NumberField, + Show, + TextField, +} from "@refinedev/antd"; +import { IResourceComponentsProps, useOne, useShow } from "@refinedev/core"; +import { Typography } from "antd"; +import React from "react"; +<%_ if (answers["data-provider"] === "data-provider-hasura") { _%> + import { BLOG_POSTS_QUERY } from "@queries/blog-posts"; +<%_ } _%> +<%_ if (answers["data-provider"] === "data-provider-nestjs-query") { _%> + import { POST_SHOW_QUERY } from "@queries/blog-posts"; +<%_ } _%> + +const { Title } = Typography; + +export default function BlogPostShow() { + const { queryResult } = useShow({ +<%_ if (answers["data-provider"] === "data-provider-hasura") { _%> + meta: { + fields: BLOG_POSTS_QUERY, + }, +<%_ } _%> +<%_ if (answers["data-provider"] === "data-provider-strapi-v4") { _%> + meta: { + populate: ['category'], + }, +<%_ } _%> +<%_ if (answers["data-provider"] === "data-provider-nestjs-query") { _%> + meta: { + gqlQuery: POST_SHOW_QUERY, + }, +<%_ } _%> +<%_ if (answers["data-provider"] === "data-provider-supabase") { _%> + meta: { + select: '*, categories(id,title)', + }, +<%_ } _%> + }); + const { data, isLoading } = queryResult; + + const record = data?.data; + +<%_ if (!isGraphQL) { _%> + const { data: categoryData, isLoading: categoryIsLoading } = useOne({ + resource: "categories", + id: record?.<%- blogPostCategoryFieldName %>?.id || "", + queryOptions: { + enabled: !!record, + }, + }); +<%_ } _%> + + return ( + + {"ID"} + + {"Title"} + + {"Content"} + + {"Category"} +<%_ if (isGraphQL) { _%> + ?.title} /> +<%_ } else { _%> + Loading... + ) : ( + <>{categoryData?.data?.title} + )} /> +<%_ } _%> + {"Status"} + + {"CreatedAt"} + + + ); +}; diff --git a/refine-nextjs/plugins/antd-example/src/app/categories/create/page.tsx b/refine-nextjs/plugins/antd-example/src/app/categories/create/page.tsx new file mode 100644 index 000000000..5e3c5cf0a --- /dev/null +++ b/refine-nextjs/plugins/antd-example/src/app/categories/create/page.tsx @@ -0,0 +1,46 @@ +"use client"; + +import { Create, useForm } from "@refinedev/antd"; +import { IResourceComponentsProps } from "@refinedev/core"; +import { Form, Input } from "antd"; +import React from "react"; +<%_ if (answers["data-provider"] === "data-provider-hasura") { _%> + import { CATEGORIES_QUERY } from '@queries/categories' +<%_ } _%> +<%_ if (answers["data-provider"] === "data-provider-nestjs-query") { _%> + import { CATEGORY_CREATE_MUTATION } from '@queries/categories' +<%_ } _%> + + +export default function CategoryCreate() { + const { formProps, saveButtonProps } = useForm({ +<%_ if (answers["data-provider"] === "data-provider-hasura") { _%> + meta: { + fields: CATEGORIES_QUERY, + }, +<%_ } _%> +<%_ if (answers["data-provider"] === "data-provider-nestjs-query") { _%> + meta: { + gqlMutation: CATEGORY_CREATE_MUTATION, + }, +<%_ } _%> + }); + + return ( + +
+ + + +
+
+ ); +}; diff --git a/refine-nextjs/plugins/antd-example/src/app/categories/edit/[id]/page.tsx b/refine-nextjs/plugins/antd-example/src/app/categories/edit/[id]/page.tsx new file mode 100644 index 000000000..3658998cc --- /dev/null +++ b/refine-nextjs/plugins/antd-example/src/app/categories/edit/[id]/page.tsx @@ -0,0 +1,46 @@ +"use client"; + +import { Edit, useForm } from "@refinedev/antd"; +import { IResourceComponentsProps } from "@refinedev/core"; +import { Form, Input } from "antd"; +import React from "react"; +<%_ if (answers["data-provider"] === "data-provider-hasura") { _%> + import { CATEGORIES_QUERY } from '@queries/categories' +<%_ } _%> +<%_ if (answers["data-provider"] === "data-provider-nestjs-query") { _%> + import { CATEGORY_EDIT_MUTATION } from '@queries/categories' +<%_ } _%> + + +export default function CategoryEdit() { + const { formProps, saveButtonProps } = useForm({ +<%_ if (answers["data-provider"] === "data-provider-hasura") { _%> + meta: { + fields: CATEGORIES_QUERY, + }, +<%_ } _%> +<%_ if (answers["data-provider"] === "data-provider-nestjs-query") { _%> + meta: { + gqlMutation: CATEGORY_EDIT_MUTATION, + }, +<%_ } _%> + }); + + return ( + +
+ + + +
+
+ ); +}; diff --git a/refine-nextjs/plugins/antd-example/src/app/categories/layout.tsx b/refine-nextjs/plugins/antd-example/src/app/categories/layout.tsx new file mode 100644 index 000000000..8cb7254b0 --- /dev/null +++ b/refine-nextjs/plugins/antd-example/src/app/categories/layout.tsx @@ -0,0 +1,53 @@ +import React from "react"; +import { ThemedLayout } from "@components/themed-layout"; +<%_ if (_app.isNextAuthCheck) { _%> + import authOptions from "@app/api/auth/[...nextauth]/options"; + import { getServerSession } from 'next-auth/next' + import { redirect } from 'next/navigation' +<%_ } _%> +<%_ if (_app.isAuthProviderCheck) { _%> + import { authProviderServer } from '@providers/auth-provider' + import { redirect } from 'next/navigation' +<%_ } _%> + +export default async function Layout({ children }: React.PropsWithChildren) { + <%_ if (_app.isNextAuthCheck || _app.isAuthProviderCheck) { _%> + const data = await getData() + + <%_ if (_app.isAuthProviderCheck) { _%> + if (!data.authenticated) { + return redirect(data?.redirectTo || '/login') + } + <%_ } _%> + + <%_ if (_app.isNextAuthCheck) { _%> + if (!data.session?.user) { + return redirect('/login') + } + <%_ } _%> + + <%_ } _%> + + return {children}; +} + + +<%_ if (_app.isNextAuthCheck) { _%> + async function getData() { + const session = await getServerSession(authOptions) + return { + session, + } + } +<%_ } _%> + +<%_ if (_app.isAuthProviderCheck) { _%> + async function getData() { + const { authenticated, redirectTo } = await authProviderServer.check() + + return { + authenticated, + redirectTo, + } + } +<%_ } _%> \ No newline at end of file diff --git a/refine-nextjs/plugins/antd-example/src/app/categories/page.tsx b/refine-nextjs/plugins/antd-example/src/app/categories/page.tsx new file mode 100644 index 000000000..503850d05 --- /dev/null +++ b/refine-nextjs/plugins/antd-example/src/app/categories/page.tsx @@ -0,0 +1,68 @@ +"use client"; + +import { + DeleteButton, + EditButton, + List, + ShowButton, + useTable, +} from "@refinedev/antd"; +import { BaseRecord, IResourceComponentsProps } from "@refinedev/core"; +import { Space, Table } from "antd"; +import React from "react"; +<%_ if (answers["data-provider"] === "data-provider-hasura") { _%> + import { CATEGORIES_QUERY } from '@queries/categories' +<%_ } _%> +<%_ if (answers["data-provider"] === "data-provider-nestjs-query") { _%> + import { CATEGORIES_LIST_QUERY } from '@queries/categories' +<%_ } _%> + + +export default function CategoryList() { + const { tableProps } = useTable({ + syncWithLocation: true, +<%_ if (answers["data-provider"] === "data-provider-hasura") { _%> + meta: { + fields: CATEGORIES_QUERY, + }, +<%_ } _%> +<%_ if (answers["data-provider"] === "data-provider-nestjs-query") { _%> + meta: { + gqlQuery: CATEGORIES_LIST_QUERY, + }, +<%_ } _%> + }); + + return ( + + + + + ( + + + + + + )} + /> +
+
+ ); +}; + diff --git a/refine-nextjs/plugins/antd-example/src/app/categories/show/[id]/page.tsx b/refine-nextjs/plugins/antd-example/src/app/categories/show/[id]/page.tsx new file mode 100644 index 000000000..ee4982db8 --- /dev/null +++ b/refine-nextjs/plugins/antd-example/src/app/categories/show/[id]/page.tsx @@ -0,0 +1,44 @@ +"use client"; + +import { NumberField, Show, TextField } from "@refinedev/antd"; +import { IResourceComponentsProps, useShow } from "@refinedev/core"; +import { Typography } from "antd"; +import React from "react"; +<%_ if (answers["data-provider"] === "data-provider-hasura") { _%> + import { CATEGORIES_QUERY } from '@queries/categories' +<%_ } _%> +<%_ if (answers["data-provider"] === "data-provider-nestjs-query") { _%> + import { CATEGORY_SHOW_QUERY } from '@queries/categories' +<%_ } _%> + + +const { Title } = Typography; + +export default function CategoryShow() { + const { queryResult } = useShow({ +<%_ if (answers["data-provider"] === "data-provider-hasura") { _%> + meta: { + fields: CATEGORIES_QUERY, + }, +<%_ } _%> +<%_ if (answers["data-provider"] === "data-provider-nestjs-query") { _%> + meta: { + gqlQuery: CATEGORY_SHOW_QUERY, + }, +<%_ } _%> + }); + const { data, isLoading } = queryResult; + + const record = data?.data; + + return ( + + {"ID"} + + {"Title"} + + + ); +}; + + diff --git a/refine-nextjs/plugins/antd-example/src/components/themed-layout/index.tsx b/refine-nextjs/plugins/antd-example/src/components/themed-layout/index.tsx new file mode 100644 index 000000000..a5c31afd9 --- /dev/null +++ b/refine-nextjs/plugins/antd-example/src/components/themed-layout/index.tsx @@ -0,0 +1,32 @@ +"use client"; + +import { Header } from "@components/header"; +import { + ThemedLayoutV2, + <%_ if (selectedSvg || selectedTitle) { _%> + ThemedTitleV2 + <%_ } _%> +} from "@refinedev/antd"; +import React from "react"; + +export const ThemedLayout = ({ children }: React.PropsWithChildren) => { + return ( +
} + <%_ if (selectedSvg || selectedTitle) { _%> + Title={({ collapsed }) => ( + + text="<%= selectedTitle %>" + <%_ } _%> + <%_ if (selectedSvg) { _%> + icon={} + <%_ } _%> + /> + )} + <%_ } _%> + > + {children} + + ); +}; diff --git a/refine-nextjs/plugins/antd/extend.js b/refine-nextjs/plugins/antd/extend.js index 2f0b7ef34..f56f08f9d 100644 --- a/refine-nextjs/plugins/antd/extend.js +++ b/refine-nextjs/plugins/antd/extend.js @@ -2,21 +2,19 @@ const base = { _app: { refineProps: ["notificationProvider={useNotificationProvider}"], import: [ - `import { App as AntdApp } from "antd"`, + `import { AntdRegistry } from "@ant-design/nextjs-registry";`, 'import "@refinedev/antd/dist/reset.css";', ], - refineAntdImports: [ - "useNotificationProvider", - "ThemedLayoutV2", - "ThemedSiderV2", - ], + refineAntdImports: ["useNotificationProvider"], wrapper: [ - [``, ``], - [``, ``], + [``, ``], + [ + ``, + ``, + ], ], localImport: [ - `import { Header } from "@components/header"`, - `import { ColorModeContextProvider } from "@contexts";`, + `import { ColorModeContextProvider } from "@contexts/color-mode";`, ], }, }; diff --git a/refine-nextjs/plugins/antd/package.json b/refine-nextjs/plugins/antd/package.json index a490611f5..250e6073e 100644 --- a/refine-nextjs/plugins/antd/package.json +++ b/refine-nextjs/plugins/antd/package.json @@ -1,7 +1,12 @@ { - "dependencies": { - "@refinedev/antd": "^5.37.1", - "antd": "^5.0.5", - "@ant-design/icons": "^5.0.1" - } + "dependencies": { + "@refinedev/antd": "^5.37.4", + "@ant-design/icons": "^5.0.1", + "antd": "^5.0.5", + "js-cookie": "^3.0.5", + "@ant-design/nextjs-registry": "^1.0.0" + }, + "devDependencies": { + "@types/js-cookie": "^3.0.6" + } } diff --git a/refine-nextjs/plugins/antd/src/components/header/index.tsx b/refine-nextjs/plugins/antd/src/components/header/index.tsx index 581989823..8111be9e9 100644 --- a/refine-nextjs/plugins/antd/src/components/header/index.tsx +++ b/refine-nextjs/plugins/antd/src/components/header/index.tsx @@ -1,3 +1,6 @@ +"use client"; + +import { ColorModeContext } from "@contexts/color-mode"; import type { RefineThemedLayoutV2HeaderProps } from "@refinedev/antd"; import { useGetIdentity } from "@refinedev/core"; import { @@ -9,7 +12,6 @@ import { Typography, } from "antd"; import React, { useContext } from "react"; -import { ColorModeContext } from "../../contexts"; const { Text } = Typography; const { useToken } = theme; diff --git a/refine-nextjs/plugins/antd/src/contexts/index.tsx b/refine-nextjs/plugins/antd/src/contexts/color-mode/index.tsx similarity index 69% rename from refine-nextjs/plugins/antd/src/contexts/index.tsx rename to refine-nextjs/plugins/antd/src/contexts/color-mode/index.tsx index bf95cfb8b..f443703ad 100644 --- a/refine-nextjs/plugins/antd/src/contexts/index.tsx +++ b/refine-nextjs/plugins/antd/src/contexts/color-mode/index.tsx @@ -1,3 +1,5 @@ +'use client' + import React, { PropsWithChildren, createContext, @@ -5,8 +7,8 @@ import React, { useState, } from "react"; import { RefineThemes } from "@refinedev/antd"; -import { ConfigProvider, theme } from "antd"; -import { parseCookies } from "nookies"; +import { ConfigProvider, App as AntdApp, theme } from 'antd' +import Cookies from 'js-cookie' type ColorModeContextType = { mode: string; @@ -17,11 +19,15 @@ export const ColorModeContext = createContext( {} as ColorModeContextType, ); -export const ColorModeContextProvider: React.FC = ({ - children, -}) => { +type ColorModeContextProviderProps = { + defaultMode?: string; +}; + +export const ColorModeContextProvider: React.FC< + PropsWithChildren +> = ({ children, defaultMode }) => { const [isMounted, setIsMounted] = useState(false); - const [mode, setMode] = useState("light"); + const [mode, setMode] = useState(defaultMode || "light"); useEffect(() => { setIsMounted(true); @@ -29,15 +35,18 @@ export const ColorModeContextProvider: React.FC = ({ useEffect(() => { if (isMounted) { - setMode(parseCookies()["theme"]); + const theme = Cookies.get('theme') || 'light' + setMode(theme) } }, [isMounted]); const setColorMode = () => { if (mode === "light") { setMode("dark"); + Cookies.set('theme', 'dark') } else { setMode("light"); + Cookies.set('theme', 'light') } }; @@ -58,7 +67,7 @@ export const ColorModeContextProvider: React.FC = ({ mode === "light" ? defaultAlgorithm : darkAlgorithm, }} > - {children} + {children} ); diff --git a/refine-nextjs/plugins/auth-provider-auth0/extend.js b/refine-nextjs/plugins/auth-provider-auth0/extend.js index 79cdbd649..668ef874f 100644 --- a/refine-nextjs/plugins/auth-provider-auth0/extend.js +++ b/refine-nextjs/plugins/auth-provider-auth0/extend.js @@ -3,9 +3,7 @@ const base = { localImport: [], refineProps: ["authProvider={authProvider}"], refineAntdImports: [], - refineMantineImports: [], refineMuiImports: [], - refineChakraImports: [], }, }; diff --git a/refine-nextjs/plugins/auth-provider-auth0/package.json b/refine-nextjs/plugins/auth-provider-auth0/package.json index d309411e5..90d1bfc2d 100644 --- a/refine-nextjs/plugins/auth-provider-auth0/package.json +++ b/refine-nextjs/plugins/auth-provider-auth0/package.json @@ -1,6 +1,5 @@ { - "dependencies": { - "nookies": "^2.5.2", - "next-auth": "^4.20.1" - } -} \ No newline at end of file + "dependencies": { + "next-auth": "^4.24.5" + } +} diff --git a/refine-nextjs/plugins/auth-provider-auth0/pages/login/index.tsx b/refine-nextjs/plugins/auth-provider-auth0/pages/login/index.tsx deleted file mode 100644 index 64b99e7a0..000000000 --- a/refine-nextjs/plugins/auth-provider-auth0/pages/login/index.tsx +++ /dev/null @@ -1,332 +0,0 @@ -import { useLogin } from "@refinedev/core"; - -<%_ if (answers["ui-framework"] === "antd") { _%> -import { ThemedTitleV2 } from "@refinedev/antd"; -import { Button, Typography, Layout, Space } from "antd"; -<%_ } _%> -<%_ if (answers["ui-framework"] === 'mui') { _%> -import Box from "@mui/material/Box"; -import Button from "@mui/material/Button"; -import Container from "@mui/material/Container"; -import Typography from "@mui/material/Typography"; -import { ThemedTitleV2 } from "@refinedev/mui"; -<%_ } _%> -<%_ if (answers["ui-framework"] === 'mantine') { _%> -import { Button, Box, Space, Text } from "@mantine/core"; -import { ThemedTitleV2 } from "@refinedev/mantine"; -<%_ } _%> -<%_ if (answers["ui-framework"] === 'chakra') { _%> -import { Button, Box, Text, VStack } from "@chakra-ui/react"; -import { ThemedTitleV2 } from "@refinedev/chakra-ui"; -<%_ } _%> - -import { GetServerSideProps } from "next"; -<%_ if (answers[`i18n-${answers["ui-framework"]}`] !== "no") { _%> -import { serverSideTranslations } from "next-i18next/serverSideTranslations"; -import { useTranslate } from "@refinedev/core"; -<%_ } _%> -<%_ if (_app.isAuthProviderCheck) { _%> -import { authProvider } from "src/authProvider"; -<%_ } _%> -<%_ if (selectedSvg && answers["ui-framework"] !== "no" ) { _%> -import { AppIcon } from "src/components/app-icon"; -<%_ } _%> - -<%_ if (_app.isNextAuthCheck) { _%> -import { getServerSession } from "next-auth"; -import { authOptions } from "../api/auth/[...nextauth]"; -<%_ } _%> - -export default function Login() { - const { mutate: login } = useLogin(); - - <%_ if (answers[`i18n-${answers["ui-framework"]}`] !== "no") { _%> - const t = useTranslate(); - <%_ } _%> - - <%_ if (answers["ui-framework"] === "antd") { _%> - return ( - - - - text="<%= selectedTitle %>" - <%_ } _%> - <%_ if (selectedSvg) { _%> - icon={} - <%_ } _%> - /> - - - Powered by - Auth0 - Auth0 - - - - ); - <%_ } _%> - - <%_ if (answers["ui-framework"] === 'mui') { _%> - return ( - - - - text="<%= selectedTitle %>" - <%_ } _%> - <%_ if (selectedSvg) { _%> - icon={} - <%_ } _%> - /> - - - - Powered by - Auth0 - Auth0 - - - - ); - <%_ } _%> - - <%_ if (answers["ui-framework"] === 'mantine') { _%> - return ( - - - text="<%= selectedTitle %>" - <%_ } _%> - <%_ if (selectedSvg) { _%> - icon={} - <%_ } _%> - /> - - - - - - Powered by - Auth0 - Auth0 - - - ); - <%_ } _%> - - <%_ if (answers["ui-framework"] === 'chakra') { _%> - return ( - - - - text="<%= selectedTitle %>" - <%_ } _%> - <%_ if (selectedSvg) { _%> - icon={} - <%_ } _%> - /> - - - - - Powered by - Auth0 - Auth0 - - - - ); - <%_ } _%> - - <%_ if (answers["ui-framework"] === "no") { _%> - return( -
- -

- Powered by - Auth0 - Auth0 -

-
- ); - <%_ } _%> -} - -Login.noLayout = true; - -export const getServerSideProps: GetServerSideProps<{}> = async (context) => { - - <%_ if (_app.isNextAuthCheck) { _%> - const session = await getServerSession( - context.req, - context.res, - authOptions, - ); - <%_ } _%> - - <%_ if (_app.isAuthProviderCheck) { _%> - const { authenticated, redirectTo } = await authProvider.check(context); - <%_ } _%> - - <%_ if (answers[`i18n-${answers["ui-framework"]}`] !== "no") { _%> - const translateProps = await serverSideTranslations( - context.locale ?? "en", - ["common"], - ); - <%_ } _%> - - <%_ if (_app.isAuthProviderCheck) { _%> - if (authenticated) { - return { - props: {}, - redirect: { - destination: "/", - permanent: false, - }, - }; - } - <%_ } _%> - - <%_ if (_app.isNextAuthCheck) { _%> - if (session) { - return { - props: {}, - redirect: { - destination: "/", - permanent: false, - }, - }; - } - <%_ } _%> - - return { - props: { - <%_ if (answers[`i18n-${answers["ui-framework"]}`] !== "no") { _%> - ...translateProps, - <%_ } _%> - }, - }; -}; - diff --git a/refine-nextjs/plugins/auth-provider-auth0/pages/_app.tsx b/refine-nextjs/plugins/auth-provider-auth0/src/app/_refine_context.tsx similarity index 65% rename from refine-nextjs/plugins/auth-provider-auth0/pages/_app.tsx rename to refine-nextjs/plugins/auth-provider-auth0/src/app/_refine_context.tsx index afebb4fb9..39f8c4bc6 100644 --- a/refine-nextjs/plugins/auth-provider-auth0/pages/_app.tsx +++ b/refine-nextjs/plugins/auth-provider-auth0/src/app/_refine_context.tsx @@ -1,23 +1,18 @@ +'use client' + import React from "react"; -import { AppProps } from "next/app"; -import type { NextPage } from "next"; import { Refine, GitHubBanner, AuthBindings, <%- (_app.refineImports || []).join("\n,") _%> } from '@refinedev/core'; import { RefineKbar, RefineKbarProvider } from "@refinedev/kbar"; import { SessionProvider, useSession, signOut, signIn } from "next-auth/react"; -import { useRouter } from "next/router"; +import { usePathname } from 'next/navigation' <%_ if (answers["ui-framework"] === 'antd') { _%> import { <%- (_app.refineAntdImports || []).join("\n,") _%> } from '@refinedev/antd'; <%_ } _%> <%_ if (answers["ui-framework"] === 'mui') { _%> import { <%- (_app.refineMuiImports || []).join("\n,") _%> } from '@refinedev/mui'; <%_ } _%> -<%_ if (answers["ui-framework"] === 'mantine') { _%> - import { <%- (_app.refineMantineImports || []).join("\n,") _%> } from '@refinedev/mantine'; -<%_ } _%> -<%_ if (answers["ui-framework"] === 'chakra') { _%> - import { <%- (_app.refineChakraImports || []).join("\n,") _%> } from '@refinedev/chakra-ui'; -<%_ } _%> -import routerProvider, { UnsavedChangesNotifier } from "@refinedev/nextjs-router"; + +import routerProvider from "@refinedev/nextjs-router"; <%- (_app.import || []).join("\n") _%> @@ -32,20 +27,31 @@ import routerProvider, { UnsavedChangesNotifier } from "@refinedev/nextjs-router var bottom = _app.wrapper.map(wrapper => wrapper[1] || "").reverse(); %> -export type NextPageWithLayout

= NextPage & { - noLayout?: boolean; - }; +type RefineContextProps = { + <%_ if (answers["ui-framework"] !== 'no') { _%> + defaultMode?: string; + <%_ } _%> +}; - type AppPropsWithLayout = AppProps & { - Component: NextPageWithLayout; - }; +export const RefineContext = (props: React.PropsWithChildren) => { + return ( + + + + ) + } + +type AppProps = { + <%_ if (answers["ui-framework"] !== 'no') { _%> + defaultMode?: string; + <%_ } _%> +}; - const App = (props: React.PropsWithChildren) => { +const App = (props: React.PropsWithChildren) => { <%- (_app.innerHooks || []).join("\n") %> const { data, status } = useSession(); - const router = useRouter(); - const { to } = router.query; + const to = usePathname() <%- (_app.inner || []).join("\n") %> @@ -75,7 +81,12 @@ export type NextPageWithLayout

= NextPage & { }; }, onError: async (error) => { - console.error(error); + if (error.response?.status === 401) { + return { + logout: true, + }; + } + return { error, }; @@ -108,6 +119,11 @@ export type NextPageWithLayout

= NextPage & { }, }; + + <%_ if (answers["ui-framework"] !== 'no') { _%> + const defaultMode = props?.defaultMode + <%_ } _%> + return ( <> @@ -116,7 +132,7 @@ export type NextPageWithLayout

= NextPage & { - <%_ if (answers["inferencer"] === 'inferencer' || answers["inferencer-headless"] === 'inferencer-headless') { _%> + <%_ if (_app.hasRoutes === true) { _%> resources={[ <%_ if (answers["data-provider"] === 'data-provider-strapi-v4') { _%> { @@ -174,62 +190,9 @@ export type NextPageWithLayout

= NextPage & { > {props.children} - <%- bottom.join("\n") %> ); }; - - -function MyApp({ Component, pageProps: { session, ...pageProps }, }: AppPropsWithLayout): JSX.Element { - const renderComponent = () => { - if (Component.noLayout) { - return ; - } - - <%_ if (answers["ui-framework"] === "no") { _%> - return ( - - ); - <%_ } else {_%> - return ( -

} - <%_ if (answers["ui-framework"] === 'antd') { _%> - Sider={(props) => } - <%_ } _%> - <%_ if (selectedSvg || selectedTitle) { _%> - Title={({ collapsed }) => ( - - text="<%= selectedTitle %>" - <%_ } _%> - <%_ if (selectedSvg) { _%> - icon={} - <%_ } _%> - /> - )} - <%_ } _%> - > - - - ); - <%_ } _%> - }; - - return ( - - {renderComponent()} - - ); -}; - - -<%_ if (answers[`i18n-${answers["ui-framework"]}`] !== 'no') { _%> -export default appWithTranslation(MyApp); -<%_ } else {_%> -export default MyApp; -<%_ } _%> diff --git a/refine-nextjs/plugins/auth-provider-auth0/pages/api/auth/[...nextauth].ts b/refine-nextjs/plugins/auth-provider-auth0/src/app/api/auth/[...nextauth]/options.ts similarity index 83% rename from refine-nextjs/plugins/auth-provider-auth0/pages/api/auth/[...nextauth].ts rename to refine-nextjs/plugins/auth-provider-auth0/src/app/api/auth/[...nextauth]/options.ts index 2d37c066a..52c5b298a 100644 --- a/refine-nextjs/plugins/auth-provider-auth0/pages/api/auth/[...nextauth].ts +++ b/refine-nextjs/plugins/auth-provider-auth0/src/app/api/auth/[...nextauth]/options.ts @@ -1,7 +1,6 @@ -import NextAuth from "next-auth"; import Auth0Provider from "next-auth/providers/auth0"; -export const authOptions = { +const authOptions = { // Configure one or more authentication providers providers: [ // !!! Should be stored in .env file. @@ -13,4 +12,5 @@ export const authOptions = { ], secret: `UItTuD1HcGXIj8ZfHUswhYdNd40Lc325R8VlxQPUoR0=`, }; -export default NextAuth(authOptions); + +export default authOptions; diff --git a/refine-nextjs/plugins/auth-provider-auth0/src/app/api/auth/[...nextauth]/route.ts b/refine-nextjs/plugins/auth-provider-auth0/src/app/api/auth/[...nextauth]/route.ts new file mode 100644 index 000000000..a79078599 --- /dev/null +++ b/refine-nextjs/plugins/auth-provider-auth0/src/app/api/auth/[...nextauth]/route.ts @@ -0,0 +1,5 @@ +import NextAuth from "next-auth/next"; +import authOptions from "./options"; + +const auth = NextAuth(authOptions); +export { auth as GET, auth as POST }; diff --git a/refine-nextjs/plugins/auth-provider-auth0/src/app/layout.tsx b/refine-nextjs/plugins/auth-provider-auth0/src/app/layout.tsx new file mode 100644 index 000000000..2c0a62343 --- /dev/null +++ b/refine-nextjs/plugins/auth-provider-auth0/src/app/layout.tsx @@ -0,0 +1,34 @@ +import { Metadata } from "next"; +<%- (_app.nextjsImport || []).join("\n") _%> +import React, { Suspense } from "react"; +import { RefineContext } from "./_refine_context"; + +export const metadata: Metadata = { + title: "Refine", + description: "Generated by create refine app", + icons: { + icon: "/favicon.ico", + }, +}; + +export default function RootLayout({ + children, +}: Readonly<{ + children: React.ReactNode; +}>) { + + <%- (_app.nextjsInner || []).join("\n") %> + + return ( + + + + + > + {children} + + + + + ); +} diff --git a/refine-nextjs/plugins/auth-provider-auth0/src/app/login/layout.tsx b/refine-nextjs/plugins/auth-provider-auth0/src/app/login/layout.tsx new file mode 100644 index 000000000..3bde1abb1 --- /dev/null +++ b/refine-nextjs/plugins/auth-provider-auth0/src/app/login/layout.tsx @@ -0,0 +1,24 @@ +import authOptions from "@app/api/auth/[...nextauth]/options"; +import { getServerSession } from "next-auth/next"; +import { redirect } from "next/navigation"; +import React from "react"; + +export default async function LoginLayout({ + children, +}: React.PropsWithChildren) { + const data = await getData(); + + if (data.session?.user) { + return redirect("/"); + } + + return <>{children}; +} + +async function getData() { + const session = await getServerSession(authOptions); + + return { + session, + }; +} diff --git a/refine-nextjs/plugins/auth-provider-auth0/src/app/login/page.tsx b/refine-nextjs/plugins/auth-provider-auth0/src/app/login/page.tsx new file mode 100644 index 000000000..1c286f12c --- /dev/null +++ b/refine-nextjs/plugins/auth-provider-auth0/src/app/login/page.tsx @@ -0,0 +1,145 @@ +"use client" + +import { useLogin } from "@refinedev/core"; + +<%_ if (answers["ui-framework"] === "antd") { _%> +import { ThemedTitleV2 } from "@refinedev/antd"; +import { Button, Typography, Layout, Space } from "antd"; +<%_ } _%> +<%_ if (answers["ui-framework"] === 'mui') { _%> +import Box from "@mui/material/Box"; +import Button from "@mui/material/Button"; +import Container from "@mui/material/Container"; +import Typography from "@mui/material/Typography"; +import { ThemedTitleV2 } from "@refinedev/mui"; +<%_ } _%> + +<%_ if (selectedSvg && answers["ui-framework"] !== "no" ) { _%> +import { AppIcon } from "src/components/app-icon"; +<%_ } _%> + + + +export default function Login() { + const { mutate: login } = useLogin(); + + <%_ if (answers["ui-framework"] === "antd") { _%> + return ( + + + + text="<%= selectedTitle %>" + <%_ } _%> + <%_ if (selectedSvg) { _%> + icon={} + <%_ } _%> + /> + + + Powered by + Auth0 + Auth0 + + + + ); + <%_ } _%> + + <%_ if (answers["ui-framework"] === 'mui') { _%> + return ( + + + + text="<%= selectedTitle %>" + <%_ } _%> + <%_ if (selectedSvg) { _%> + icon={} + <%_ } _%> + /> + + + + Powered by + Auth0 + Auth0 + + + + ); + <%_ } _%> + + <%_ if (answers["ui-framework"] === "no") { _%> + return( +
+ +

+ Powered by + Auth0 + Auth0 +

+
+ ); + <%_ } _%> +} + diff --git a/refine-nextjs/plugins/auth-provider-custom/extend.js b/refine-nextjs/plugins/auth-provider-custom/extend.js index 70dbfd0aa..89927dc93 100644 --- a/refine-nextjs/plugins/auth-provider-custom/extend.js +++ b/refine-nextjs/plugins/auth-provider-custom/extend.js @@ -1,11 +1,11 @@ const base = { _app: { - localImport: ['import { authProvider } from "src/authProvider";'], + localImport: [ + 'import { authProvider } from "@providers/auth-provider";', + ], refineProps: ["authProvider={authProvider}"], refineAntdImports: [], - refineMantineImports: [], refineMuiImports: [], - refineChakraImports: [], }, }; diff --git a/refine-nextjs/plugins/auth-provider-custom/package.json b/refine-nextjs/plugins/auth-provider-custom/package.json index 299287252..28b2743fd 100644 --- a/refine-nextjs/plugins/auth-provider-custom/package.json +++ b/refine-nextjs/plugins/auth-provider-custom/package.json @@ -1,5 +1,8 @@ { - "dependencies": { - "nookies": "^2.5.2" - } -} \ No newline at end of file + "dependencies": { + "js-cookie": "^3.0.5" + }, + "devDependencies": { + "@types/js-cookie": "^3.0.6" + } +} diff --git a/refine-nextjs/plugins/auth-provider-custom/pages/forgot-password/index.tsx b/refine-nextjs/plugins/auth-provider-custom/pages/forgot-password/index.tsx deleted file mode 100644 index 06c850271..000000000 --- a/refine-nextjs/plugins/auth-provider-custom/pages/forgot-password/index.tsx +++ /dev/null @@ -1,103 +0,0 @@ -<%_ if (answers["ui-framework"] === 'antd') { _%> -import { - AuthPage, - <%_ if (selectedSvg || selectedTitle) { _%> - ThemedTitleV2, - <%_ } _%> -} from "@refinedev/antd"; -<%_ } _%> -<%_ if (answers["ui-framework"] === 'mui') { _%> -import { - AuthPage, - <%_ if (selectedSvg || selectedTitle) { _%> - ThemedTitleV2, - <%_ } _%> -} from "@refinedev/mui"; -<%_ } _%> -<%_ if (answers["ui-framework"] === 'mantine') { _%> -import { - AuthPage, - <%_ if (selectedSvg || selectedTitle) { _%> - ThemedTitleV2, - <%_ } _%> -} from "@refinedev/mantine"; -<%_ } _%> -<%_ if (answers["ui-framework"] === 'chakra') { _%> -import { - AuthPage, - <%_ if (selectedSvg || selectedTitle) { _%> - ThemedTitleV2, - <%_ } _%> -} from "@refinedev/chakra-ui"; -<%_ } _%> -<%_ if (answers[`ui-framework`] === "no") { _%> - import { AuthPage } from "@refinedev/core"; -<%_ } _%> - -import { GetServerSideProps } from "next"; -<%_ if (answers[`i18n-${answers["ui-framework"]}`] !== "no") { _%> -import { serverSideTranslations } from "next-i18next/serverSideTranslations"; -<%_ } _%> -<%_ if (_app.isAuthProviderCheck) { _%> -import { authProvider } from "src/authProvider"; -<%_ } _%> -<%_ if (selectedSvg && answers["ui-framework"] !== "no") { _%> -import { AppIcon } from "src/components/app-icon"; -<%_ } _%> - -export default function ForgotPassword() { - return ( - - title={( - - text="<%= selectedTitle %>" - <%_ } _%> - <%_ if (selectedSvg) { _%> - icon={} - <%_ } _%> - /> - )} - <%_ } _%> - /> - ); -} - -ForgotPassword.noLayout = true; - -export const getServerSideProps: GetServerSideProps<{}> = async (context) => { - <%_ if (_app.isAuthProviderCheck) { _%> - const { authenticated, redirectTo } = await authProvider.check(context); - <%_ } _%> - - <%_ if (answers[`i18n-${answers["ui-framework"]}`] !== "no") { _%> - const translateProps = await serverSideTranslations( - context.locale ?? "en", - ["common"], - ); - <%_ } _%> - - <%_ if (_app.isAuthProviderCheck) { _%> - if (authenticated) { - return { - props: {}, - redirect: { - destination: redirectTo ?? "/", - permanent: false, - }, - }; - } - <%_ } _%> - - return { - props: { - <%_ if (answers[`i18n-${answers["ui-framework"]}`] !== "no") { _%> - ...translateProps, - <%_ } _%> - }, - }; -}; - diff --git a/refine-nextjs/plugins/auth-provider-custom/pages/login/index.tsx b/refine-nextjs/plugins/auth-provider-custom/pages/login/index.tsx deleted file mode 100644 index 47e4a6ab7..000000000 --- a/refine-nextjs/plugins/auth-provider-custom/pages/login/index.tsx +++ /dev/null @@ -1,104 +0,0 @@ -<%_ if (answers["ui-framework"] === 'antd') { _%> -import { - AuthPage, - <%_ if (selectedSvg || selectedTitle) { _%> - ThemedTitleV2, - <%_ } _%> -} from "@refinedev/antd"; -<%_ } _%> -<%_ if (answers["ui-framework"] === 'mui') { _%> -import { - AuthPage, - <%_ if (selectedSvg || selectedTitle) { _%> - ThemedTitleV2, - <%_ } _%> -} from "@refinedev/mui"; -<%_ } _%> -<%_ if (answers["ui-framework"] === 'mantine') { _%> -import { - AuthPage, - <%_ if (selectedSvg || selectedTitle) { _%> - ThemedTitleV2, - <%_ } _%> -} from "@refinedev/mantine"; -<%_ } _%> -<%_ if (answers["ui-framework"] === 'chakra') { _%> -import { - AuthPage, - <%_ if (selectedSvg || selectedTitle) { _%> - ThemedTitleV2, - <%_ } _%> -} from "@refinedev/chakra-ui"; -<%_ } _%> -<%_ if (answers[`ui-framework`] === "no") { _%> - import { AuthPage } from "@refinedev/core"; -<%_ } _%> - -import { GetServerSideProps } from "next"; -<%_ if (answers[`i18n-${answers["ui-framework"]}`] !== "no") { _%> -import { serverSideTranslations } from "next-i18next/serverSideTranslations"; -<%_ } _%> -<%_ if (_app.isAuthProviderCheck) { _%> -import { authProvider } from "src/authProvider"; -<%_ } _%> -<%_ if (selectedSvg && answers["ui-framework"] !== "no") { _%> -import { AppIcon } from "src/components/app-icon"; -<%_ } _%> - -export default function Login() { - return ( - - <%_ if ((selectedSvg || selectedTitle) && answers["ui-framework"] !== "no") { _%> - title={( - - text="<%= selectedTitle %>" - <%_ } _%> - <%_ if (selectedSvg) { _%> - icon={} - <%_ } _%> - /> - )} - <%_ } _%> - /> - ); -} - -Login.noLayout = true; - -export const getServerSideProps: GetServerSideProps<{}> = async (context) => { - <%_ if (_app.isAuthProviderCheck) { _%> - const { authenticated, redirectTo } = await authProvider.check(context); - <%_ } _%> - - <%_ if (answers[`i18n-${answers["ui-framework"]}`] !== "no") { _%> - const translateProps = await serverSideTranslations( - context.locale ?? "en", - ["common"], - ); - <%_ } _%> - - <%_ if (_app.isAuthProviderCheck) { _%> - if (authenticated) { - return { - props: {}, - redirect: { - destination: redirectTo ?? "/", - permanent: false, - }, - }; - } - <%_ } _%> - - return { - props: { - <%_ if (answers[`i18n-${answers["ui-framework"]}`] !== "no") { _%> - ...translateProps, - <%_ } _%> - }, - }; -}; - diff --git a/refine-nextjs/plugins/auth-provider-custom/pages/register/index.tsx b/refine-nextjs/plugins/auth-provider-custom/pages/register/index.tsx deleted file mode 100644 index 4f294b605..000000000 --- a/refine-nextjs/plugins/auth-provider-custom/pages/register/index.tsx +++ /dev/null @@ -1,103 +0,0 @@ -<%_ if (answers["ui-framework"] === 'antd') { _%> -import { - AuthPage, - <%_ if (selectedSvg || selectedTitle) { _%> - ThemedTitleV2, - <%_ } _%> -} from "@refinedev/antd"; -<%_ } _%> -<%_ if (answers["ui-framework"] === 'mui') { _%> -import { - AuthPage, - <%_ if (selectedSvg || selectedTitle) { _%> - ThemedTitleV2, - <%_ } _%> -} from "@refinedev/mui"; -<%_ } _%> -<%_ if (answers["ui-framework"] === 'mantine') { _%> -import { - AuthPage, - <%_ if (selectedSvg || selectedTitle) { _%> - ThemedTitleV2, - <%_ } _%> -} from "@refinedev/mantine"; -<%_ } _%> -<%_ if (answers["ui-framework"] === 'chakra') { _%> -import { - AuthPage, - <%_ if (selectedSvg || selectedTitle) { _%> - ThemedTitleV2, - <%_ } _%> -} from "@refinedev/chakra-ui"; -<%_ } _%> -<%_ if (answers[`ui-framework`] === "no") { _%> - import { AuthPage } from "@refinedev/core"; -<%_ } _%> - -import { GetServerSideProps } from "next"; -<%_ if (answers[`i18n-${answers["ui-framework"]}`] !== "no") { _%> -import { serverSideTranslations } from "next-i18next/serverSideTranslations"; -<%_ } _%> -<%_ if (_app.isAuthProviderCheck) { _%> -import { authProvider } from "src/authProvider"; -<%_ } _%> -<%_ if (selectedSvg && answers["ui-framework"] !== "no") { _%> -import { AppIcon } from "src/components/app-icon"; -<%_ } _%> - -export default function Register() { - return ( - - title={( - - text="<%= selectedTitle %>" - <%_ } _%> - <%_ if (selectedSvg) { _%> - icon={} - <%_ } _%> - /> - )} - <%_ } _%> - /> - ); -} - -Register.noLayout = true; - -export const getServerSideProps: GetServerSideProps<{}> = async (context) => { - <%_ if (_app.isAuthProviderCheck) { _%> - const { authenticated, redirectTo } = await authProvider.check(context); - <%_ } _%> - - <%_ if (answers[`i18n-${answers["ui-framework"]}`] !== "no") { _%> - const translateProps = await serverSideTranslations( - context.locale ?? "en", - ["common"], - ); - <%_ } _%> - - <%_ if (_app.isAuthProviderCheck) { _%> - if (authenticated) { - return { - props: {}, - redirect: { - destination: redirectTo ?? "/", - permanent: false, - }, - }; - } - <%_ } _%> - - return { - props: { - <%_ if (answers[`i18n-${answers["ui-framework"]}`] !== "no") { _%> - ...translateProps, - <%_ } _%> - }, - }; -}; - diff --git a/refine-nextjs/plugins/auth-provider-custom/src/app/forgot-password/page.tsx b/refine-nextjs/plugins/auth-provider-custom/src/app/forgot-password/page.tsx new file mode 100644 index 000000000..c2b0061f5 --- /dev/null +++ b/refine-nextjs/plugins/auth-provider-custom/src/app/forgot-password/page.tsx @@ -0,0 +1,24 @@ +import { AuthPage } from "@components/auth-page"; +import { authProviderServer } from "@providers/auth-provider"; +import { redirect } from "next/navigation"; + +export default async function ForgotPassword() { + const data = await getData(); + + if (data.authenticated) { + redirect(data?.redirectTo || "/"); + } + + return ; +} + +async function getData() { + const { authenticated, redirectTo, error } = + await authProviderServer.check(); + + return { + authenticated, + redirectTo, + error, + }; +} diff --git a/refine-nextjs/plugins/auth-provider-custom/src/app/login/page.tsx b/refine-nextjs/plugins/auth-provider-custom/src/app/login/page.tsx new file mode 100644 index 000000000..e4e77ff92 --- /dev/null +++ b/refine-nextjs/plugins/auth-provider-custom/src/app/login/page.tsx @@ -0,0 +1,24 @@ +import { AuthPage } from "@components/auth-page"; +import { authProviderServer } from "@providers/auth-provider"; +import { redirect } from "next/navigation"; + +export default async function Login() { + const data = await getData(); + + if (data.authenticated) { + redirect(data?.redirectTo || "/"); + } + + return ; +} + +async function getData() { + const { authenticated, redirectTo, error } = + await authProviderServer.check(); + + return { + authenticated, + redirectTo, + error, + }; +} diff --git a/refine-nextjs/plugins/auth-provider-custom/src/app/register/page.tsx b/refine-nextjs/plugins/auth-provider-custom/src/app/register/page.tsx new file mode 100644 index 000000000..b07acae8d --- /dev/null +++ b/refine-nextjs/plugins/auth-provider-custom/src/app/register/page.tsx @@ -0,0 +1,24 @@ +import { AuthPage } from "@components/auth-page"; +import { authProviderServer } from "@providers/auth-provider"; +import { redirect } from "next/navigation"; + +export default async function Register() { + const data = await getData(); + + if (data.authenticated) { + redirect(data?.redirectTo || "/"); + } + + return ; +} + +async function getData() { + const { authenticated, redirectTo, error } = + await authProviderServer.check(); + + return { + authenticated, + redirectTo, + error, + }; +} diff --git a/refine-nextjs/plugins/auth-provider-custom/src/providers/auth-provider/auth-provider.server.ts b/refine-nextjs/plugins/auth-provider-custom/src/providers/auth-provider/auth-provider.server.ts new file mode 100644 index 000000000..b44a5b3a7 --- /dev/null +++ b/refine-nextjs/plugins/auth-provider-custom/src/providers/auth-provider/auth-provider.server.ts @@ -0,0 +1,21 @@ +import { AuthBindings } from "@refinedev/core"; +import { cookies } from "next/headers"; + +export const authProviderServer: Pick = { + check: async () => { + const cookieStore = cookies(); + const auth = cookieStore.get("auth"); + + if (auth) { + return { + authenticated: true, + }; + } + + return { + authenticated: false, + logout: true, + redirectTo: "/login", + }; + }, +}; diff --git a/refine-nextjs/plugins/auth-provider-custom/src/authProvider.ts b/refine-nextjs/plugins/auth-provider-custom/src/providers/auth-provider/auth-provider.ts similarity index 77% rename from refine-nextjs/plugins/auth-provider-custom/src/authProvider.ts rename to refine-nextjs/plugins/auth-provider-custom/src/providers/auth-provider/auth-provider.ts index cbc07f16a..2a10c84bc 100644 --- a/refine-nextjs/plugins/auth-provider-custom/src/authProvider.ts +++ b/refine-nextjs/plugins/auth-provider-custom/src/providers/auth-provider/auth-provider.ts @@ -1,5 +1,7 @@ +"use client"; + import { AuthBindings } from "@refinedev/core"; -import nookies from "nookies"; +import Cookies from "js-cookie"; const mockUsers = [ { @@ -22,8 +24,8 @@ export const authProvider: AuthBindings = { const user = mockUsers[0]; if (user) { - nookies.set(null, "auth", JSON.stringify(user), { - maxAge: 30 * 24 * 60 * 60, + Cookies.set("auth", JSON.stringify(user), { + expires: 30, // 30 days path: "/", }); return { @@ -41,15 +43,15 @@ export const authProvider: AuthBindings = { }; }, logout: async () => { - nookies.destroy(null, "auth"); + Cookies.remove("auth", { path: "/" }); return { success: true, redirectTo: "/login", }; }, - check: async (ctx: any) => { - const cookies = nookies.get(ctx); - if (cookies["auth"]) { + check: async () => { + const auth = Cookies.get("auth"); + if (auth) { return { authenticated: true, }; @@ -62,7 +64,7 @@ export const authProvider: AuthBindings = { }; }, getPermissions: async () => { - const auth = nookies.get()["auth"]; + const auth = Cookies.get("auth"); if (auth) { const parsedUser = JSON.parse(auth); return parsedUser.roles; @@ -70,7 +72,7 @@ export const authProvider: AuthBindings = { return null; }, getIdentity: async () => { - const auth = nookies.get()["auth"]; + const auth = Cookies.get("auth"); if (auth) { const parsedUser = JSON.parse(auth); return parsedUser; @@ -78,7 +80,12 @@ export const authProvider: AuthBindings = { return null; }, onError: async (error) => { - console.error(error); + if (error.response?.status === 401) { + return { + logout: true, + }; + } + return { error }; }, }; diff --git a/refine-nextjs/plugins/auth-provider-custom/src/providers/auth-provider/index.ts b/refine-nextjs/plugins/auth-provider-custom/src/providers/auth-provider/index.ts new file mode 100644 index 000000000..b7f6d9fe9 --- /dev/null +++ b/refine-nextjs/plugins/auth-provider-custom/src/providers/auth-provider/index.ts @@ -0,0 +1,2 @@ +export * from './auth-provider' +export * from './auth-provider.server' diff --git a/refine-nextjs/plugins/auth-provider-google/extend.js b/refine-nextjs/plugins/auth-provider-google/extend.js index 79cdbd649..512f7f1be 100644 --- a/refine-nextjs/plugins/auth-provider-google/extend.js +++ b/refine-nextjs/plugins/auth-provider-google/extend.js @@ -1,11 +1,10 @@ const base = { _app: { localImport: [], + refineContextProps: ["defaultMode={defaultMode}"], refineProps: ["authProvider={authProvider}"], refineAntdImports: [], - refineMantineImports: [], refineMuiImports: [], - refineChakraImports: [], }, }; diff --git a/refine-nextjs/plugins/auth-provider-google/package.json b/refine-nextjs/plugins/auth-provider-google/package.json index d309411e5..90d1bfc2d 100644 --- a/refine-nextjs/plugins/auth-provider-google/package.json +++ b/refine-nextjs/plugins/auth-provider-google/package.json @@ -1,6 +1,5 @@ { - "dependencies": { - "nookies": "^2.5.2", - "next-auth": "^4.20.1" - } -} \ No newline at end of file + "dependencies": { + "next-auth": "^4.24.5" + } +} diff --git a/refine-nextjs/plugins/auth-provider-google/pages/login/index.tsx b/refine-nextjs/plugins/auth-provider-google/pages/login/index.tsx deleted file mode 100644 index d20615a3d..000000000 --- a/refine-nextjs/plugins/auth-provider-google/pages/login/index.tsx +++ /dev/null @@ -1,330 +0,0 @@ -<%_ if (answers["ui-framework"] === "antd") { _%> -import { ThemedTitleV2 } from "@refinedev/antd"; -import { Button, Typography, Layout, Space } from "antd"; -<%_ } _%> -<%_ if (answers["ui-framework"] === 'mui') { _%> -import Box from "@mui/material/Box"; -import Button from "@mui/material/Button"; -import Container from "@mui/material/Container"; -import Typography from "@mui/material/Typography"; -import { ThemedTitleV2 } from "@refinedev/mui"; -<%_ } _%> -<%_ if (answers["ui-framework"] === 'mantine') { _%> -import { Button, Box, Space, Text } from "@mantine/core"; -import { ThemedTitleV2 } from "@refinedev/mantine"; -<%_ } _%> -<%_ if (answers["ui-framework"] === 'chakra') { _%> -import { Button, Box, Text, VStack } from "@chakra-ui/react"; -import { ThemedTitleV2 } from "@refinedev/chakra-ui"; -<%_ } _%> -import { useLogin } from "@refinedev/core"; - -import { GetServerSideProps } from "next"; -<%_ if (answers[`i18n-${answers["ui-framework"]}`] !== "no") { _%> -import { serverSideTranslations } from "next-i18next/serverSideTranslations"; -import { useTranslate } from "@refinedev/core"; -<%_ } _%> -<%_ if (_app.isAuthProviderCheck) { _%> -import { authProvider } from "src/authProvider"; -<%_ } _%> -<%_ if (selectedSvg && answers["ui-framework"] !== "no" ) { _%> -import { AppIcon } from "src/components/app-icon"; -<%_ } _%> - -<%_ if (_app.isNextAuthCheck) { _%> -import { getServerSession } from "next-auth"; -import { authOptions } from "../api/auth/[...nextauth]"; -<%_ } _%> - - -export default function Login() { - const { mutate: login } = useLogin(); - - <%_ if (answers[`i18n-${answers["ui-framework"]}`] !== "no") { _%> - const t = useTranslate(); - <%_ } _%> - - <%_ if (answers["ui-framework"] === "antd") { _%> - return ( - - - - text="<%= selectedTitle %>" - <%_ } _%> - <%_ if (selectedSvg) { _%> - icon={} - <%_ } _%> - /> - - - Powered by - Google - Google - - - - ); - <%_ } _%> - - <%_ if (answers["ui-framework"] === 'mui') { _%> - return ( - - - - text="<%= selectedTitle %>" - <%_ } _%> - <%_ if (selectedSvg) { _%> - icon={} - <%_ } _%> - /> - - - - Powered by - Google - Google - - - - ); - <%_ } _%> - - <%_ if (answers["ui-framework"] === 'mantine') { _%> - return ( - - - text="<%= selectedTitle %>" - <%_ } _%> - <%_ if (selectedSvg) { _%> - icon={} - <%_ } _%> - /> - - - - - - Powered by - Google - Google - - - ); - <%_ } _%> - - <%_ if (answers["ui-framework"] === 'chakra') { _%> - return ( - - - - text="<%= selectedTitle %>" - <%_ } _%> - <%_ if (selectedSvg) { _%> - icon={} - <%_ } _%> - /> - - - - - Powered by - Google - Google - - - - ); - <%_ } _%> - - <%_ if (answers["ui-framework"] === "no") { _%> - return( -
- -

- Powered by - Google - Google -

-
- ); - <%_ } _%> -} - -Login.noLayout = true; - -export const getServerSideProps: GetServerSideProps<{}> = async (context) => { - - <%_ if (_app.isNextAuthCheck) { _%> - const session = await getServerSession( - context.req, - context.res, - authOptions, - ); - <%_ } _%> - - <%_ if (_app.isAuthProviderCheck) { _%> - const { authenticated, redirectTo } = await authProvider.check(context); - <%_ } _%> - - <%_ if (answers[`i18n-${answers["ui-framework"]}`] !== "no") { _%> - const translateProps = await serverSideTranslations( - context.locale ?? "en", - ["common"], - ); - <%_ } _%> - - <%_ if (_app.isAuthProviderCheck) { _%> - if (authenticated) { - return { - props: {}, - redirect: { - destination: "/", - permanent: false, - }, - }; - } - <%_ } _%> - - <%_ if (_app.isNextAuthCheck) { _%> - if (session) { - return { - props: {}, - redirect: { - destination: "/", - permanent: false, - }, - }; - } - <%_ } _%> - - return { - props: { - <%_ if (answers[`i18n-${answers["ui-framework"]}`] !== "no") { _%> - ...translateProps, - <%_ } _%> - }, - }; -}; - diff --git a/refine-nextjs/plugins/auth-provider-google/pages/_app.tsx b/refine-nextjs/plugins/auth-provider-google/src/app/_refine_context.tsx similarity index 65% rename from refine-nextjs/plugins/auth-provider-google/pages/_app.tsx rename to refine-nextjs/plugins/auth-provider-google/src/app/_refine_context.tsx index 4ca51adef..42f584bb0 100644 --- a/refine-nextjs/plugins/auth-provider-google/pages/_app.tsx +++ b/refine-nextjs/plugins/auth-provider-google/src/app/_refine_context.tsx @@ -1,23 +1,18 @@ +'use client' + import React from "react"; -import { AppProps } from "next/app"; -import type { NextPage } from "next"; import { Refine, GitHubBanner, AuthBindings, <%- (_app.refineImports || []).join("\n,") _%> } from '@refinedev/core'; import { RefineKbar, RefineKbarProvider } from "@refinedev/kbar"; import { SessionProvider, useSession, signOut, signIn } from "next-auth/react"; -import { useRouter } from "next/router"; +import { usePathname } from 'next/navigation' <%_ if (answers["ui-framework"] === 'antd') { _%> import { <%- (_app.refineAntdImports || []).join("\n,") _%> } from '@refinedev/antd'; <%_ } _%> <%_ if (answers["ui-framework"] === 'mui') { _%> import { <%- (_app.refineMuiImports || []).join("\n,") _%> } from '@refinedev/mui'; <%_ } _%> -<%_ if (answers["ui-framework"] === 'mantine') { _%> - import { <%- (_app.refineMantineImports || []).join("\n,") _%> } from '@refinedev/mantine'; -<%_ } _%> -<%_ if (answers["ui-framework"] === 'chakra') { _%> - import { <%- (_app.refineChakraImports || []).join("\n,") _%> } from '@refinedev/chakra-ui'; -<%_ } _%> -import routerProvider, { UnsavedChangesNotifier } from "@refinedev/nextjs-router"; + +import routerProvider from "@refinedev/nextjs-router"; <%- (_app.import || []).join("\n") _%> @@ -32,20 +27,31 @@ import routerProvider, { UnsavedChangesNotifier } from "@refinedev/nextjs-router var bottom = _app.wrapper.map(wrapper => wrapper[1] || "").reverse(); %> -export type NextPageWithLayout

= NextPage & { - noLayout?: boolean; - }; +type RefineContextProps = { + <%_ if (answers["ui-framework"] !== 'no') { _%> + defaultMode?: string; + <%_ } _%> +}; - type AppPropsWithLayout = AppProps & { - Component: NextPageWithLayout; - }; +export const RefineContext = (props: React.PropsWithChildren) => { + return ( + + + + ) + } + +type AppProps = { + <%_ if (answers["ui-framework"] !== 'no') { _%> + defaultMode?: string; + <%_ } _%> +}; - const App = (props: React.PropsWithChildren) => { +const App = (props: React.PropsWithChildren) => { <%- (_app.innerHooks || []).join("\n") %> const { data, status } = useSession(); - const router = useRouter(); - const { to } = router.query; + const to = usePathname() <%- (_app.inner || []).join("\n") %> @@ -75,7 +81,12 @@ export type NextPageWithLayout

= NextPage & { }; }, onError: async (error) => { - console.error(error); + if (error.response?.status === 401) { + return { + logout: true, + }; + } + return { error, }; @@ -108,6 +119,11 @@ export type NextPageWithLayout

= NextPage & { }, }; + + <%_ if (answers["ui-framework"] !== 'no') { _%> + const defaultMode = props?.defaultMode + <%_ } _%> + return ( <> @@ -116,7 +132,7 @@ export type NextPageWithLayout

= NextPage & { - <%_ if (answers["inferencer"] === 'inferencer' || answers["inferencer-headless"] === 'inferencer-headless') { _%> + <%_ if (_app.hasRoutes === true) { _%> resources={[ <%_ if (answers["data-provider"] === 'data-provider-strapi-v4') { _%> { @@ -174,62 +190,9 @@ export type NextPageWithLayout

= NextPage & { > {props.children} - <%- bottom.join("\n") %> ); }; - - -function MyApp({ Component, pageProps: { session, ...pageProps }, }: AppPropsWithLayout): JSX.Element { - const renderComponent = () => { - if (Component.noLayout) { - return ; - } - - <%_ if (answers["ui-framework"] === "no") { _%> - return ( - - ); - <%_ } else {_%> - return ( -

} - <%_ if (answers["ui-framework"] === 'antd') { _%> - Sider={(props) => } - <%_ } _%> - <%_ if (selectedSvg || selectedTitle) { _%> - Title={({ collapsed }) => ( - - text="<%= selectedTitle %>" - <%_ } _%> - <%_ if (selectedSvg) { _%> - icon={} - <%_ } _%> - /> - )} - <%_ } _%> - > - - - ); - <%_ } _%> - }; - - return ( - - {renderComponent()} - - ); -}; - - -<%_ if (answers[`i18n-${answers["ui-framework"]}`] !== 'no') { _%> -export default appWithTranslation(MyApp); -<%_ } else {_%> -export default MyApp; -<%_ } _%> diff --git a/refine-nextjs/plugins/auth-provider-google/pages/api/auth/[...nextauth].ts b/refine-nextjs/plugins/auth-provider-google/src/app/api/auth/[...nextauth]/options.ts similarity index 81% rename from refine-nextjs/plugins/auth-provider-google/pages/api/auth/[...nextauth].ts rename to refine-nextjs/plugins/auth-provider-google/src/app/api/auth/[...nextauth]/options.ts index 06206a305..18be9a69c 100644 --- a/refine-nextjs/plugins/auth-provider-google/pages/api/auth/[...nextauth].ts +++ b/refine-nextjs/plugins/auth-provider-google/src/app/api/auth/[...nextauth]/options.ts @@ -1,7 +1,6 @@ -import NextAuth from "next-auth"; import GoogleProvider from "next-auth/providers/google"; -export const authOptions = { +const authOptions = { // Configure one or more authentication providers providers: [ // !!! Should be stored in .env file. @@ -12,4 +11,5 @@ export const authOptions = { ], secret: `UItTuD1HcGXIj8ZfHUswhYdNd40Lc325R8VlxQPUoR0=`, }; -export default NextAuth(authOptions); + +export default authOptions; diff --git a/refine-nextjs/plugins/auth-provider-google/src/app/api/auth/[...nextauth]/route.ts b/refine-nextjs/plugins/auth-provider-google/src/app/api/auth/[...nextauth]/route.ts new file mode 100644 index 000000000..a79078599 --- /dev/null +++ b/refine-nextjs/plugins/auth-provider-google/src/app/api/auth/[...nextauth]/route.ts @@ -0,0 +1,5 @@ +import NextAuth from "next-auth/next"; +import authOptions from "./options"; + +const auth = NextAuth(authOptions); +export { auth as GET, auth as POST }; diff --git a/refine-nextjs/plugins/auth-provider-google/src/app/layout.tsx b/refine-nextjs/plugins/auth-provider-google/src/app/layout.tsx new file mode 100644 index 000000000..2c0a62343 --- /dev/null +++ b/refine-nextjs/plugins/auth-provider-google/src/app/layout.tsx @@ -0,0 +1,34 @@ +import { Metadata } from "next"; +<%- (_app.nextjsImport || []).join("\n") _%> +import React, { Suspense } from "react"; +import { RefineContext } from "./_refine_context"; + +export const metadata: Metadata = { + title: "Refine", + description: "Generated by create refine app", + icons: { + icon: "/favicon.ico", + }, +}; + +export default function RootLayout({ + children, +}: Readonly<{ + children: React.ReactNode; +}>) { + + <%- (_app.nextjsInner || []).join("\n") %> + + return ( + + + + + > + {children} + + + + + ); +} diff --git a/refine-nextjs/plugins/auth-provider-google/src/app/login/layout.tsx b/refine-nextjs/plugins/auth-provider-google/src/app/login/layout.tsx new file mode 100644 index 000000000..3bde1abb1 --- /dev/null +++ b/refine-nextjs/plugins/auth-provider-google/src/app/login/layout.tsx @@ -0,0 +1,24 @@ +import authOptions from "@app/api/auth/[...nextauth]/options"; +import { getServerSession } from "next-auth/next"; +import { redirect } from "next/navigation"; +import React from "react"; + +export default async function LoginLayout({ + children, +}: React.PropsWithChildren) { + const data = await getData(); + + if (data.session?.user) { + return redirect("/"); + } + + return <>{children}; +} + +async function getData() { + const session = await getServerSession(authOptions); + + return { + session, + }; +} diff --git a/refine-nextjs/plugins/auth-provider-google/src/app/login/page.tsx b/refine-nextjs/plugins/auth-provider-google/src/app/login/page.tsx new file mode 100644 index 000000000..b1fd33c43 --- /dev/null +++ b/refine-nextjs/plugins/auth-provider-google/src/app/login/page.tsx @@ -0,0 +1,140 @@ +"use client" + +<%_ if (answers["ui-framework"] === "antd") { _%> +import { ThemedTitleV2 } from "@refinedev/antd"; +import { Button, Typography, Layout, Space } from "antd"; +<%_ } _%> +<%_ if (answers["ui-framework"] === 'mui') { _%> +import Box from "@mui/material/Box"; +import Button from "@mui/material/Button"; +import Container from "@mui/material/Container"; +import Typography from "@mui/material/Typography"; +import { ThemedTitleV2 } from "@refinedev/mui"; +<%_ } _%> +import { useLogin } from "@refinedev/core"; +<%_ if (selectedSvg && answers["ui-framework"] !== "no" ) { _%> +import { AppIcon } from "src/components/app-icon"; +<%_ } _%> + + +export default function Login() { + const { mutate: login } = useLogin(); + + <%_ if (answers["ui-framework"] === "antd") { _%> + return ( + + + + text="<%= selectedTitle %>" + <%_ } _%> + <%_ if (selectedSvg) { _%> + icon={} + <%_ } _%> + /> + + + Powered by + Google + Google + + + + ); + <%_ } _%> + + <%_ if (answers["ui-framework"] === 'mui') { _%> + return ( + + + + text="<%= selectedTitle %>" + <%_ } _%> + <%_ if (selectedSvg) { _%> + icon={} + <%_ } _%> + /> + + + + Powered by + Google + Google + + + + ); + <%_ } _%> + + <%_ if (answers["ui-framework"] === "no") { _%> + return( +
+ +

+ Powered by + Google + Google +

+
+ ); + <%_ } _%> +} diff --git a/refine-nextjs/plugins/auth-provider-keycloak/extend.js b/refine-nextjs/plugins/auth-provider-keycloak/extend.js index 70dbfd0aa..efbb72d46 100644 --- a/refine-nextjs/plugins/auth-provider-keycloak/extend.js +++ b/refine-nextjs/plugins/auth-provider-keycloak/extend.js @@ -1,11 +1,8 @@ const base = { _app: { - localImport: ['import { authProvider } from "src/authProvider";'], refineProps: ["authProvider={authProvider}"], refineAntdImports: [], - refineMantineImports: [], refineMuiImports: [], - refineChakraImports: [], }, }; diff --git a/refine-nextjs/plugins/auth-provider-keycloak/package.json b/refine-nextjs/plugins/auth-provider-keycloak/package.json index d309411e5..90d1bfc2d 100644 --- a/refine-nextjs/plugins/auth-provider-keycloak/package.json +++ b/refine-nextjs/plugins/auth-provider-keycloak/package.json @@ -1,6 +1,5 @@ { - "dependencies": { - "nookies": "^2.5.2", - "next-auth": "^4.20.1" - } -} \ No newline at end of file + "dependencies": { + "next-auth": "^4.24.5" + } +} diff --git a/refine-nextjs/plugins/auth-provider-keycloak/pages/login/index.tsx b/refine-nextjs/plugins/auth-provider-keycloak/pages/login/index.tsx deleted file mode 100644 index 7234ef040..000000000 --- a/refine-nextjs/plugins/auth-provider-keycloak/pages/login/index.tsx +++ /dev/null @@ -1,333 +0,0 @@ -<%_ if (answers["ui-framework"] === "antd") { _%> -import { ThemedTitleV2 } from "@refinedev/antd"; -import { Button, Typography, Layout, Space } from "antd"; -<%_ } _%> -<%_ if (answers["ui-framework"] === 'mui') { _%> -import Box from "@mui/material/Box"; -import Button from "@mui/material/Button"; -import Container from "@mui/material/Container"; -import Typography from "@mui/material/Typography"; -import { ThemedTitleV2 } from "@refinedev/mui"; -<%_ } _%> -<%_ if (answers["ui-framework"] === 'mantine') { _%> -import { Button, Box, Space, Text } from "@mantine/core"; -import { ThemedTitleV2 } from "@refinedev/mantine"; -<%_ } _%> -<%_ if (answers["ui-framework"] === 'chakra') { _%> -import { Button, Box, Text, VStack } from "@chakra-ui/react"; -import { ThemedTitleV2 } from "@refinedev/chakra-ui"; -<%_ } _%> -import { useLogin } from "@refinedev/core"; - -import { GetServerSideProps } from "next"; -<%_ if (answers[`i18n-${answers["ui-framework"]}`] !== "no") { _%> -import { serverSideTranslations } from "next-i18next/serverSideTranslations"; -import { useTranslate } from "@refinedev/core"; -<%_ } _%> -<%_ if (_app.isAuthProviderCheck) { _%> -import { authProvider } from "src/authProvider"; -<%_ } _%> -<%_ if (selectedSvg && answers["ui-framework"] !== "no" ) { _%> -import { AppIcon } from "src/components/app-icon"; -<%_ } _%> - -<%_ if (_app.isNextAuthCheck) { _%> -import { getServerSession } from "next-auth"; -import { authOptions } from "../api/auth/[...nextauth]"; -<%_ } _%> - - -export default function Login() { - const { mutate: login } = useLogin(); - - <%_ if (answers[`i18n-${answers["ui-framework"]}`] !== "no") { _%> - const t = useTranslate(); - <%_ } _%> - - - <%_ if (answers["ui-framework"] === "antd") { _%> - return ( - - - - text="<%= selectedTitle %>" - <%_ } _%> - <%_ if (selectedSvg) { _%> - icon={} - <%_ } _%> - /> - - - Powered by - Keycloak - Keycloak - - - - ); - <%_ } _%> - - <%_ if (answers["ui-framework"] === 'mui') { _%> - return ( - - - - text="<%= selectedTitle %>" - <%_ } _%> - <%_ if (selectedSvg) { _%> - icon={} - <%_ } _%> - /> - - - - Powered by - Keycloak - Keycloak - - - - ); - <%_ } _%> - - <%_ if (answers["ui-framework"] === 'mantine') { _%> - return ( - - - text="<%= selectedTitle %>" - <%_ } _%> - <%_ if (selectedSvg) { _%> - icon={} - <%_ } _%> - /> - - - - - - Powered by - Keycloak - Keycloak - - - ); - <%_ } _%> - - <%_ if (answers["ui-framework"] === 'chakra') { _%> - return ( - - - - text="<%= selectedTitle %>" - <%_ } _%> - <%_ if (selectedSvg) { _%> - icon={} - <%_ } _%> - /> - - - - - Powered by - Keycloak - Keycloak - - - - ); - <%_ } _%> - - <%_ if (answers["ui-framework"] === "no") { _%> - return( -
- -

- Powered by - Keycloak - Keycloak -

-
- ); - <%_ } _%> -} - -Login.noLayout = true; - -export const getServerSideProps: GetServerSideProps<{}> = async (context) => { - - <%_ if (_app.isNextAuthCheck) { _%> - const session = await getServerSession( - context.req, - context.res, - authOptions, - ); - <%_ } _%> - - <%_ if (_app.isAuthProviderCheck) { _%> - const { authenticated, redirectTo } = await authProvider.check(context); - <%_ } _%> - - <%_ if (answers[`i18n-${answers["ui-framework"]}`] !== "no") { _%> - const translateProps = await serverSideTranslations( - context.locale ?? "en", - ["common"], - ); - <%_ } _%> - - <%_ if (_app.isAuthProviderCheck) { _%> - if (authenticated) { - return { - props: {}, - redirect: { - destination: "/", - permanent: false, - }, - }; - } - <%_ } _%> - - <%_ if (_app.isNextAuthCheck) { _%> - if (session) { - return { - props: {}, - redirect: { - destination: "/", - permanent: false, - }, - }; - } - <%_ } _%> - - return { - props: { - <%_ if (answers[`i18n-${answers["ui-framework"]}`] !== "no") { _%> - ...translateProps, - <%_ } _%> - }, - }; -}; - diff --git a/refine-nextjs/plugins/auth-provider-keycloak/pages/_app.tsx b/refine-nextjs/plugins/auth-provider-keycloak/src/app/_refine_context.tsx similarity index 65% rename from refine-nextjs/plugins/auth-provider-keycloak/pages/_app.tsx rename to refine-nextjs/plugins/auth-provider-keycloak/src/app/_refine_context.tsx index 54520c4e3..0661a4d81 100644 --- a/refine-nextjs/plugins/auth-provider-keycloak/pages/_app.tsx +++ b/refine-nextjs/plugins/auth-provider-keycloak/src/app/_refine_context.tsx @@ -1,23 +1,18 @@ +'use client' + import React from "react"; -import { AppProps } from "next/app"; -import type { NextPage } from "next"; import { Refine, GitHubBanner, AuthBindings, <%- (_app.refineImports || []).join("\n,") _%> } from '@refinedev/core'; import { RefineKbar, RefineKbarProvider } from "@refinedev/kbar"; import { SessionProvider, useSession, signOut, signIn } from "next-auth/react"; -import { useRouter } from "next/router"; +import { usePathname } from 'next/navigation' <%_ if (answers["ui-framework"] === 'antd') { _%> import { <%- (_app.refineAntdImports || []).join("\n,") _%> } from '@refinedev/antd'; <%_ } _%> <%_ if (answers["ui-framework"] === 'mui') { _%> import { <%- (_app.refineMuiImports || []).join("\n,") _%> } from '@refinedev/mui'; <%_ } _%> -<%_ if (answers["ui-framework"] === 'mantine') { _%> - import { <%- (_app.refineMantineImports || []).join("\n,") _%> } from '@refinedev/mantine'; -<%_ } _%> -<%_ if (answers["ui-framework"] === 'chakra') { _%> - import { <%- (_app.refineChakraImports || []).join("\n,") _%> } from '@refinedev/chakra-ui'; -<%_ } _%> -import routerProvider, { UnsavedChangesNotifier } from "@refinedev/nextjs-router"; + +import routerProvider from "@refinedev/nextjs-router"; <%- (_app.import || []).join("\n") _%> @@ -32,20 +27,31 @@ import routerProvider, { UnsavedChangesNotifier } from "@refinedev/nextjs-router var bottom = _app.wrapper.map(wrapper => wrapper[1] || "").reverse(); %> -export type NextPageWithLayout

= NextPage & { - noLayout?: boolean; - }; +type RefineContextProps = { + <%_ if (answers["ui-framework"] !== 'no') { _%> + defaultMode?: string; + <%_ } _%> +}; - type AppPropsWithLayout = AppProps & { - Component: NextPageWithLayout; - }; +export const RefineContext = (props: React.PropsWithChildren) => { + return ( + + + + ) + } + +type AppProps = { + <%_ if (answers["ui-framework"] !== 'no') { _%> + defaultMode?: string; + <%_ } _%> +}; - const App = (props: React.PropsWithChildren) => { +const App = (props: React.PropsWithChildren) => { <%- (_app.innerHooks || []).join("\n") %> const { data, status } = useSession(); - const router = useRouter(); - const { to } = router.query; + const to = usePathname() <%- (_app.inner || []).join("\n") %> @@ -75,7 +81,12 @@ export type NextPageWithLayout

= NextPage & { }; }, onError: async (error) => { - console.error(error); + if (error.response?.status === 401) { + return { + logout: true, + }; + } + return { error, }; @@ -108,6 +119,11 @@ export type NextPageWithLayout

= NextPage & { }, }; + + <%_ if (answers["ui-framework"] !== 'no') { _%> + const defaultMode = props?.defaultMode + <%_ } _%> + return ( <> @@ -116,7 +132,7 @@ export type NextPageWithLayout

= NextPage & { - <%_ if (answers["inferencer"] === 'inferencer' || answers["inferencer-headless"] === 'inferencer-headless') { _%> + <%_ if (_app.hasRoutes === true) { _%> resources={[ <%_ if (answers["data-provider"] === 'data-provider-strapi-v4') { _%> { @@ -174,62 +190,9 @@ export type NextPageWithLayout

= NextPage & { > {props.children} - <%- bottom.join("\n") %> ); }; - - -function MyApp({ Component, pageProps: { session, ...pageProps }, }: AppPropsWithLayout): JSX.Element { - const renderComponent = () => { - if (Component.noLayout) { - return ; - } - - <%_ if (answers["ui-framework"] === "no") { _%> - return ( - - ); - <%_ } else {_%> - return ( -

} - <%_ if (answers["ui-framework"] === 'antd') { _%> - Sider={(props) => } - <%_ } _%> - <%_ if (selectedSvg || selectedTitle) { _%> - Title={({ collapsed }) => ( - - text="<%= selectedTitle %>" - <%_ } _%> - <%_ if (selectedSvg) { _%> - icon={} - <%_ } _%> - /> - )} - <%_ } _%> - > - - - ); - <%_ } _%> - }; - - return ( - - {renderComponent()} - - ); -}; - - -<%_ if (answers[`i18n-${answers["ui-framework"]}`] !== 'no') { _%> -export default appWithTranslation(MyApp); -<%_ } else {_%> -export default MyApp; -<%_ } _%> diff --git a/refine-nextjs/plugins/auth-provider-keycloak/pages/api/auth/[...nextauth].ts b/refine-nextjs/plugins/auth-provider-keycloak/src/app/api/auth/[...nextauth]/options.ts similarity index 88% rename from refine-nextjs/plugins/auth-provider-keycloak/pages/api/auth/[...nextauth].ts rename to refine-nextjs/plugins/auth-provider-keycloak/src/app/api/auth/[...nextauth]/options.ts index d5f675877..5bf455407 100644 --- a/refine-nextjs/plugins/auth-provider-keycloak/pages/api/auth/[...nextauth].ts +++ b/refine-nextjs/plugins/auth-provider-keycloak/src/app/api/auth/[...nextauth]/options.ts @@ -1,7 +1,6 @@ -import NextAuth from "next-auth"; import KeycloakProvider from "next-auth/providers/keycloak"; -export const authOptions = { +const authOptions = { // Configure one or more authentication providers providers: [ // !!! Should be stored in .env file. @@ -21,4 +20,5 @@ export const authOptions = { ], secret: `UItTuD1HcGXIj8ZfHUswhYdNd40Lc325R8VlxQPUoR0=`, }; -export default NextAuth(authOptions); + +export default authOptions; diff --git a/refine-nextjs/plugins/auth-provider-keycloak/src/app/api/auth/[...nextauth]/route.ts b/refine-nextjs/plugins/auth-provider-keycloak/src/app/api/auth/[...nextauth]/route.ts new file mode 100644 index 000000000..a79078599 --- /dev/null +++ b/refine-nextjs/plugins/auth-provider-keycloak/src/app/api/auth/[...nextauth]/route.ts @@ -0,0 +1,5 @@ +import NextAuth from "next-auth/next"; +import authOptions from "./options"; + +const auth = NextAuth(authOptions); +export { auth as GET, auth as POST }; diff --git a/refine-nextjs/plugins/auth-provider-keycloak/src/app/layout.tsx b/refine-nextjs/plugins/auth-provider-keycloak/src/app/layout.tsx new file mode 100644 index 000000000..2c0a62343 --- /dev/null +++ b/refine-nextjs/plugins/auth-provider-keycloak/src/app/layout.tsx @@ -0,0 +1,34 @@ +import { Metadata } from "next"; +<%- (_app.nextjsImport || []).join("\n") _%> +import React, { Suspense } from "react"; +import { RefineContext } from "./_refine_context"; + +export const metadata: Metadata = { + title: "Refine", + description: "Generated by create refine app", + icons: { + icon: "/favicon.ico", + }, +}; + +export default function RootLayout({ + children, +}: Readonly<{ + children: React.ReactNode; +}>) { + + <%- (_app.nextjsInner || []).join("\n") %> + + return ( + + + + + > + {children} + + + + + ); +} diff --git a/refine-nextjs/plugins/auth-provider-keycloak/src/app/login/layout.tsx b/refine-nextjs/plugins/auth-provider-keycloak/src/app/login/layout.tsx new file mode 100644 index 000000000..3bde1abb1 --- /dev/null +++ b/refine-nextjs/plugins/auth-provider-keycloak/src/app/login/layout.tsx @@ -0,0 +1,24 @@ +import authOptions from "@app/api/auth/[...nextauth]/options"; +import { getServerSession } from "next-auth/next"; +import { redirect } from "next/navigation"; +import React from "react"; + +export default async function LoginLayout({ + children, +}: React.PropsWithChildren) { + const data = await getData(); + + if (data.session?.user) { + return redirect("/"); + } + + return <>{children}; +} + +async function getData() { + const session = await getServerSession(authOptions); + + return { + session, + }; +} diff --git a/refine-nextjs/plugins/auth-provider-keycloak/src/app/login/page.tsx b/refine-nextjs/plugins/auth-provider-keycloak/src/app/login/page.tsx new file mode 100644 index 000000000..2cca7d6ab --- /dev/null +++ b/refine-nextjs/plugins/auth-provider-keycloak/src/app/login/page.tsx @@ -0,0 +1,141 @@ +"use client" + +<%_ if (answers["ui-framework"] === "antd") { _%> +import { ThemedTitleV2 } from "@refinedev/antd"; +import { Button, Typography, Layout, Space } from "antd"; +<%_ } _%> +<%_ if (answers["ui-framework"] === 'mui') { _%> +import Box from "@mui/material/Box"; +import Button from "@mui/material/Button"; +import Container from "@mui/material/Container"; +import Typography from "@mui/material/Typography"; +import { ThemedTitleV2 } from "@refinedev/mui"; +<%_ } _%> +import { useLogin } from "@refinedev/core"; + +<%_ if (selectedSvg && answers["ui-framework"] !== "no" ) { _%> +import { AppIcon } from "src/components/app-icon"; +<%_ } _%> + +export default function Login() { + const { mutate: login } = useLogin(); + + <%_ if (answers["ui-framework"] === "antd") { _%> + return ( + + + + text="<%= selectedTitle %>" + <%_ } _%> + <%_ if (selectedSvg) { _%> + icon={} + <%_ } _%> + /> + + + Powered by + Keycloak + Keycloak + + + + ); + <%_ } _%> + + <%_ if (answers["ui-framework"] === 'mui') { _%> + return ( + + + + text="<%= selectedTitle %>" + <%_ } _%> + <%_ if (selectedSvg) { _%> + icon={} + <%_ } _%> + /> + + + + Powered by + Keycloak + Keycloak + + + + ); + <%_ } _%> + + <%_ if (answers["ui-framework"] === "no") { _%> + return( +
+ +

+ Powered by + Keycloak + Keycloak +

+
+ ); + <%_ } _%> +} diff --git a/refine-nextjs/plugins/chakra/extend.js b/refine-nextjs/plugins/chakra/extend.js deleted file mode 100644 index 838d215d5..000000000 --- a/refine-nextjs/plugins/chakra/extend.js +++ /dev/null @@ -1,35 +0,0 @@ -const base = { - _app: { - refineProps: ["notificationProvider={notificationProvider}"], - import: [`import { ChakraProvider } from "@chakra-ui/react";`], - refineChakraImports: [ - "notificationProvider", - "RefineThemes", - "ThemedLayoutV2", - ], - localImport: [`import { Header } from "@components/header"`], - }, -}; - -module.exports = { - extend(answers) { - const selectedTheme = answers["theme"] ? answers["theme"] : "Blue"; - - return { - ...base, - _app: { - ...base._app, - wrapper: [ - [ - "{/* You can change the theme colors here. example: theme={RefineThemes.Magenta} */}", - "", - ], - [ - ``, - "", - ], - ], - }, - }; - }, -}; diff --git a/refine-nextjs/plugins/chakra/meta.json b/refine-nextjs/plugins/chakra/meta.json deleted file mode 100644 index 454e96c88..000000000 --- a/refine-nextjs/plugins/chakra/meta.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "name": "Chakra UI", - "url": "https://refine.dev/docs/" -} diff --git a/refine-nextjs/plugins/chakra/package.json b/refine-nextjs/plugins/chakra/package.json deleted file mode 100644 index afd930707..000000000 --- a/refine-nextjs/plugins/chakra/package.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "dependencies": { - "@refinedev/chakra-ui": "^2.27.1", - "@refinedev/react-hook-form": "^4.8.13", - "@refinedev/react-table": "^5.6.5", - "@tabler/icons": "^1.1.0", - "@chakra-ui/react": "^2.5.1" - } -} diff --git a/refine-nextjs/plugins/chakra/pages/_document.tsx b/refine-nextjs/plugins/chakra/pages/_document.tsx deleted file mode 100644 index eecf6a3ec..000000000 --- a/refine-nextjs/plugins/chakra/pages/_document.tsx +++ /dev/null @@ -1,16 +0,0 @@ -import { Html, Head, Main, NextScript } from 'next/document' -import {refineTheme} from '@refinedev/chakra-ui' -import {ColorModeScript} from '@chakra-ui/react' - -export default function Document() { - return ( - - - - -
- - - - ) -} \ No newline at end of file diff --git a/refine-nextjs/plugins/chakra/src/components/header/index.tsx b/refine-nextjs/plugins/chakra/src/components/header/index.tsx deleted file mode 100644 index 63575ced9..000000000 --- a/refine-nextjs/plugins/chakra/src/components/header/index.tsx +++ /dev/null @@ -1,92 +0,0 @@ -import { - Avatar, - Box, - BoxProps, - HStack, - Icon, - IconButton, - Text, - useColorMode, - useColorModeValue, -} from "@chakra-ui/react"; -import { - HamburgerMenu, - RefineThemedLayoutV2HeaderProps, -} from "@refinedev/chakra-ui"; -import { useGetIdentity } from "@refinedev/core"; -import { IconMoon, IconSun } from "@tabler/icons"; -import React from "react"; - -type IUser = { - id: number; - name: string; - avatar: string; -}; - -export const Header: React.FC = ({ - sticky, -}) => { - const { data: user } = useGetIdentity(); - - const { colorMode, toggleColorMode } = useColorMode(); - - const bgColor = useColorModeValue( - "refine.header.bg.light", - "refine.header.bg.dark", - ); - - let stickyProps: BoxProps = {}; - if (sticky) { - stickyProps = { - position: "sticky", - top: 0, - zIndex: 1, - }; - } - - return ( - - - - - - - {(user?.avatar || user?.name) && ( - - {user?.name && ( - - {user.name} - - )} - - - )} - - - ); -}; diff --git a/refine-nextjs/plugins/data-provider-airtable/extend.js b/refine-nextjs/plugins/data-provider-airtable/extend.js index 3b6c23092..8a43af398 100644 --- a/refine-nextjs/plugins/data-provider-airtable/extend.js +++ b/refine-nextjs/plugins/data-provider-airtable/extend.js @@ -1,14 +1,11 @@ const base = { _app: { - import: [`import dataProvider from "@refinedev/airtable";`], - afterImport: [ - `const API_TOKEN = "keyI18pnBeEMfPAIb";`, - `const BASE_ID = "appKYl1H4k9g73sBT";`, - "", - ], - refineProps: ["dataProvider={dataProvider(API_TOKEN, BASE_ID)}"], + import: [`import { dataProvider } from "@providers/data-provider";`], + afterImport: [], + refineProps: ["dataProvider={dataProvider}"], }, }; + module.exports = { extend() { return base; diff --git a/refine-nextjs/plugins/data-provider-airtable/src/providers/data-provider/index.ts b/refine-nextjs/plugins/data-provider-airtable/src/providers/data-provider/index.ts new file mode 100644 index 000000000..5cd436ab6 --- /dev/null +++ b/refine-nextjs/plugins/data-provider-airtable/src/providers/data-provider/index.ts @@ -0,0 +1,8 @@ +"use client"; + +import airtable from "@refinedev/airtable"; + +const API_TOKEN = "keyI18pnBeEMfPAIb"; +const BASE_ID = "appKYl1H4k9g73sBT"; + +export const dataProvider = airtable(API_TOKEN, BASE_ID); diff --git a/refine-nextjs/plugins/data-provider-altogic/extend.js b/refine-nextjs/plugins/data-provider-altogic/extend.js index 699a0a6a9..671dd6407 100644 --- a/refine-nextjs/plugins/data-provider-altogic/extend.js +++ b/refine-nextjs/plugins/data-provider-altogic/extend.js @@ -1,20 +1,20 @@ const base = { - _app: { - refineImports: [`HttpError`], - import: [ - `import dataProvider from "@refinedev/altogic";`, - `import axios from "axios";`, - ], - afterImport: [ - `const API_URL = "https://dev001.na-dev-engine.altogic.com";`, - `const YOUR_SECRET_API_KEY = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbnZJZCI6IjYxMzczZGVkMjQ5NWMzMDAxOTliZTAxNiIsImtleUlkIjoiNjEzNzNlMzYyNDk1YzMwMDE5OWJlMDJkIiwiaWF0IjoxNjMxMDEwMzU4LCJleHAiOjI0OTUwMTAzNTh9.2fL28Bzd97mqfAvcsTrYj1mZ_hqf3WRnr2DOtV3lsc0";`, - "", - `const axiosInstance = axios.create();`, - `axiosInstance.defaults.headers.common = { + _app: { + refineImports: [`HttpError`], + import: [ + `import dataProvider from "@refinedev/altogic";`, + `import axios from "axios";`, + ], + afterImport: [ + `const API_URL = "https://dev001.na-dev-engine.altogic.com";`, + `const YOUR_SECRET_API_KEY = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbnZJZCI6IjYxMzczZGVkMjQ5NWMzMDAxOTliZTAxNiIsImtleUlkIjoiNjEzNzNlMzYyNDk1YzMwMDE5OWJlMDJkIiwiaWF0IjoxNjMxMDEwMzU4LCJleHAiOjI0OTUwMTAzNTh9.2fL28Bzd97mqfAvcsTrYj1mZ_hqf3WRnr2DOtV3lsc0";`, + "", + `const axiosInstance = axios.create();`, + `axiosInstance.defaults.headers.common = { Authorization: YOUR_SECRET_API_KEY };`, - "", - `axiosInstance.interceptors.response.use( + "", + `axiosInstance.interceptors.response.use( (response) => { return response; }, @@ -28,13 +28,13 @@ const base = { return Promise.reject(customError); } );`, - "", - ], - refineProps: ["dataProvider={dataProvider(API_URL, axiosInstance)}"], - }, + "", + ], + refineProps: ["dataProvider={dataProvider(API_URL, axiosInstance)}"], + }, }; module.exports = { - extend() { - return base; - }, + extend() { + return base; + }, }; diff --git a/refine-nextjs/plugins/data-provider-altogic/src/providers/data-provider/index.ts b/refine-nextjs/plugins/data-provider-altogic/src/providers/data-provider/index.ts new file mode 100644 index 000000000..5cd436ab6 --- /dev/null +++ b/refine-nextjs/plugins/data-provider-altogic/src/providers/data-provider/index.ts @@ -0,0 +1,8 @@ +"use client"; + +import airtable from "@refinedev/airtable"; + +const API_TOKEN = "keyI18pnBeEMfPAIb"; +const BASE_ID = "appKYl1H4k9g73sBT"; + +export const dataProvider = airtable(API_TOKEN, BASE_ID); diff --git a/refine-nextjs/plugins/data-provider-appwrite/extend.js b/refine-nextjs/plugins/data-provider-appwrite/extend.js index e78964023..6f53d905b 100644 --- a/refine-nextjs/plugins/data-provider-appwrite/extend.js +++ b/refine-nextjs/plugins/data-provider-appwrite/extend.js @@ -1,24 +1,17 @@ const base = { _app: { - import: [ - `import { dataProvider, liveProvider } from "@refinedev/appwrite";`, - ], + import: [], localImport: [ - `import { authProvider } from "src/authProvider";`, - `import { appwriteClient } from "src/utility";`, + 'import { authProvider } from "@providers/auth-provider";', + 'import { dataProvider, liveProvider } from "@providers/data-provider";', ], refineProps: [ - `dataProvider={dataProvider(appwriteClient, { - databaseId: "database", - })}`, - `liveProvider={liveProvider(appwriteClient, { - databaseId: "database", - })}`, + `dataProvider={dataProvider}`, + `liveProvider={liveProvider}`, `authProvider={authProvider}`, ], refineOptions: [`liveMode: "auto",`], refineAntdImports: [], - refineMantineImports: [], refineMuiImports: [], }, }; diff --git a/refine-nextjs/plugins/data-provider-appwrite/package.json b/refine-nextjs/plugins/data-provider-appwrite/package.json index b5a42d2ce..0811c7637 100644 --- a/refine-nextjs/plugins/data-provider-appwrite/package.json +++ b/refine-nextjs/plugins/data-provider-appwrite/package.json @@ -1,9 +1,12 @@ { "dependencies": { "@refinedev/appwrite": "^6.4.6", - "uuid": "^9.0.0" + "uuid": "^9.0.0", + "js-cookie": "^3.0.5" }, "devDependencies": { - "@types/uuid": "^9.0.2" + "@types/uuid": "^9.0.2", + "@types/js-cookie": "^3.0.6" } -} \ No newline at end of file +} + diff --git a/refine-nextjs/plugins/data-provider-appwrite/pages/forgot-password/index.tsx b/refine-nextjs/plugins/data-provider-appwrite/pages/forgot-password/index.tsx deleted file mode 100644 index 18e230c29..000000000 --- a/refine-nextjs/plugins/data-provider-appwrite/pages/forgot-password/index.tsx +++ /dev/null @@ -1,77 +0,0 @@ -<%_ if (answers["ui-framework"] === 'antd') { _%> - import { AuthPage, ThemedTitleV2 } from "@refinedev/antd"; -<%_ } _%> -<%_ if (answers["ui-framework"] === 'mui') { _%> - import { AuthPage, ThemedTitleV2 } from "@refinedev/mui"; -<%_ } _%> -<%_ if (answers["ui-framework"] === 'mantine') { _%> - import { AuthPage, ThemedTitleV2 } from "@refinedev/mantine"; -<%_ } _%> -<%_ if (answers["ui-framework"] === 'chakra') { _%> - import { AuthPage, ThemedTitleV2 } from "@refinedev/chakra-ui"; -<%_ } _%> -<%_ if (answers[`ui-framework`] === "no") { _%> - import { AuthPage } from "@refinedev/core"; -<%_ } _%> - -import { GetServerSideProps } from "next"; -<%_ if (answers[`i18n-${answers["ui-framework"]}`] !== "no") { _%> -import { serverSideTranslations } from "next-i18next/serverSideTranslations"; -<%_ } _%> - -import { authProvider } from "src/authProvider"; - -<%_ if (selectedSvg && answers["ui-framework"] !== "no" ) { _%> -import { AppIcon } from "src/components/app-icon"; -<%_ } _%> - -export default function ForgotPassword() { - return ( - - title={( - - text="<%= selectedTitle %>" - <%_ } _%> - <%_ if (selectedSvg) { _%> - icon={} - <%_ } _%> - /> - )} - <%_ } _%> - /> - ); -} - -ForgotPassword.noLayout = true; - -export const getServerSideProps: GetServerSideProps<{}> = async (context) => { - const { authenticated } = await authProvider.check(context); - - <%_ if (answers[`i18n-${answers["ui-framework"]}`] !== "no") { _%> - const translateProps = await serverSideTranslations( - context.locale ?? "en", - ["common"], - ); - <%_ } _%> - - if (authenticated) { - return { - props: {}, - redirect: { - destination: `/`, - permanent: false, - }, - }; - } - - return { - props: { - <%_ if (answers[`i18n-${answers["ui-framework"]}`] !== "no") { _%> - ...translateProps, - <%_ } _%> - } - } -}; diff --git a/refine-nextjs/plugins/data-provider-appwrite/pages/login/index.tsx b/refine-nextjs/plugins/data-provider-appwrite/pages/login/index.tsx deleted file mode 100644 index fef7b6bc7..000000000 --- a/refine-nextjs/plugins/data-provider-appwrite/pages/login/index.tsx +++ /dev/null @@ -1,80 +0,0 @@ -<%_ if (answers["ui-framework"] === 'antd') { _%> - import { AuthPage, ThemedTitleV2 } from "@refinedev/antd"; -<%_ } _%> -<%_ if (answers["ui-framework"] === 'mui') { _%> - import { AuthPage, ThemedTitleV2 } from "@refinedev/mui"; -<%_ } _%> -<%_ if (answers["ui-framework"] === 'mantine') { _%> - import { AuthPage, ThemedTitleV2 } from "@refinedev/mantine"; -<%_ } _%> -<%_ if (answers["ui-framework"] === 'chakra') { _%> - import { AuthPage, ThemedTitleV2 } from "@refinedev/chakra-ui"; -<%_ } _%> -<%_ if (answers[`ui-framework`] === "no") { _%> - import { AuthPage } from "@refinedev/core"; -<%_ } _%> - -import { GetServerSideProps } from "next"; -<%_ if (answers[`i18n-${answers["ui-framework"]}`] !== "no") { _%> -import { serverSideTranslations } from "next-i18next/serverSideTranslations"; -<%_ } _%> - -import { authProvider } from "src/authProvider"; - -<%_ if (selectedSvg && answers["ui-framework"] !== "no" ) { _%> -import { AppIcon } from "src/components/app-icon"; -<%_ } _%> - -export default function Login() { - return ( - - <%_ if ((selectedSvg || selectedTitle) && answers["ui-framework"] !== "no") { _%> - title={( - - text="<%= selectedTitle %>" - <%_ } _%> - <%_ if (selectedSvg) { _%> - icon={} - <%_ } _%> - /> - )} - <%_ } _%> - /> - ); -} - -Login.noLayout = true; - -export const getServerSideProps: GetServerSideProps<{}> = async (context) => { - const { authenticated } = await authProvider.check(context); - - <%_ if (answers[`i18n-${answers["ui-framework"]}`] !== "no") { _%> - const translateProps = await serverSideTranslations( - context.locale ?? "en", - ["common"], - ); - <%_ } _%> - - if (authenticated) { - return { - props: {}, - redirect: { - destination: `/`, - permanent: false, - }, - }; - } - - return { - props: { - <%_ if (answers[`i18n-${answers["ui-framework"]}`] !== "no") { _%> - ...translateProps, - <%_ } _%> - } - } -}; - diff --git a/refine-nextjs/plugins/data-provider-appwrite/pages/register/index.tsx b/refine-nextjs/plugins/data-provider-appwrite/pages/register/index.tsx deleted file mode 100644 index a31f02291..000000000 --- a/refine-nextjs/plugins/data-provider-appwrite/pages/register/index.tsx +++ /dev/null @@ -1,77 +0,0 @@ -<%_ if (answers["ui-framework"] === 'antd') { _%> - import { AuthPage, ThemedTitleV2 } from "@refinedev/antd"; -<%_ } _%> -<%_ if (answers["ui-framework"] === 'mui') { _%> - import { AuthPage, ThemedTitleV2 } from "@refinedev/mui"; -<%_ } _%> -<%_ if (answers["ui-framework"] === 'mantine') { _%> - import { AuthPage, ThemedTitleV2 } from "@refinedev/mantine"; -<%_ } _%> -<%_ if (answers["ui-framework"] === 'chakra') { _%> - import { AuthPage, ThemedTitleV2 } from "@refinedev/chakra-ui"; -<%_ } _%> -<%_ if (answers[`ui-framework`] === "no") { _%> - import { AuthPage } from "@refinedev/core"; -<%_ } _%> - -import { GetServerSideProps } from "next"; -<%_ if (answers[`i18n-${answers["ui-framework"]}`] !== "no") { _%> -import { serverSideTranslations } from "next-i18next/serverSideTranslations"; -<%_ } _%> - -import { authProvider } from "src/authProvider"; - -<%_ if (selectedSvg && answers["ui-framework"] !== "no" ) { _%> - import { AppIcon } from "src/components/app-icon"; -<%_ } _%> - -export default function Register() { - return ( - - title={( - - text="<%= selectedTitle %>" - <%_ } _%> - <%_ if (selectedSvg) { _%> - icon={} - <%_ } _%> - /> - )} - <%_ } _%> - /> - ); -} - -Register.noLayout = true; - -export const getServerSideProps: GetServerSideProps<{}> = async (context) => { - const { authenticated } = await authProvider.check(context); - - <%_ if (answers[`i18n-${answers["ui-framework"]}`] !== "no") { _%> - const translateProps = await serverSideTranslations( - context.locale ?? "en", - ["common"], - ); - <%_ } _%> - - if (authenticated) { - return { - props: {}, - redirect: { - destination: `/`, - permanent: false, - }, - }; - } - - return { - props: { - <%_ if (answers[`i18n-${answers["ui-framework"]}`] !== "no") { _%> - ...translateProps, - <%_ } _%> - } - } -}; diff --git a/refine-nextjs/plugins/data-provider-appwrite/src/app/forgot-password/page.tsx b/refine-nextjs/plugins/data-provider-appwrite/src/app/forgot-password/page.tsx new file mode 100644 index 000000000..c2b0061f5 --- /dev/null +++ b/refine-nextjs/plugins/data-provider-appwrite/src/app/forgot-password/page.tsx @@ -0,0 +1,24 @@ +import { AuthPage } from "@components/auth-page"; +import { authProviderServer } from "@providers/auth-provider"; +import { redirect } from "next/navigation"; + +export default async function ForgotPassword() { + const data = await getData(); + + if (data.authenticated) { + redirect(data?.redirectTo || "/"); + } + + return ; +} + +async function getData() { + const { authenticated, redirectTo, error } = + await authProviderServer.check(); + + return { + authenticated, + redirectTo, + error, + }; +} diff --git a/refine-nextjs/plugins/data-provider-appwrite/src/app/login/page.tsx b/refine-nextjs/plugins/data-provider-appwrite/src/app/login/page.tsx new file mode 100644 index 000000000..e4e77ff92 --- /dev/null +++ b/refine-nextjs/plugins/data-provider-appwrite/src/app/login/page.tsx @@ -0,0 +1,24 @@ +import { AuthPage } from "@components/auth-page"; +import { authProviderServer } from "@providers/auth-provider"; +import { redirect } from "next/navigation"; + +export default async function Login() { + const data = await getData(); + + if (data.authenticated) { + redirect(data?.redirectTo || "/"); + } + + return ; +} + +async function getData() { + const { authenticated, redirectTo, error } = + await authProviderServer.check(); + + return { + authenticated, + redirectTo, + error, + }; +} diff --git a/refine-nextjs/plugins/data-provider-appwrite/src/app/register/page.tsx b/refine-nextjs/plugins/data-provider-appwrite/src/app/register/page.tsx new file mode 100644 index 000000000..b07acae8d --- /dev/null +++ b/refine-nextjs/plugins/data-provider-appwrite/src/app/register/page.tsx @@ -0,0 +1,24 @@ +import { AuthPage } from "@components/auth-page"; +import { authProviderServer } from "@providers/auth-provider"; +import { redirect } from "next/navigation"; + +export default async function Register() { + const data = await getData(); + + if (data.authenticated) { + redirect(data?.redirectTo || "/"); + } + + return ; +} + +async function getData() { + const { authenticated, redirectTo, error } = + await authProviderServer.check(); + + return { + authenticated, + redirectTo, + error, + }; +} diff --git a/refine-nextjs/plugins/data-provider-appwrite/src/providers/auth-provider/auth-provider.server.ts b/refine-nextjs/plugins/data-provider-appwrite/src/providers/auth-provider/auth-provider.server.ts new file mode 100644 index 000000000..b786f6dc5 --- /dev/null +++ b/refine-nextjs/plugins/data-provider-appwrite/src/providers/auth-provider/auth-provider.server.ts @@ -0,0 +1,22 @@ +import { AuthBindings } from "@refinedev/core"; +import { APPWRITE_TOKEN_KEY } from "@utility/constants"; +import { cookies } from "next/headers"; + +export const authProviderServer: Pick = { + check: async () => { + const cookieStore = cookies(); + const auth = cookieStore.get(APPWRITE_TOKEN_KEY); + + if (auth) { + return { + authenticated: true, + }; + } + + return { + authenticated: false, + logout: true, + redirectTo: "/login", + }; + }, +}; diff --git a/refine-nextjs/plugins/data-provider-appwrite/src/authProvider.ts b/refine-nextjs/plugins/data-provider-appwrite/src/providers/auth-provider/auth-provider.ts similarity index 86% rename from refine-nextjs/plugins/data-provider-appwrite/src/authProvider.ts rename to refine-nextjs/plugins/data-provider-appwrite/src/providers/auth-provider/auth-provider.ts index 7ba1eccc7..c443bc611 100644 --- a/refine-nextjs/plugins/data-provider-appwrite/src/authProvider.ts +++ b/refine-nextjs/plugins/data-provider-appwrite/src/providers/auth-provider/auth-provider.ts @@ -1,8 +1,11 @@ +"use client"; + +import { account, appwriteClient } from "@providers/data-provider"; import { AppwriteException } from "@refinedev/appwrite"; import { AuthBindings } from "@refinedev/core"; -import nookies from "nookies"; +import { APPWRITE_TOKEN_KEY } from "@utility/constants"; +import Cookies from "js-cookie"; import { v4 as uuidv4 } from "uuid"; -import { account, appwriteClient, APPWRITE_TOKEN_KEY } from "./utility"; export const authProvider: AuthBindings = { login: async ({ email, password }) => { @@ -11,8 +14,8 @@ export const authProvider: AuthBindings = { const { jwt } = await account.createJWT(); if (jwt) { - nookies.set(null, APPWRITE_TOKEN_KEY, jwt, { - maxAge: 30 * 24 * 60 * 60, + Cookies.set(APPWRITE_TOKEN_KEY, jwt, { + expires: 30, // 30 days path: "/", }); } @@ -41,7 +44,7 @@ export const authProvider: AuthBindings = { error, }; } - nookies.destroy(null, APPWRITE_TOKEN_KEY); + Cookies.remove(APPWRITE_TOKEN_KEY, { path: "/" }); appwriteClient.setJWT(""); return { success: true, @@ -70,10 +73,8 @@ export const authProvider: AuthBindings = { console.error(error); return { error }; }, - check: async (ctx) => { - // for server side authentication - const cookies = nookies.get(ctx); - const appwriteJWT = cookies[APPWRITE_TOKEN_KEY]; + check: async () => { + const appwriteJWT = Cookies.get(APPWRITE_TOKEN_KEY); if (appwriteJWT) { appwriteClient.setJWT(appwriteJWT); } diff --git a/refine-nextjs/plugins/data-provider-appwrite/src/providers/auth-provider/index.ts b/refine-nextjs/plugins/data-provider-appwrite/src/providers/auth-provider/index.ts new file mode 100644 index 000000000..b7f6d9fe9 --- /dev/null +++ b/refine-nextjs/plugins/data-provider-appwrite/src/providers/auth-provider/index.ts @@ -0,0 +1,2 @@ +export * from './auth-provider' +export * from './auth-provider.server' diff --git a/refine-nextjs/plugins/data-provider-appwrite/src/providers/data-provider/index.ts b/refine-nextjs/plugins/data-provider-appwrite/src/providers/data-provider/index.ts new file mode 100644 index 000000000..dcfec38d4 --- /dev/null +++ b/refine-nextjs/plugins/data-provider-appwrite/src/providers/data-provider/index.ts @@ -0,0 +1,38 @@ +"use client"; + +import { + Account, + Appwrite, + dataProvider as appwriteDataProvider, + liveProvider as appwriteLiveProvider, + Storage, +} from "@refinedev/appwrite"; +import { + APPWRITE_PROJECT, + APPWRITE_TOKEN_KEY, + APPWRITE_URL, +} from "@utility/constants"; +import Cookies from "js-cookie"; + +const appwriteClient = new Appwrite(); + +appwriteClient.setEndpoint(APPWRITE_URL).setProject(APPWRITE_PROJECT); + +// for client side authentication +const appwriteJWT = Cookies.get(APPWRITE_TOKEN_KEY); +if (appwriteJWT) { + appwriteClient.setJWT(appwriteJWT); +} + +const account = new Account(appwriteClient); +const storage = new Storage(appwriteClient); + +export { appwriteClient, account, storage }; + +export const dataProvider = appwriteDataProvider(appwriteClient, { + databaseId: "database", +}); + +export const liveProvider = appwriteLiveProvider(appwriteClient, { + databaseId: "database", +}); diff --git a/refine-nextjs/plugins/data-provider-appwrite/src/utility/appwriteClient.ts b/refine-nextjs/plugins/data-provider-appwrite/src/utility/appwriteClient.ts deleted file mode 100644 index 950a55b24..000000000 --- a/refine-nextjs/plugins/data-provider-appwrite/src/utility/appwriteClient.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { Account, Appwrite, Storage } from "@refinedev/appwrite"; -import nookies from "nookies"; - -const APPWRITE_URL = "https://refine.appwrite.org/v1"; -const APPWRITE_PROJECT = "61c4368b4e349"; -export const APPWRITE_TOKEN_KEY = "appwrite-jwt"; - -const appwriteClient = new Appwrite(); - -appwriteClient.setEndpoint(APPWRITE_URL).setProject(APPWRITE_PROJECT); - -// for client side authentication -const cookies = nookies.get(); -const appwriteJWT = cookies[APPWRITE_TOKEN_KEY]; -if (appwriteJWT) { - appwriteClient.setJWT(appwriteJWT); -} - -const account = new Account(appwriteClient); -const storage = new Storage(appwriteClient); - -export { appwriteClient, account, storage }; diff --git a/refine-nextjs/plugins/data-provider-appwrite/src/utility/constants.ts b/refine-nextjs/plugins/data-provider-appwrite/src/utility/constants.ts new file mode 100644 index 000000000..3046b4303 --- /dev/null +++ b/refine-nextjs/plugins/data-provider-appwrite/src/utility/constants.ts @@ -0,0 +1,3 @@ +export const APPWRITE_URL = "https://refine.appwrite.org/v1"; +export const APPWRITE_PROJECT = "61c4368b4e349"; +export const APPWRITE_TOKEN_KEY = "appwrite-jwt"; diff --git a/refine-nextjs/plugins/data-provider-appwrite/src/utility/index.ts b/refine-nextjs/plugins/data-provider-appwrite/src/utility/index.ts deleted file mode 100644 index b4f6465b1..000000000 --- a/refine-nextjs/plugins/data-provider-appwrite/src/utility/index.ts +++ /dev/null @@ -1,4 +0,0 @@ -export * from "./appwriteClient"; -<%_ if (answers["ui-framework"] === "antd") { _%> -export * from "./normalize"; -<%_ } _%> diff --git a/refine-nextjs/plugins/data-provider-appwrite/src/utility/normalize.ts b/refine-nextjs/plugins/data-provider-appwrite/src/utility/normalize.ts index 038790ea5..4631e8488 100644 --- a/refine-nextjs/plugins/data-provider-appwrite/src/utility/normalize.ts +++ b/refine-nextjs/plugins/data-provider-appwrite/src/utility/normalize.ts @@ -1,3 +1,5 @@ +"use client"; + import { UploadFile } from "antd"; interface UploadResponse { @@ -24,4 +26,4 @@ export const normalizeFile = (event: EventArgs) => { status, }; }); -}; \ No newline at end of file +}; diff --git a/refine-nextjs/plugins/data-provider-custom-json-rest/extend.js b/refine-nextjs/plugins/data-provider-custom-json-rest/extend.js index 02f53b8d4..8a43af398 100644 --- a/refine-nextjs/plugins/data-provider-custom-json-rest/extend.js +++ b/refine-nextjs/plugins/data-provider-custom-json-rest/extend.js @@ -1,11 +1,8 @@ const base = { _app: { - import: [`import dataProvider from "@refinedev/simple-rest";`], - afterImport: [ - `const API_URL = "https://api.fake-rest.refine.dev";`, - "", - ], - refineProps: ["dataProvider={dataProvider(API_URL)}"], + import: [`import { dataProvider } from "@providers/data-provider";`], + afterImport: [], + refineProps: ["dataProvider={dataProvider}"], }, }; diff --git a/refine-nextjs/plugins/data-provider-custom-json-rest/src/providers/data-provider/index.ts b/refine-nextjs/plugins/data-provider-custom-json-rest/src/providers/data-provider/index.ts new file mode 100644 index 000000000..a049c0e10 --- /dev/null +++ b/refine-nextjs/plugins/data-provider-custom-json-rest/src/providers/data-provider/index.ts @@ -0,0 +1,7 @@ +"use client"; + +import dataProviderSimpleRest from "@refinedev/simple-rest"; + +const API_URL = "https://api.fake-rest.refine.dev"; + +export const dataProvider = dataProviderSimpleRest(API_URL); diff --git a/refine-nextjs/plugins/data-provider-graphql/extend.js b/refine-nextjs/plugins/data-provider-graphql/extend.js index dc6d2fa35..8a43af398 100644 --- a/refine-nextjs/plugins/data-provider-graphql/extend.js +++ b/refine-nextjs/plugins/data-provider-graphql/extend.js @@ -1,18 +1,11 @@ const base = { _app: { - import: [ - `import dataProvider, { GraphQLClient } from "@refinedev/graphql";`, - ], - afterImport: [ - `const API_URL = "https://your-graphql-url/graphql";`, - "", - `const client = new GraphQLClient(API_URL);`, - `const gqlDataProvider = dataProvider(client);`, - "", - ], - refineProps: ["dataProvider={gqlDataProvider}"], + import: [`import { dataProvider } from "@providers/data-provider";`], + afterImport: [], + refineProps: ["dataProvider={dataProvider}"], }, }; + module.exports = { extend() { return base; diff --git a/refine-nextjs/plugins/data-provider-graphql/src/providers/data-provider/index.ts b/refine-nextjs/plugins/data-provider-graphql/src/providers/data-provider/index.ts new file mode 100644 index 000000000..f1e1ca6f6 --- /dev/null +++ b/refine-nextjs/plugins/data-provider-graphql/src/providers/data-provider/index.ts @@ -0,0 +1,9 @@ +"use client"; + +import graphqlDataProvider, { GraphQLClient } from "@refinedev/graphql"; + +const API_URL = "https://your-graphql-url/graphql"; + +export const client = new GraphQLClient(API_URL); + +export const dataProvider = graphqlDataProvider(client); diff --git a/refine-nextjs/plugins/data-provider-hasura/extend.js b/refine-nextjs/plugins/data-provider-hasura/extend.js index 2afb9ba6c..8a43af398 100644 --- a/refine-nextjs/plugins/data-provider-hasura/extend.js +++ b/refine-nextjs/plugins/data-provider-hasura/extend.js @@ -1,21 +1,11 @@ const base = { _app: { - import: [ - `import dataProvider, { GraphQLClient } from "@refinedev/hasura";`, - ], - afterImport: [ - "", - `const API_URL = "https://flowing-mammal-24.hasura.app/v1/graphql";`, - "", - `const client = new GraphQLClient(API_URL, { - headers: { - "x-hasura-role": "public", - }, - });`, - ], - refineProps: [`dataProvider={dataProvider(client)}`], + import: [`import { dataProvider } from "@providers/data-provider";`], + afterImport: [], + refineProps: ["dataProvider={dataProvider}"], }, }; + module.exports = { extend() { return base; diff --git a/refine-nextjs/plugins/data-provider-hasura/src/inferencerPredefinedMeta.ts b/refine-nextjs/plugins/data-provider-hasura/src/inferencerPredefinedMeta.ts deleted file mode 100644 index 67f26ed5b..000000000 --- a/refine-nextjs/plugins/data-provider-hasura/src/inferencerPredefinedMeta.ts +++ /dev/null @@ -1,202 +0,0 @@ -import gql from "graphql-tag"; - -/** - * This `meta` object is used to define the necessary metadata for inferencer to work with. - * - * They will be used to infer the fields of the response of the data provider. - * Also they will be included in the generated code, making them easily editable after you generate the boilerplate code for your resource. - */ -export const inferencerPredefinedMeta = { - blog_posts: { - getList: { - gqlQuery: gql` - query BlogPostsList( - $offset: Int! - $limit: Int! - $order_by: [blog_posts_order_by!] - $where: blog_posts_bool_exp - ) { - blog_posts( - offset: $offset - limit: $limit - order_by: $order_by - where: $where - ) { - id - title - content - category_id - created_at - status - category { - id - title - } - } - blog_posts_aggregate(where: $where) { - aggregate { - count - } - } - } - `, - }, - getOne: { - gqlQuery: gql` - query GetBlogPost($id: uuid!) { - blog_posts_by_pk(id: $id) { - id - title - content - category_id - created_at - status - category { - id - title - } - } - } - `, - }, - create: { - foo: "bar", - objFoo: { - bar: "baz", - }, - gqlMutation: gql` - mutation CreateBlogPosts($object: blog_posts_insert_input!) { - insert_blog_posts_one(object: $object) { - id - title - content - created_at - category_id - status - category { - id - title - } - } - } - `, - }, - update: { - gqlMutation: gql` - mutation UpdateBlogPosts( - $id: uuid! - $object: blog_posts_set_input! - ) { - update_blog_posts_by_pk( - pk_columns: { id: $id } - _set: $object - ) { - id - title - content - created_at - category_id - status - category { - id - title - } - } - } - `, - }, - }, - categories: { - default: { - gqlQuery: gql` - query CategoriesList( - $offset: Int - $limit: Int - $order_by: [categories_order_by!] - $where: categories_bool_exp - ) { - categories( - offset: $offset - limit: $limit - order_by: $order_by - where: $where - ) { - id - title - created_at - } - categories_aggregate(where: $where) { - aggregate { - count - } - } - } - `, - }, - getList: { - gqlQuery: gql` - query CategoriesList( - $offset: Int - $limit: Int - $order_by: [categories_order_by!] - $where: categories_bool_exp - ) { - categories( - offset: $offset - limit: $limit - order_by: $order_by - where: $where - ) { - id - title - created_at - } - categories_aggregate(where: $where) { - aggregate { - count - } - } - } - `, - }, - getOne: { - gqlQuery: gql` - query GetCategory($id: uuid!) { - categories_by_pk(id: $id) { - id - title - created_at - } - } - `, - }, - create: { - gqlMutation: gql` - mutation CreateCategory($object: categories_insert_input!) { - insert_categories_one(object: $object) { - id - title - created_at - } - } - `, - }, - update: { - gqlMutation: gql` - mutation UpdateCategory( - $id: uuid! - $object: categories_set_input! - ) { - update_categories_by_pk( - pk_columns: { id: $id } - _set: $object - ) { - id - title - created_at - } - } - `, - }, - }, -}; diff --git a/refine-nextjs/plugins/data-provider-hasura/src/providers/data-provider/index.ts b/refine-nextjs/plugins/data-provider-hasura/src/providers/data-provider/index.ts new file mode 100644 index 000000000..f4eff9c90 --- /dev/null +++ b/refine-nextjs/plugins/data-provider-hasura/src/providers/data-provider/index.ts @@ -0,0 +1,13 @@ +"use client"; + +import dataProviderHasura, { GraphQLClient } from "@refinedev/hasura"; + +const API_URL = "https://flowing-mammal-24.hasura.app/v1/graphql"; + +export const client = new GraphQLClient(API_URL, { + headers: { + "x-hasura-role": "public", + }, +}); + +export const dataProvider = dataProviderHasura(client); diff --git a/refine-nextjs/plugins/data-provider-hasura/src/queries/blog-posts.ts b/refine-nextjs/plugins/data-provider-hasura/src/queries/blog-posts.ts new file mode 100644 index 000000000..76bfc8400 --- /dev/null +++ b/refine-nextjs/plugins/data-provider-hasura/src/queries/blog-posts.ts @@ -0,0 +1,13 @@ +export const BLOG_POSTS_QUERY = [ + "id", + "title", + "status", + "created_at", + "category_id", + "content", + { + category: ["id", "title"], + }, +]; + +export const BLOG_POSTS_CATEGORIES_SELECT_QUERY = ["id", "title"]; diff --git a/refine-nextjs/plugins/data-provider-hasura/src/queries/categories.ts b/refine-nextjs/plugins/data-provider-hasura/src/queries/categories.ts new file mode 100644 index 000000000..9a6a5ccd8 --- /dev/null +++ b/refine-nextjs/plugins/data-provider-hasura/src/queries/categories.ts @@ -0,0 +1 @@ +export const CATEGORIES_QUERY = ["id", "title"]; diff --git a/refine-nextjs/plugins/data-provider-medusa/extend.js b/refine-nextjs/plugins/data-provider-medusa/extend.js deleted file mode 100644 index f8267892c..000000000 --- a/refine-nextjs/plugins/data-provider-medusa/extend.js +++ /dev/null @@ -1,23 +0,0 @@ -const base = { - _app: { - import: [ - `import dataProvider, { authProvider } from "@refinedev/medusa";`, - ], - afterImport: [ - `const API_URL = "https://your-medusa-url";`, - "", - `const medusaDataProvider = dataProvider(API_URL);`, - `const medusaAuthProvider = authProvider(API_URL);`, - "", - ], - refineProps: [ - "authProvider={medusaAuthProvider}", - "dataProvider={medusaDataProvider}", - ], - }, -}; -module.exports = { - extend() { - return base; - }, -}; diff --git a/refine-nextjs/plugins/data-provider-medusa/package.json b/refine-nextjs/plugins/data-provider-medusa/package.json deleted file mode 100644 index bfc50b17c..000000000 --- a/refine-nextjs/plugins/data-provider-medusa/package.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "dependencies": { - "@refinedev/medusa": "^3.0.1" - } -} diff --git a/refine-nextjs/plugins/data-provider-nestjs-query/extend.js b/refine-nextjs/plugins/data-provider-nestjs-query/extend.js index 947ebabec..9494f4b2c 100644 --- a/refine-nextjs/plugins/data-provider-nestjs-query/extend.js +++ b/refine-nextjs/plugins/data-provider-nestjs-query/extend.js @@ -1,23 +1,16 @@ const base = { _app: { - import: [ - `import dataProvider, { GraphQLClient, liveProvider } from "@refinedev/nestjs-query";`, - `import { createClient } from "graphql-ws";` - ], - afterImport: [ - "", - `const API_URL = "https://api.nestjs-query.refine.dev/graphql";`, - `const WS_URL = "wss://api.nestjs-query.refine.dev/graphql";`, - "", - `const gqlClient = new GraphQLClient(API_URL);`, - `const wsClient = createClient({ url: WS_URL });`, - "", + import: [], + localImport: [ + 'import { dataProvider, liveProvider } from "@providers/data-provider";', ], refineProps: [ - `dataProvider={dataProvider(gqlClient)}`, - `liveProvider={liveProvider(wsClient)}`, + `dataProvider={dataProvider}`, + `liveProvider={liveProvider}`, ], refineOptions: [`liveMode: "auto",`], + refineAntdImports: [], + refineMuiImports: [], }, }; module.exports = { diff --git a/refine-nextjs/plugins/data-provider-nestjs-query/package.json b/refine-nextjs/plugins/data-provider-nestjs-query/package.json index f3d4e67e7..6506d516e 100644 --- a/refine-nextjs/plugins/data-provider-nestjs-query/package.json +++ b/refine-nextjs/plugins/data-provider-nestjs-query/package.json @@ -1,5 +1,16 @@ { - "dependencies": { - "@refinedev/nestjs-query": "^1.1.1" - } -} \ No newline at end of file + "scripts": { + "codegen": "graphql-codegen" + }, + "dependencies": { + "@refinedev/nestjs-query": "^1.1.1", + "graphql-tag": "^2.12.6", + "graphql-ws": "^5.9.1" + }, + "devDependencies": { + "@graphql-codegen/cli": "^5.0.0", + "@graphql-codegen/typescript": "^4.0.1", + "@graphql-codegen/typescript-operations": "^4.0.1", + "@graphql-codegen/import-types-preset": "^3.0.0" + } +} diff --git a/refine-nextjs/plugins/data-provider-nestjs-query/src/providers/data-provider/index.ts b/refine-nextjs/plugins/data-provider-nestjs-query/src/providers/data-provider/index.ts new file mode 100644 index 000000000..b660b82ed --- /dev/null +++ b/refine-nextjs/plugins/data-provider-nestjs-query/src/providers/data-provider/index.ts @@ -0,0 +1,16 @@ +"use client"; + +import dataProviderNestjsQuery, { + GraphQLClient, + liveProvider as liveProviderNestjsQuery, +} from "@refinedev/nestjs-query"; +import { createClient } from "graphql-ws"; + +const API_URL = "https://api.nestjs-query.refine.dev/graphql"; +const WS_URL = "wss://api.nestjs-query.refine.dev/graphql"; + +const gqlClient = new GraphQLClient(API_URL); +const wsClient = createClient({ url: WS_URL }); + +export const dataProvider = dataProviderNestjsQuery(gqlClient); +export const liveProvider = liveProviderNestjsQuery(wsClient); diff --git a/refine-nextjs/plugins/data-provider-nestjs-query/src/queries/blog-posts.ts b/refine-nextjs/plugins/data-provider-nestjs-query/src/queries/blog-posts.ts new file mode 100644 index 000000000..3e77249eb --- /dev/null +++ b/refine-nextjs/plugins/data-provider-nestjs-query/src/queries/blog-posts.ts @@ -0,0 +1,85 @@ +import gql from "graphql-tag"; + +export const POST_CREATE_MUTATION = gql` + mutation PostCreate($input: CreateOneBlogPostInput!) { + createOneBlogPost(input: $input) { + id + title + status + categoryId + category { + id + title + } + content + } + } +`; + +export const POST_EDIT_MUTATION = gql` + mutation PostEdit($input: UpdateOneBlogPostInput!) { + updateOneBlogPost(input: $input) { + id + title + status + categoryId + category { + id + title + } + content + } + } +`; + +export const POSTS_LIST_QUERY = gql` + query BlogPostsList( + $paging: OffsetPaging! + $filter: BlogPostFilter + $sorting: [BlogPostSort!]! + ) { + blogPosts(paging: $paging, filter: $filter, sorting: $sorting) { + nodes { + id + title + categoryId + category { + id + title + } + status + content + createdAt + } + totalCount + } + } +`; + +export const POST_SHOW_QUERY = gql` + query PostShow($id: ID!) { + blogPost(id: $id) { + id + title + status + categoryId + category { + id + title + } + content + createdAt + } + } +`; + +export const CATEGORIES_SELECT_QUERY = gql` + query CategoriesSelect($filter: CategoryFilter!) { + categories(filter: $filter) { + nodes { + id + title + } + } + } +`; diff --git a/refine-nextjs/plugins/data-provider-nestjs-query/src/queries/categories.ts b/refine-nextjs/plugins/data-provider-nestjs-query/src/queries/categories.ts new file mode 100644 index 000000000..8e4e6e0b1 --- /dev/null +++ b/refine-nextjs/plugins/data-provider-nestjs-query/src/queries/categories.ts @@ -0,0 +1,45 @@ +import gql from "graphql-tag"; + +export const CATEGORY_CREATE_MUTATION = gql` + mutation CategoryCreate($input: CreateOneCategoryInput!) { + createOneCategory(input: $input) { + id + title + } + } +`; + +export const CATEGORY_EDIT_MUTATION = gql` + mutation CategoryEdit($input: UpdateOneCategoryInput!) { + updateOneCategory(input: $input) { + id + title + } + } +`; + +export const CATEGORIES_LIST_QUERY = gql` + query CategoriesList( + $paging: OffsetPaging! + $filter: CategoryFilter + $sorting: [CategorySort!]! + ) { + categories(paging: $paging, filter: $filter, sorting: $sorting) { + nodes { + id + title + createdAt + } + totalCount + } + } +`; +export const CATEGORY_SHOW_QUERY = gql` + query CategoryShow($id: ID!) { + category(id: $id) { + id + title + createdAt + } + } +`; diff --git a/refine-nextjs/plugins/data-provider-nestjsx-crud/extend.js b/refine-nextjs/plugins/data-provider-nestjsx-crud/extend.js index 84535bb87..8a43af398 100644 --- a/refine-nextjs/plugins/data-provider-nestjsx-crud/extend.js +++ b/refine-nextjs/plugins/data-provider-nestjsx-crud/extend.js @@ -1,8 +1,8 @@ const base = { _app: { - import: ['import dataProvider from "@refinedev/nestjsx-crud";'], - afterImport: [`const API_URL = "https://api.nestjsx-crud.refine.dev";`], - refineProps: ["dataProvider={dataProvider(API_URL)}"], + import: [`import { dataProvider } from "@providers/data-provider";`], + afterImport: [], + refineProps: ["dataProvider={dataProvider}"], }, }; diff --git a/refine-nextjs/plugins/data-provider-nestjsx-crud/src/providers/data-provider/index.ts b/refine-nextjs/plugins/data-provider-nestjsx-crud/src/providers/data-provider/index.ts new file mode 100644 index 000000000..13f8f00c3 --- /dev/null +++ b/refine-nextjs/plugins/data-provider-nestjsx-crud/src/providers/data-provider/index.ts @@ -0,0 +1,7 @@ +"use client"; + +import dataProviderNestjsxCrud from "@refinedev/nestjsx-crud"; + +const API_URL = "https://api.nestjsx-crud.refine.dev"; + +export const dataProvider = dataProviderNestjsxCrud(API_URL); diff --git a/refine-nextjs/plugins/data-provider-strapi-v4/extend.js b/refine-nextjs/plugins/data-provider-strapi-v4/extend.js index c4fe4ee5f..366f21843 100644 --- a/refine-nextjs/plugins/data-provider-strapi-v4/extend.js +++ b/refine-nextjs/plugins/data-provider-strapi-v4/extend.js @@ -1,16 +1,15 @@ const base = { _app: { - import: [`import { DataProvider } from "@refinedev/strapi-v4";`], + import: [], localImport: [ - `import { authProvider, axiosInstance } from "src/authProvider";`, - `import { API_URL } from "src/constants";`, + 'import { authProvider } from "@providers/auth-provider";', + 'import { dataProvider } from "@providers/data-provider";', ], refineProps: [ "authProvider={authProvider}", - "dataProvider={DataProvider(API_URL + `/api`, axiosInstance)}", + "dataProvider={dataProvider}", ], refineAntdImports: [], - refineMantineImports: [], refineMuiImports: [], }, }; diff --git a/refine-nextjs/plugins/data-provider-strapi-v4/package.json b/refine-nextjs/plugins/data-provider-strapi-v4/package.json index e2b156cb7..1e78c87ff 100644 --- a/refine-nextjs/plugins/data-provider-strapi-v4/package.json +++ b/refine-nextjs/plugins/data-provider-strapi-v4/package.json @@ -1,7 +1,10 @@ { - "dependencies": { - "@refinedev/strapi-v4": "^6.0.1", - "axios": "^1.6.2", - "nookies": "^2.5.2" - } -} \ No newline at end of file + "dependencies": { + "@refinedev/strapi-v4": "^6.0.1", + "axios": "^1.6.2", + "js-cookie": "^3.0.5" + }, + "devDependencies": { + "@types/js-cookie": "^3.0.6" + } +} diff --git a/refine-nextjs/plugins/data-provider-strapi-v4/pages/forgot-password/index.tsx b/refine-nextjs/plugins/data-provider-strapi-v4/pages/forgot-password/index.tsx deleted file mode 100644 index 18e230c29..000000000 --- a/refine-nextjs/plugins/data-provider-strapi-v4/pages/forgot-password/index.tsx +++ /dev/null @@ -1,77 +0,0 @@ -<%_ if (answers["ui-framework"] === 'antd') { _%> - import { AuthPage, ThemedTitleV2 } from "@refinedev/antd"; -<%_ } _%> -<%_ if (answers["ui-framework"] === 'mui') { _%> - import { AuthPage, ThemedTitleV2 } from "@refinedev/mui"; -<%_ } _%> -<%_ if (answers["ui-framework"] === 'mantine') { _%> - import { AuthPage, ThemedTitleV2 } from "@refinedev/mantine"; -<%_ } _%> -<%_ if (answers["ui-framework"] === 'chakra') { _%> - import { AuthPage, ThemedTitleV2 } from "@refinedev/chakra-ui"; -<%_ } _%> -<%_ if (answers[`ui-framework`] === "no") { _%> - import { AuthPage } from "@refinedev/core"; -<%_ } _%> - -import { GetServerSideProps } from "next"; -<%_ if (answers[`i18n-${answers["ui-framework"]}`] !== "no") { _%> -import { serverSideTranslations } from "next-i18next/serverSideTranslations"; -<%_ } _%> - -import { authProvider } from "src/authProvider"; - -<%_ if (selectedSvg && answers["ui-framework"] !== "no" ) { _%> -import { AppIcon } from "src/components/app-icon"; -<%_ } _%> - -export default function ForgotPassword() { - return ( - - title={( - - text="<%= selectedTitle %>" - <%_ } _%> - <%_ if (selectedSvg) { _%> - icon={} - <%_ } _%> - /> - )} - <%_ } _%> - /> - ); -} - -ForgotPassword.noLayout = true; - -export const getServerSideProps: GetServerSideProps<{}> = async (context) => { - const { authenticated } = await authProvider.check(context); - - <%_ if (answers[`i18n-${answers["ui-framework"]}`] !== "no") { _%> - const translateProps = await serverSideTranslations( - context.locale ?? "en", - ["common"], - ); - <%_ } _%> - - if (authenticated) { - return { - props: {}, - redirect: { - destination: `/`, - permanent: false, - }, - }; - } - - return { - props: { - <%_ if (answers[`i18n-${answers["ui-framework"]}`] !== "no") { _%> - ...translateProps, - <%_ } _%> - } - } -}; diff --git a/refine-nextjs/plugins/data-provider-strapi-v4/pages/login/index.tsx b/refine-nextjs/plugins/data-provider-strapi-v4/pages/login/index.tsx deleted file mode 100644 index 116a8f50e..000000000 --- a/refine-nextjs/plugins/data-provider-strapi-v4/pages/login/index.tsx +++ /dev/null @@ -1,81 +0,0 @@ -<%_ if (answers["ui-framework"] === 'antd') { _%> - import { AuthPage, ThemedTitleV2 } from "@refinedev/antd"; -<%_ } _%> -<%_ if (answers["ui-framework"] === 'mui') { _%> - import { AuthPage, ThemedTitleV2 } from "@refinedev/mui"; -<%_ } _%> -<%_ if (answers["ui-framework"] === 'mantine') { _%> - import { AuthPage, ThemedTitleV2 } from "@refinedev/mantine"; -<%_ } _%> -<%_ if (answers["ui-framework"] === 'chakra') { _%> - import { AuthPage, ThemedTitleV2 } from "@refinedev/chakra-ui"; -<%_ } _%> -<%_ if (answers[`ui-framework`] === "no") { _%> - import { AuthPage } from "@refinedev/core"; -<%_ } _%> - -import { GetServerSideProps } from "next"; -<%_ if (answers[`i18n-${answers["ui-framework"]}`] !== "no") { _%> -import { serverSideTranslations } from "next-i18next/serverSideTranslations"; -<%_ } _%> - -import { authProvider } from "src/authProvider"; - -<%_ if (selectedSvg && answers["ui-framework"] !== "no" ) { _%> -import { AppIcon } from "src/components/app-icon"; -<%_ } _%> - -export default function Login() { - return ( - - <%_ if ((selectedSvg || selectedTitle) && answers["ui-framework"] !== "no") { _%> - title={( - - text="<%= selectedTitle %>" - <%_ } _%> - <%_ if (selectedSvg) { _%> - icon={} - <%_ } _%> - /> - )} - <%_ } _%> - /> - ); -} - -Login.noLayout = true; - -export const getServerSideProps: GetServerSideProps<{}> = async (context) => { - const { authenticated } = await authProvider.check(context); - - <%_ if (answers[`i18n-${answers["ui-framework"]}`] !== "no") { _%> - const translateProps = await serverSideTranslations( - context.locale ?? "en", - ["common"], - ); - <%_ } _%> - - if (authenticated) { - return { - props: {}, - redirect: { - destination: `/`, - permanent: false, - }, - }; - } - - return { - props: { - <%_ if (answers[`i18n-${answers["ui-framework"]}`] !== "no") { _%> - ...translateProps, - <%_ } _%> - } - } - -}; - diff --git a/refine-nextjs/plugins/data-provider-strapi-v4/pages/register/index.tsx b/refine-nextjs/plugins/data-provider-strapi-v4/pages/register/index.tsx deleted file mode 100644 index d207e59f7..000000000 --- a/refine-nextjs/plugins/data-provider-strapi-v4/pages/register/index.tsx +++ /dev/null @@ -1,76 +0,0 @@ -<%_ if (answers["ui-framework"] === 'antd') { _%> - import { AuthPage, ThemedTitleV2 } from "@refinedev/antd"; -<%_ } _%> -<%_ if (answers["ui-framework"] === 'mui') { _%> - import { AuthPage, ThemedTitleV2 } from "@refinedev/mui"; -<%_ } _%> -<%_ if (answers["ui-framework"] === 'mantine') { _%> - import { AuthPage, ThemedTitleV2 } from "@refinedev/mantine"; -<%_ } _%> -<%_ if (answers["ui-framework"] === 'chakra') { _%> - import { AuthPage, ThemedTitleV2 } from "@refinedev/chakra-ui"; -<%_ } _%> -<%_ if (answers[`ui-framework`] === "no") { _%> - import { AuthPage } from "@refinedev/core"; -<%_ } _%> - -import { GetServerSideProps } from "next"; -<%_ if (answers[`i18n-${answers["ui-framework"]}`] !== "no") { _%> -import { serverSideTranslations } from "next-i18next/serverSideTranslations"; -<%_ } _%> - -import { authProvider } from "src/authProvider"; - -<%_ if (selectedSvg && answers["ui-framework"] !== "no" ) { _%> -import { AppIcon } from "src/components/app-icon"; -<%_ } _%> -export default function Register() { - return ( - - title={( - - text="<%= selectedTitle %>" - <%_ } _%> - <%_ if (selectedSvg) { _%> - icon={} - <%_ } _%> - /> - )} - <%_ } _%> - /> - ); -} - -Register.noLayout = true; - -export const getServerSideProps: GetServerSideProps<{}> = async (context) => { - const { authenticated } = await authProvider.check(context); - - <%_ if (answers[`i18n-${answers["ui-framework"]}`] !== "no") { _%> - const translateProps = await serverSideTranslations( - context.locale ?? "en", - ["common"], - ); - <%_ } _%> - - if (authenticated) { - return { - props: {}, - redirect: { - destination: `/`, - permanent: false, - }, - }; - } - - return { - props: { - <%_ if (answers[`i18n-${answers["ui-framework"]}`] !== "no") { _%> - ...translateProps, - <%_ } _%> - } - } -}; diff --git a/refine-nextjs/plugins/data-provider-strapi-v4/src/app/forgot-password/page.tsx b/refine-nextjs/plugins/data-provider-strapi-v4/src/app/forgot-password/page.tsx new file mode 100644 index 000000000..c2b0061f5 --- /dev/null +++ b/refine-nextjs/plugins/data-provider-strapi-v4/src/app/forgot-password/page.tsx @@ -0,0 +1,24 @@ +import { AuthPage } from "@components/auth-page"; +import { authProviderServer } from "@providers/auth-provider"; +import { redirect } from "next/navigation"; + +export default async function ForgotPassword() { + const data = await getData(); + + if (data.authenticated) { + redirect(data?.redirectTo || "/"); + } + + return ; +} + +async function getData() { + const { authenticated, redirectTo, error } = + await authProviderServer.check(); + + return { + authenticated, + redirectTo, + error, + }; +} diff --git a/refine-nextjs/plugins/data-provider-strapi-v4/src/app/login/page.tsx b/refine-nextjs/plugins/data-provider-strapi-v4/src/app/login/page.tsx new file mode 100644 index 000000000..e4e77ff92 --- /dev/null +++ b/refine-nextjs/plugins/data-provider-strapi-v4/src/app/login/page.tsx @@ -0,0 +1,24 @@ +import { AuthPage } from "@components/auth-page"; +import { authProviderServer } from "@providers/auth-provider"; +import { redirect } from "next/navigation"; + +export default async function Login() { + const data = await getData(); + + if (data.authenticated) { + redirect(data?.redirectTo || "/"); + } + + return ; +} + +async function getData() { + const { authenticated, redirectTo, error } = + await authProviderServer.check(); + + return { + authenticated, + redirectTo, + error, + }; +} diff --git a/refine-nextjs/plugins/data-provider-strapi-v4/src/app/register/page.tsx b/refine-nextjs/plugins/data-provider-strapi-v4/src/app/register/page.tsx new file mode 100644 index 000000000..b07acae8d --- /dev/null +++ b/refine-nextjs/plugins/data-provider-strapi-v4/src/app/register/page.tsx @@ -0,0 +1,24 @@ +import { AuthPage } from "@components/auth-page"; +import { authProviderServer } from "@providers/auth-provider"; +import { redirect } from "next/navigation"; + +export default async function Register() { + const data = await getData(); + + if (data.authenticated) { + redirect(data?.redirectTo || "/"); + } + + return ; +} + +async function getData() { + const { authenticated, redirectTo, error } = + await authProviderServer.check(); + + return { + authenticated, + redirectTo, + error, + }; +} diff --git a/refine-nextjs/plugins/data-provider-strapi-v4/src/providers/auth-provider/auth-provider.server.ts b/refine-nextjs/plugins/data-provider-strapi-v4/src/providers/auth-provider/auth-provider.server.ts new file mode 100644 index 000000000..03deb9a9d --- /dev/null +++ b/refine-nextjs/plugins/data-provider-strapi-v4/src/providers/auth-provider/auth-provider.server.ts @@ -0,0 +1,22 @@ +import { AuthBindings } from "@refinedev/core"; +import { TOKEN_KEY } from "@utility/constants"; +import { cookies } from "next/headers"; + +export const authProviderServer: Pick = { + check: async () => { + const cookieStore = cookies(); + const auth = cookieStore.get(TOKEN_KEY); + + if (auth) { + return { + authenticated: true, + }; + } + + return { + authenticated: false, + logout: true, + redirectTo: "/login", + }; + }, +}; diff --git a/refine-nextjs/plugins/data-provider-strapi-v4/src/authProvider.ts b/refine-nextjs/plugins/data-provider-strapi-v4/src/providers/auth-provider/auth-provider.ts similarity index 69% rename from refine-nextjs/plugins/data-provider-strapi-v4/src/authProvider.ts rename to refine-nextjs/plugins/data-provider-strapi-v4/src/providers/auth-provider/auth-provider.ts index e670be974..e62dde328 100644 --- a/refine-nextjs/plugins/data-provider-strapi-v4/src/authProvider.ts +++ b/refine-nextjs/plugins/data-provider-strapi-v4/src/providers/auth-provider/auth-provider.ts @@ -1,26 +1,19 @@ +"use client"; + import { AuthBindings } from "@refinedev/core"; import { AuthHelper } from "@refinedev/strapi-v4"; -import axios from "axios"; -import nookies from "nookies"; -import { API_URL, TOKEN_KEY } from "./constants"; +import { axiosInstance } from "@utility/axios-instance"; +import { API_URL, TOKEN_KEY } from "@utility/constants"; +import Cookies from "js-cookie"; -export const axiosInstance = axios.create(); const strapiAuthHelper = AuthHelper(API_URL + "/api"); -axiosInstance.interceptors.request.use((config) => { - const cookies = nookies.get(); - if (cookies[TOKEN_KEY] && config.headers) { - config.headers["Authorization"] = `Bearer ${cookies[TOKEN_KEY]}`; - } - return config; -}); - export const authProvider: AuthBindings = { login: async ({ email, password }) => { const { data, status } = await strapiAuthHelper.login(email, password); if (status === 200) { - nookies.set(null, TOKEN_KEY, data.jwt, { - maxAge: 30 * 24 * 60 * 60, + Cookies.set(TOKEN_KEY, data.jwt, { + expires: 30, // 30 days path: "/", }); @@ -43,17 +36,17 @@ export const authProvider: AuthBindings = { }; }, logout: async () => { - nookies.destroy(null, TOKEN_KEY); + Cookies.remove(TOKEN_KEY, { path: "/" }); return { success: true, redirectTo: "/login", }; }, - check: async (ctx) => { - const cookies = nookies.get(ctx); - if (cookies[TOKEN_KEY]) { + check: async () => { + const token = Cookies.get(TOKEN_KEY); + if (token) { axiosInstance.defaults.headers.common = { - Authorization: `Bearer ${cookies[TOKEN_KEY]}`, + Authorization: `Bearer ${token}`, }; return { authenticated: true, @@ -67,7 +60,7 @@ export const authProvider: AuthBindings = { }, getPermissions: async () => null, getIdentity: async () => { - const token = nookies.get()[TOKEN_KEY]; + const token = Cookies.get(TOKEN_KEY); if (!token) { return null; } @@ -85,7 +78,12 @@ export const authProvider: AuthBindings = { return null; }, onError: async (error) => { - console.error(error); + if (error.response?.status === 401) { + return { + logout: true, + }; + } + return { error }; }, }; diff --git a/refine-nextjs/plugins/data-provider-strapi-v4/src/providers/auth-provider/index.ts b/refine-nextjs/plugins/data-provider-strapi-v4/src/providers/auth-provider/index.ts new file mode 100644 index 000000000..b7f6d9fe9 --- /dev/null +++ b/refine-nextjs/plugins/data-provider-strapi-v4/src/providers/auth-provider/index.ts @@ -0,0 +1,2 @@ +export * from './auth-provider' +export * from './auth-provider.server' diff --git a/refine-nextjs/plugins/data-provider-strapi-v4/src/providers/data-provider/index.ts b/refine-nextjs/plugins/data-provider-strapi-v4/src/providers/data-provider/index.ts new file mode 100644 index 000000000..2fba71074 --- /dev/null +++ b/refine-nextjs/plugins/data-provider-strapi-v4/src/providers/data-provider/index.ts @@ -0,0 +1,7 @@ +"use client"; + +import { DataProvider } from "@refinedev/strapi-v4"; +import { axiosInstance } from "@utility/axios-instance"; +import { API_URL } from "@utility/constants"; + +export const dataProvider = DataProvider(API_URL + `/api`, axiosInstance); diff --git a/refine-nextjs/plugins/data-provider-strapi-v4/src/utility/axios-instance.ts b/refine-nextjs/plugins/data-provider-strapi-v4/src/utility/axios-instance.ts new file mode 100644 index 000000000..d336fc60f --- /dev/null +++ b/refine-nextjs/plugins/data-provider-strapi-v4/src/utility/axios-instance.ts @@ -0,0 +1,16 @@ +"use client"; + +import { TOKEN_KEY } from "@utility/constants"; +import axios from "axios"; +import Cookies from "js-cookie"; + +export const axiosInstance = axios.create(); + +axiosInstance.interceptors.request.use((config) => { + const token = Cookies.get(TOKEN_KEY); + + if (token && config.headers) { + config.headers["Authorization"] = `Bearer ${token}`; + } + return config; +}); diff --git a/refine-nextjs/plugins/data-provider-strapi-v4/src/constants.ts b/refine-nextjs/plugins/data-provider-strapi-v4/src/utility/constants.ts similarity index 100% rename from refine-nextjs/plugins/data-provider-strapi-v4/src/constants.ts rename to refine-nextjs/plugins/data-provider-strapi-v4/src/utility/constants.ts diff --git a/refine-nextjs/plugins/data-provider-supabase/extend.js b/refine-nextjs/plugins/data-provider-supabase/extend.js index bc7f0ca99..366f21843 100644 --- a/refine-nextjs/plugins/data-provider-supabase/extend.js +++ b/refine-nextjs/plugins/data-provider-supabase/extend.js @@ -1,18 +1,16 @@ const base = { _app: { - import: [`import { dataProvider } from "@refinedev/supabase";`], + import: [], localImport: [ - `import { authProvider } from "src/authProvider";`, - `import { supabaseClient } from "src/utility";`, + 'import { authProvider } from "@providers/auth-provider";', + 'import { dataProvider } from "@providers/data-provider";', ], - refineAntdImports: [], - refineMantineImports: [], - refineMuiImports: [], - refineChakraImports: [], refineProps: [ - "dataProvider={dataProvider(supabaseClient)}", "authProvider={authProvider}", + "dataProvider={dataProvider}", ], + refineAntdImports: [], + refineMuiImports: [], }, }; module.exports = { diff --git a/refine-nextjs/plugins/data-provider-supabase/package.json b/refine-nextjs/plugins/data-provider-supabase/package.json index 5e5359604..45fe38bb5 100644 --- a/refine-nextjs/plugins/data-provider-supabase/package.json +++ b/refine-nextjs/plugins/data-provider-supabase/package.json @@ -1,6 +1,9 @@ { - "dependencies": { - "@refinedev/supabase": "^5.7.4", - "nookies": "^2.5.2" - } -} \ No newline at end of file + "dependencies": { + "@refinedev/supabase": "^5.7.4", + "js-cookie": "^3.0.5" + }, + "devDependencies": { + "@types/js-cookie": "^3.0.6" + } +} diff --git a/refine-nextjs/plugins/data-provider-supabase/pages/forgot-password/index.tsx b/refine-nextjs/plugins/data-provider-supabase/pages/forgot-password/index.tsx deleted file mode 100644 index 1c89afd6f..000000000 --- a/refine-nextjs/plugins/data-provider-supabase/pages/forgot-password/index.tsx +++ /dev/null @@ -1,78 +0,0 @@ -<%_ if (answers["ui-framework"] === 'antd') { _%> - import { AuthPage, ThemedTitleV2 } from "@refinedev/antd"; -<%_ } _%> -<%_ if (answers["ui-framework"] === 'mui') { _%> - import { AuthPage, ThemedTitleV2 } from "@refinedev/mui"; -<%_ } _%> -<%_ if (answers["ui-framework"] === 'mantine') { _%> - import { AuthPage, ThemedTitleV2 } from "@refinedev/mantine"; -<%_ } _%> -<%_ if (answers["ui-framework"] === 'chakra') { _%> - import { AuthPage, ThemedTitleV2 } from "@refinedev/chakra-ui"; -<%_ } _%> -<%_ if (answers[`ui-framework`] === "no") { _%> - import { AuthPage } from "@refinedev/core"; -<%_ } _%> - -import { GetServerSideProps } from "next"; -<%_ if (answers[`i18n-${answers["ui-framework"]}`] !== "no") { _%> -import { serverSideTranslations } from "next-i18next/serverSideTranslations"; -<%_ } _%> - -import { authProvider } from "src/authProvider"; - -<%_ if (selectedSvg && answers["ui-framework"] !== "no" ) { _%> -import { AppIcon } from "src/components/app-icon"; -<%_ } _%> - -export default function ForgotPassword() { - return ( - - title={( - - text="<%= selectedTitle %>" - <%_ } _%> - <%_ if (selectedSvg) { _%> - icon={} - <%_ } _%> - /> - )} - <%_ } _%> - /> - ); -} - -ForgotPassword.noLayout = true; - -export const getServerSideProps: GetServerSideProps<{}> = async (context) => { - const { authenticated } = await authProvider.check(context); - - <%_ if (answers[`i18n-${answers["ui-framework"]}`] !== "no") { _%> - const translateProps = await serverSideTranslations( - context.locale ?? "en", - ["common"], - ); - <%_ } _%> - - if (authenticated) { - return { - props: {}, - redirect: { - destination: `/`, - permanent: false, - }, - }; - } - - return { - props: { - <%_ if (answers[`i18n-${answers["ui-framework"]}`] !== "no") { _%> - ...translateProps, - <%_ } _%> - } - } -}; diff --git a/refine-nextjs/plugins/data-provider-supabase/pages/login/index.tsx b/refine-nextjs/plugins/data-provider-supabase/pages/login/index.tsx deleted file mode 100644 index a62336d42..000000000 --- a/refine-nextjs/plugins/data-provider-supabase/pages/login/index.tsx +++ /dev/null @@ -1,79 +0,0 @@ -<%_ if (answers["ui-framework"] === 'antd') { _%> - import { AuthPage, ThemedTitleV2 } from "@refinedev/antd"; -<%_ } _%> -<%_ if (answers["ui-framework"] === 'mui') { _%> - import { AuthPage, ThemedTitleV2 } from "@refinedev/mui"; -<%_ } _%> -<%_ if (answers["ui-framework"] === 'mantine') { _%> - import { AuthPage, ThemedTitleV2 } from "@refinedev/mantine"; -<%_ } _%> -<%_ if (answers["ui-framework"] === 'chakra') { _%> - import { AuthPage, ThemedTitleV2 } from "@refinedev/chakra-ui"; -<%_ } _%> -<%_ if (answers[`ui-framework`] === "no") { _%> - import { AuthPage } from "@refinedev/core"; -<%_ } _%> - -import { GetServerSideProps } from "next"; -<%_ if (answers[`i18n-${answers["ui-framework"]}`] !== "no") { _%> -import { serverSideTranslations } from "next-i18next/serverSideTranslations"; -<%_ } _%> - -import { authProvider } from "src/authProvider"; - -<%_ if (selectedSvg && answers["ui-framework"] !== "no" ) { _%> -import { AppIcon } from "src/components/app-icon"; -<%_ } _%> -export default function Login() { - return ( - - <%_ if ((selectedSvg || selectedTitle) && answers["ui-framework"] !== "no") { _%> - title={( - - text="<%= selectedTitle %>" - <%_ } _%> - <%_ if (selectedSvg) { _%> - icon={} - <%_ } _%> - /> - )} - <%_ } _%> - /> - ); -} - -Login.noLayout = true; - -export const getServerSideProps: GetServerSideProps<{}> = async (context) => { - const { authenticated } = await authProvider.check(context); - - <%_ if (answers[`i18n-${answers["ui-framework"]}`] !== "no") { _%> - const translateProps = await serverSideTranslations( - context.locale ?? "en", - ["common"], - ); - <%_ } _%> - - if (authenticated) { - return { - props: {}, - redirect: { - destination: `/`, - permanent: false, - }, - }; - } - - return { - props: { - <%_ if (answers[`i18n-${answers["ui-framework"]}`] !== "no") { _%> - ...translateProps, - <%_ } _%> - } - } -}; - diff --git a/refine-nextjs/plugins/data-provider-supabase/pages/register/index.tsx b/refine-nextjs/plugins/data-provider-supabase/pages/register/index.tsx deleted file mode 100644 index 24fea6637..000000000 --- a/refine-nextjs/plugins/data-provider-supabase/pages/register/index.tsx +++ /dev/null @@ -1,75 +0,0 @@ -<%_ if (answers["ui-framework"] === 'antd') { _%> - import { AuthPage, ThemedTitleV2 } from "@refinedev/antd"; -<%_ } _%> -<%_ if (answers["ui-framework"] === 'mui') { _%> - import { AuthPage, ThemedTitleV2 } from "@refinedev/mui"; -<%_ } _%> -<%_ if (answers["ui-framework"] === 'mantine') { _%> - import { AuthPage, ThemedTitleV2 } from "@refinedev/mantine"; -<%_ } _%> -<%_ if (answers["ui-framework"] === 'chakra') { _%> - import { AuthPage, ThemedTitleV2 } from "@refinedev/chakra-ui"; -<%_ } _%> -<%_ if (answers[`ui-framework`] === "no") { _%> - import { AuthPage } from "@refinedev/core"; -<%_ } _%> - -import { GetServerSideProps } from "next"; -<%_ if (answers[`i18n-${answers["ui-framework"]}`] !== "no") { _%> -import { serverSideTranslations } from "next-i18next/serverSideTranslations"; -<%_ } _%> - -import { authProvider } from "src/authProvider"; - -<%_ if (selectedSvg && answers["ui-framework"] !== "no" ) { _%> -import { AppIcon } from "src/components/app-icon"; -<%_ } _%> - -export default function Register() { - return ( - - title={( - - text="<%= selectedTitle %>" - <%_ } _%> - <%_ if (selectedSvg) { _%> - icon={} - <%_ } _%> - /> - )} - <%_ } _%> /> - ); -} - -Register.noLayout = true; - -export const getServerSideProps: GetServerSideProps<{}> = async (context) => { - const { authenticated } = await authProvider.check(context); - - <%_ if (answers[`i18n-${answers["ui-framework"]}`] !== "no") { _%> - const translateProps = await serverSideTranslations( - context.locale ?? "en", - ["common"], - ); - <%_ } _%> - - if (authenticated) { - return { - props: {}, - redirect: { - destination: `/`, - permanent: false, - }, - }; - } - - return { - props: { - <%_ if (answers[`i18n-${answers["ui-framework"]}`] !== "no") { _%> - ...translateProps, - <%_ } _%> - } - } -}; diff --git a/refine-nextjs/plugins/data-provider-supabase/src/app/forgot-password/page.tsx b/refine-nextjs/plugins/data-provider-supabase/src/app/forgot-password/page.tsx new file mode 100644 index 000000000..c2b0061f5 --- /dev/null +++ b/refine-nextjs/plugins/data-provider-supabase/src/app/forgot-password/page.tsx @@ -0,0 +1,24 @@ +import { AuthPage } from "@components/auth-page"; +import { authProviderServer } from "@providers/auth-provider"; +import { redirect } from "next/navigation"; + +export default async function ForgotPassword() { + const data = await getData(); + + if (data.authenticated) { + redirect(data?.redirectTo || "/"); + } + + return ; +} + +async function getData() { + const { authenticated, redirectTo, error } = + await authProviderServer.check(); + + return { + authenticated, + redirectTo, + error, + }; +} diff --git a/refine-nextjs/plugins/data-provider-supabase/src/app/login/page.tsx b/refine-nextjs/plugins/data-provider-supabase/src/app/login/page.tsx new file mode 100644 index 000000000..e4e77ff92 --- /dev/null +++ b/refine-nextjs/plugins/data-provider-supabase/src/app/login/page.tsx @@ -0,0 +1,24 @@ +import { AuthPage } from "@components/auth-page"; +import { authProviderServer } from "@providers/auth-provider"; +import { redirect } from "next/navigation"; + +export default async function Login() { + const data = await getData(); + + if (data.authenticated) { + redirect(data?.redirectTo || "/"); + } + + return ; +} + +async function getData() { + const { authenticated, redirectTo, error } = + await authProviderServer.check(); + + return { + authenticated, + redirectTo, + error, + }; +} diff --git a/refine-nextjs/plugins/data-provider-supabase/src/app/register/page.tsx b/refine-nextjs/plugins/data-provider-supabase/src/app/register/page.tsx new file mode 100644 index 000000000..b07acae8d --- /dev/null +++ b/refine-nextjs/plugins/data-provider-supabase/src/app/register/page.tsx @@ -0,0 +1,24 @@ +import { AuthPage } from "@components/auth-page"; +import { authProviderServer } from "@providers/auth-provider"; +import { redirect } from "next/navigation"; + +export default async function Register() { + const data = await getData(); + + if (data.authenticated) { + redirect(data?.redirectTo || "/"); + } + + return ; +} + +async function getData() { + const { authenticated, redirectTo, error } = + await authProviderServer.check(); + + return { + authenticated, + redirectTo, + error, + }; +} diff --git a/refine-nextjs/plugins/data-provider-supabase/src/providers/auth-provider/auth-provider.server.ts b/refine-nextjs/plugins/data-provider-supabase/src/providers/auth-provider/auth-provider.server.ts new file mode 100644 index 000000000..ade4d4736 --- /dev/null +++ b/refine-nextjs/plugins/data-provider-supabase/src/providers/auth-provider/auth-provider.server.ts @@ -0,0 +1,21 @@ +import { AuthBindings } from "@refinedev/core"; +import { cookies } from "next/headers"; + +export const authProviderServer: Pick = { + check: async () => { + const cookieStore = cookies(); + const auth = cookieStore.get("token"); + + if (auth) { + return { + authenticated: true, + }; + } + + return { + authenticated: false, + logout: true, + redirectTo: "/login", + }; + }, +}; diff --git a/refine-nextjs/plugins/data-provider-supabase/src/authProvider.ts b/refine-nextjs/plugins/data-provider-supabase/src/providers/auth-provider/auth-provider.ts similarity index 85% rename from refine-nextjs/plugins/data-provider-supabase/src/authProvider.ts rename to refine-nextjs/plugins/data-provider-supabase/src/providers/auth-provider/auth-provider.ts index c9f7ca106..8772fb217 100644 --- a/refine-nextjs/plugins/data-provider-supabase/src/authProvider.ts +++ b/refine-nextjs/plugins/data-provider-supabase/src/providers/auth-provider/auth-provider.ts @@ -1,7 +1,8 @@ -import { AuthBindings } from "@refinedev/core"; -import nookies from "nookies"; +"use client"; -import { supabaseClient } from "./utility"; +import { AuthBindings } from "@refinedev/core"; +import { supabaseClient } from "@utility/supabase-client"; +import Cookies from "js-cookie"; export const authProvider: AuthBindings = { login: async ({ email, password }) => { @@ -14,12 +15,12 @@ export const authProvider: AuthBindings = { return { success: false, error, - } + }; } if (data?.session) { - nookies.set(null, "token", data.session.access_token, { - maxAge: 30 * 24 * 60 * 60, + Cookies.set("token", data.session.access_token, { + expires: 30, // 30 days path: "/", }); @@ -39,7 +40,7 @@ export const authProvider: AuthBindings = { }; }, logout: async () => { - nookies.destroy(null, "token"); + Cookies.remove("token", { path: "/" }); const { error } = await supabaseClient.auth.signOut(); if (error) { @@ -60,14 +61,14 @@ export const authProvider: AuthBindings = { email, password, }); - + if (error) { return { success: false, error, }; } - + if (data) { return { success: true, @@ -80,7 +81,7 @@ export const authProvider: AuthBindings = { error, }; } - + return { success: false, error: { @@ -89,8 +90,8 @@ export const authProvider: AuthBindings = { }, }; }, - check: async (ctx) => { - const { token } = nookies.get(ctx); + check: async () => { + const token = Cookies.get("token"); const { data } = await supabaseClient.auth.getUser(token); const { user } = data; @@ -127,7 +128,12 @@ export const authProvider: AuthBindings = { return null; }, onError: async (error) => { - console.error(error); + if (error?.code === "PGRST301" || error?.code === 401) { + return { + logout: true, + }; + } + return { error }; }, }; diff --git a/refine-nextjs/plugins/data-provider-supabase/src/providers/auth-provider/index.ts b/refine-nextjs/plugins/data-provider-supabase/src/providers/auth-provider/index.ts new file mode 100644 index 000000000..b7f6d9fe9 --- /dev/null +++ b/refine-nextjs/plugins/data-provider-supabase/src/providers/auth-provider/index.ts @@ -0,0 +1,2 @@ +export * from './auth-provider' +export * from './auth-provider.server' diff --git a/refine-nextjs/plugins/data-provider-supabase/src/providers/data-provider/index.ts b/refine-nextjs/plugins/data-provider-supabase/src/providers/data-provider/index.ts new file mode 100644 index 000000000..afe23face --- /dev/null +++ b/refine-nextjs/plugins/data-provider-supabase/src/providers/data-provider/index.ts @@ -0,0 +1,6 @@ +"use client"; + +import { dataProvider as dataProviderSupabase } from "@refinedev/supabase"; +import { supabaseClient } from "@utility/supabase-client"; + +export const dataProvider = dataProviderSupabase(supabaseClient); diff --git a/refine-nextjs/plugins/data-provider-supabase/src/utility/index.ts b/refine-nextjs/plugins/data-provider-supabase/src/utility/index.ts deleted file mode 100644 index 1a2159651..000000000 --- a/refine-nextjs/plugins/data-provider-supabase/src/utility/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./supabaseClient"; diff --git a/refine-nextjs/plugins/data-provider-supabase/src/utility/supabaseClient.ts b/refine-nextjs/plugins/data-provider-supabase/src/utility/supabase-client.ts similarity index 99% rename from refine-nextjs/plugins/data-provider-supabase/src/utility/supabaseClient.ts rename to refine-nextjs/plugins/data-provider-supabase/src/utility/supabase-client.ts index 4368fd9f1..595273b8e 100644 --- a/refine-nextjs/plugins/data-provider-supabase/src/utility/supabaseClient.ts +++ b/refine-nextjs/plugins/data-provider-supabase/src/utility/supabase-client.ts @@ -11,4 +11,4 @@ export const supabaseClient = createClient(SUPABASE_URL, SUPABASE_KEY, { auth: { persistSession: true, }, -}); \ No newline at end of file +}); diff --git a/refine-nextjs/plugins/headless-example/package.json b/refine-nextjs/plugins/headless-example/package.json new file mode 100644 index 000000000..20dc8d7ec --- /dev/null +++ b/refine-nextjs/plugins/headless-example/package.json @@ -0,0 +1,8 @@ +{ + "dependencies": { + "@refinedev/react-hook-form": "^4.8.14", + "@refinedev/nextjs-router": "^6.0.0", + "@refinedev/react-table": "^5.6.6", + "@tanstack/react-table": "^8.2.6" + } +} diff --git a/refine-nextjs/plugins/headless-example/src/app/blog-posts/create/page.tsx b/refine-nextjs/plugins/headless-example/src/app/blog-posts/create/page.tsx new file mode 100644 index 000000000..efee9192c --- /dev/null +++ b/refine-nextjs/plugins/headless-example/src/app/blog-posts/create/page.tsx @@ -0,0 +1,144 @@ +"use client" + +import { + IResourceComponentsProps, + useNavigation, + useSelect, +} from "@refinedev/core"; +import { useForm } from "@refinedev/react-hook-form"; +import React from "react"; +<%_ if (answers["data-provider"] === "data-provider-hasura") { _%> + import { BLOG_POSTS_QUERY, BLOG_POSTS_CATEGORIES_SELECT_QUERY } from "@queries/blog-posts"; +<%_ } _%> +<%_ if (answers["data-provider"] === "data-provider-nestjs-query") { _%> + import { POST_CREATE_MUTATION, CATEGORIES_SELECT_QUERY } from "@queries/blog-posts"; +<%_ } _%> + +export default function BlogPostCreate() { + const { list } = useNavigation(); + + const { + refineCore: { onFinish }, + register, + handleSubmit, + formState: { errors }, + } = useForm({ +<%_ if (answers["data-provider"] === "data-provider-hasura") { _%> + refineCoreProps: { + meta: { + fields: BLOG_POSTS_QUERY, + }, + }, +<%_ } _%> +<%_ if (answers["data-provider"] === "data-provider-nestjs-query") { _%> + refineCoreProps: { + meta: { + gqlMutation: POST_CREATE_MUTATION, + }, + }, +<%_ } _%> + }); + + const { options: categoryOptions } = useSelect({ + resource: "categories", +<%_ if (answers["data-provider"] === "data-provider-hasura") { _%> + meta: { + fields: BLOG_POSTS_CATEGORIES_SELECT_QUERY, + }, +<%_ } _%> +<%_ if (answers["data-provider"] === "data-provider-nestjs-query") { _%> + meta: { + gqlQuery: CATEGORIES_SELECT_QUERY, + }, +<%_ } _%> + }); + + return ( +
+
+

Create

+
+ +
+
+
+
+ +