From c2b138fe8c95ea9bd3df6a933e181b1d51d56053 Mon Sep 17 00:00:00 2001 From: Quentin AUBERT Date: Wed, 27 Nov 2024 17:02:33 +0100 Subject: [PATCH] Usage plan form id quite finished --- .../components/frontend/api/ApiPricing.tsx | 755 ++++++++++-------- .../src/components/utils/formatters.tsx | 12 +- .../javascript/src/style/components/btn.scss | 62 +- daikoku/javascript/src/types/api.ts | 7 +- 4 files changed, 467 insertions(+), 369 deletions(-) diff --git a/daikoku/javascript/src/components/frontend/api/ApiPricing.tsx b/daikoku/javascript/src/components/frontend/api/ApiPricing.tsx index 16f4ea293..4aed6c7c2 100644 --- a/daikoku/javascript/src/components/frontend/api/ApiPricing.tsx +++ b/daikoku/javascript/src/components/frontend/api/ApiPricing.tsx @@ -1,16 +1,16 @@ -import { getApolloContext } from '@apollo/client'; -import { constraints, Flow, format, Schema, type, Form, FlowObject } from '@maif/react-forms'; +import { constraints, Flow, Form, format, Schema, type } from '@maif/react-forms'; import { useQuery, useQueryClient } from '@tanstack/react-query'; import classNames from 'classnames'; import cloneDeep from 'lodash/cloneDeep'; import difference from 'lodash/difference'; import find from 'lodash/find'; import { nanoid } from 'nanoid'; -import { useContext, useEffect, useState } from 'react'; +import { memo, PropsWithChildren, useContext, useEffect, useState } from 'react'; import More from 'react-feather/dist/icons/more-vertical'; import { Link, useMatch, useNavigate } from 'react-router-dom'; import { toast } from 'sonner'; +import { GraphQLClient } from 'graphql-request'; import { I18nContext, ModalContext } from '../../../contexts'; import { GlobalContext } from '../../../contexts/globalContext'; import * as Services from '../../../services'; @@ -19,44 +19,39 @@ import { IApi, IBaseUsagePlan, IOtoroshiSettings, + isError, ISubscription, ISubscriptionDemand, - ISubscriptionWithApiInfo, + isValidationStepTeamAdmin, ITeamSimple, ITenantFull, IThirdPartyPaymentSettings, IUsagePlan, - UsagePlanVisibility, - isError, - isValidationStepTeamAdmin, + UsagePlanVisibility } from '../../../types'; import { CustomMetadataInput, OtoroshiEntitiesSelector } from '../../backoffice/apis/TeamApiPricings'; import { - api as API, - Can, - IMultistepsformStep, - MultiStepForm, - Option, - Spinner, access, + api as API, apikey, + Can, isPublish, isSubscriptionProcessIsAutomatic, manage, + Option, renderPlanInfo, - renderPricing + renderPricing, + Spinner } from '../../utils'; -import { formatPlanType } from '../../utils/formatters'; import { ApiDocumentation } from './ApiDocumentation'; import { ApiRedoc } from './ApiRedoc'; import { ApiSwagger } from './ApiSwagger'; -import { CustomizationForm } from '../../adminbackoffice/tenants/forms'; export const currency = (plan?: IBaseUsagePlan) => { if (!plan) { return ''; //todo: return undefined } - const cur = find(currencies, (c) => c.code === plan.currency.code); + const cur = find(currencies, (c) => c.code === plan.currency?.code); return `${cur?.name}(${cur?.symbol})`; }; @@ -77,6 +72,55 @@ type ApiPricingCardProps = { plans: Array }; +type MemoizedFormProps = { + plan: IUsagePlan + schema: Schema + flow: Flow + onSubmit: (plan: IUsagePlan) => void +} + +const isPlanEqual = (oldProps: MemoizedFormProps, newProps: MemoizedFormProps) => { + const oldPlan = oldProps.plan + const newPlan = newProps.plan + + //FIXME: better test with deepEqual for example or deep hash + + return oldPlan.customName === newPlan.customName && + oldPlan.customDescription === newPlan.customDescription && + oldPlan.otoroshiTarget?.otoroshiSettings === newPlan.otoroshiTarget?.otoroshiSettings && + oldPlan.otoroshiTarget?.authorizedEntities?.groups.length === newPlan.otoroshiTarget?.authorizedEntities?.groups.length && + oldPlan.otoroshiTarget?.authorizedEntities?.services.length === newPlan.otoroshiTarget?.authorizedEntities?.services.length && + oldPlan.otoroshiTarget?.authorizedEntities?.routes.length === newPlan.otoroshiTarget?.authorizedEntities?.routes.length +} +const MemoizedForm = memo((props: MemoizedFormProps) => { + return ( +
+ ) +}, isPlanEqual) + +const FormSection = (props: PropsWithChildren<{ label: string }>) => { + return ( +
+
+ {props.label} + {props.children} +
+ ) +} + const ApiPricingCard = (props: ApiPricingCardProps) => { const { Translation } = useContext(I18nContext); const { @@ -88,19 +132,15 @@ const ApiPricingCard = (props: ApiPricingCardProps) => { close, closeRightPanel } = useContext(ModalContext); - const { client } = useContext(getApolloContext()); - const { connectedUser, tenant } = useContext(GlobalContext); const queryClient = useQueryClient(); + const graphqlEndpoint = `${window.location.origin}/api/search`; + const customGraphQLClient = new GraphQLClient(graphqlEndpoint); + const showApiKeySelectModal = (team: string) => { const { plan } = props; - //FIXME: not bwaaagh !! - if (!client) { - return; - } - const askForApikeys = ( team: string, plan: IUsagePlan, @@ -140,20 +180,15 @@ const ApiPricingCard = (props: ApiPricingCardProps) => { Services.getAllTeamSubscriptions(team) .then((subscriptions) => - client - .query({ - query: Services.graphql.apisByIdsWithPlans, - variables: { ids: [...new Set(subscriptions.map((s) => s.api))] }, - }) - .then(({ data }) => ({ apis: data.apis, subscriptions })) + customGraphQLClient.request<{ apis: Array }>(Services.graphql.apisByIdsWithPlans, + { ids: [...new Set(subscriptions.map((s) => s.api))] }, + ) + .then(({ apis }) => ({ apis, subscriptions })) ) .then( ({ apis, subscriptions, - }: { - apis: Array; - subscriptions: Array; }) => { const int = subscriptions.map((subscription) => { const api = apis.find((a) => a._id === subscription.api); @@ -337,91 +372,68 @@ const ApiPricingCard = (props: ApiPricingCardProps) => { className="card-img-top card-link card-header" data-holder-rendered="true" > -
-