Просмотр исходного кода

Merge pull request #27851 from overleaf/slg-group-member-pricing-js-to-ts

[web] Migrate group-member-pricing.jsx to tsx

GitOrigin-RevId: f5fd95939f6af5dfaedb1fafeecec04ceb6612f6
Simon Gardner 1 год назад
Родитель
Сommit
ccd770f433

+ 5 - 1
services/web/frontend/js/utils/meta.ts

@@ -44,7 +44,10 @@ import {
 } from '../../../types/settings-page'
 import { SuggestedLanguage } from '../../../types/system-message'
 import type { TeamInvite } from '../../../types/team-invite'
-import { GroupPlans } from '../../../types/subscription/dashboard/group-plans'
+import {
+  GroupPlans,
+  GroupPlansData,
+} from '../../../types/subscription/dashboard/group-plans'
 import {
   GroupSSOLinkingStatus,
   SSOConfig,
@@ -125,6 +128,7 @@ export interface Meta {
   'ol-groupId': string
   'ol-groupName': string
   'ol-groupPlans': GroupPlans
+  'ol-groupPlansData': GroupPlansData
   'ol-groupPolicy': GroupPolicy
   'ol-groupSSOActive': boolean
   'ol-groupSSOConfig'?: SSOConfig

+ 29 - 0
services/web/types/subscription/dashboard/group-plans.ts

@@ -1,3 +1,7 @@
+// this import fails linting in CI if from '@ol-types/utils' so as a temporary workaround we'll use the relative path
+import { mkLiteralUnionTypeguard } from '../../utils'
+import { CurrencyCode } from '../currency'
+
 export type GroupPlans = {
   plans: {
     display: string
@@ -5,3 +9,28 @@ export type GroupPlans = {
   }[]
   sizes: string[]
 }
+
+export const planTypeGroup = ['collaborator', 'professional'] as const
+export type PlanTypeGroup = (typeof planTypeGroup)[number]
+export const isPlanTypeGroup = mkLiteralUnionTypeguard(planTypeGroup)
+
+export const planUsageType = ['enterprise', 'educational'] as const
+export type PlanUsageType = (typeof planUsageType)[number]
+export const isPlanUsageType = mkLiteralUnionTypeguard(planUsageType)
+
+export const licenseSize = ['2', '3', '4', '5', '10', '20'] as const
+export type LicenseSize = (typeof licenseSize)[number]
+export const isLicenseSize = mkLiteralUnionTypeguard(licenseSize)
+
+export type LicensePrice = {
+  price_in_cents: number
+  additional_license_legacy_price_in_cents: number
+}
+
+export type PlanPriceByLicenseSize = Record<LicenseSize, LicensePrice>
+
+export type PlanByCurrencyCode = Record<CurrencyCode, PlanPriceByLicenseSize>
+
+export type PlansByPlanTypeGroup = Record<PlanTypeGroup, PlanByCurrencyCode>
+
+export type GroupPlansData = Record<PlanUsageType, PlansByPlanTypeGroup>

+ 32 - 0
services/web/types/utils.ts

@@ -20,3 +20,35 @@ export type DeepPartial<T> = Partial<{ [P in keyof T]: DeepPartial<T[P]> }>
 export type MergeAndOverride<Parent, Own> = Own & Omit<Parent, keyof Own>
 
 export type Keys<T extends object> = (keyof T)[]
+
+/**
+ * Helper to create type guards for literal unions
+ *
+ * @example
+ * ```ts
+ * const fruit = ['apple', 'banana', 'cherry'] as const;
+ * type Fruit = typeof fruit[number];
+ * const isFruit = mkLiteralUnionTypeguard(fruit);
+ *
+ * // Usage example:
+ * function eatFood(food: unknown[]) {
+ *   food.forEach(item => {
+ *     if (isFruit(item)) {
+ *       eatFruit(item)
+ *     } else {
+ *       console.log(`Not fruit ${item}`)
+ *     }
+ *   })
+ * }
+ * eatFood(['banana', 'pizza'])
+ * ```
+ *
+ * @param xs A readonly tuple of allowed values (strings, numbers, or symbols).
+ * @returns A type guard function `(value: unknown) => value is T[number]`.
+ */
+export function mkLiteralUnionTypeguard<
+  const T extends readonly (string | number | symbol)[],
+>(xs: T) {
+  return (v: unknown): v is T[number] =>
+    (xs as readonly (string | number | symbol)[]).includes(v as any)
+}