relation-input.tsx 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. import { graphql } from '@/vdb/graphql/graphql.js';
  2. import { createRelationSelectorConfig, RelationSelector } from './relation-selector.js';
  3. /**
  4. * Single relation input component
  5. */
  6. export interface SingleRelationInputProps<T = any> {
  7. value: string;
  8. onChange: (value: string) => void;
  9. config: Parameters<typeof createRelationSelectorConfig<T>>[0];
  10. disabled?: boolean;
  11. className?: string;
  12. /**
  13. * @description
  14. * Custom text for the selector label,
  15. * defaults to `Select item` or `Select items`
  16. */
  17. selectorLabel?: React.ReactNode;
  18. }
  19. export function SingleRelationInput<T>({
  20. value,
  21. onChange,
  22. config,
  23. disabled,
  24. className,
  25. selectorLabel,
  26. }: Readonly<SingleRelationInputProps<T>>) {
  27. const singleConfig = createRelationSelectorConfig<T>({
  28. ...config,
  29. multiple: false,
  30. });
  31. return (
  32. <RelationSelector
  33. config={singleConfig}
  34. value={value}
  35. selectorLabel={selectorLabel}
  36. onChange={newValue => onChange(newValue as string)}
  37. disabled={disabled}
  38. className={className}
  39. />
  40. );
  41. }
  42. /**
  43. * Multi relation input component
  44. */
  45. export interface MultiRelationInputProps<T = any> {
  46. value: string[];
  47. onChange: (value: string[]) => void;
  48. config: Parameters<typeof createRelationSelectorConfig<T>>[0];
  49. disabled?: boolean;
  50. className?: string;
  51. selectorLabel?: React.ReactNode;
  52. }
  53. export function MultiRelationInput<T>({
  54. value,
  55. onChange,
  56. config,
  57. disabled,
  58. className,
  59. selectorLabel,
  60. }: Readonly<MultiRelationInputProps<T>>) {
  61. const multiConfig = createRelationSelectorConfig<T>({
  62. ...config,
  63. multiple: true,
  64. });
  65. return (
  66. <RelationSelector
  67. config={multiConfig}
  68. value={value}
  69. onChange={newValue => onChange(newValue as string[])}
  70. disabled={disabled}
  71. className={className}
  72. selectorLabel={selectorLabel}
  73. />
  74. );
  75. }
  76. // Example configurations for common entities
  77. /**
  78. * Product relation selector configuration
  79. */
  80. export const productRelationConfig = createRelationSelectorConfig({
  81. listQuery: graphql(`
  82. query GetProductsForRelationSelector($options: ProductListOptions) {
  83. products(options: $options) {
  84. items {
  85. id
  86. name
  87. slug
  88. featuredAsset {
  89. id
  90. preview
  91. }
  92. }
  93. totalItems
  94. }
  95. }
  96. `),
  97. idKey: 'id' as const,
  98. labelKey: 'name' as const,
  99. placeholder: 'Search products...',
  100. buildSearchFilter: (term: string) => ({
  101. name: { contains: term },
  102. }),
  103. });
  104. /**
  105. * Customer relation selector configuration
  106. */
  107. export const customerRelationConfig = createRelationSelectorConfig({
  108. listQuery: graphql(`
  109. query GetCustomersForRelationSelector($options: CustomerListOptions) {
  110. customers(options: $options) {
  111. items {
  112. id
  113. firstName
  114. lastName
  115. emailAddress
  116. }
  117. totalItems
  118. }
  119. }
  120. `),
  121. idKey: 'id' as const,
  122. labelKey: 'emailAddress' as const,
  123. placeholder: 'Search customers...',
  124. buildSearchFilter: (term: string) => ({
  125. emailAddress: { contains: term },
  126. }),
  127. });
  128. /**
  129. * Collection relation selector configuration
  130. */
  131. export const collectionRelationConfig = createRelationSelectorConfig({
  132. listQuery: graphql(`
  133. query GetCollectionsForRelationSelector($options: CollectionListOptions) {
  134. collections(options: $options) {
  135. items {
  136. id
  137. name
  138. slug
  139. featuredAsset {
  140. id
  141. preview
  142. }
  143. }
  144. totalItems
  145. }
  146. }
  147. `),
  148. idKey: 'id' as const,
  149. labelKey: 'name' as const,
  150. placeholder: 'Search collections...',
  151. buildSearchFilter: (term: string) => ({
  152. name: { contains: term },
  153. }),
  154. });