dashboard.mdc 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. ---
  2. description: Dashboard package
  3. globs: packages/dashboard/**/*
  4. alwaysApply: false
  5. ---
  6. The project in the /packages/dashboard dir uses the following stack. Please make sure to use these in any solutions:
  7. - React
  8. - Shadcn UI & tailwind
  9. - TanStack Query for data fetching, i.e. useQuery or useMutation. Not Apollo Client.
  10. - TanStack router for any routing & navigation
  11. ## API Interaction
  12. When creating useQuery or useMutation calls, use the following pattern as a guide:
  13. ```
  14. import { api } from '@/graphql/api.js';
  15. import { graphql } from '@/graphql/graphql.js';
  16. import { useQuery } from '@tanstack/react-query';
  17. const taxCategoriesDocument = graphql(`
  18. query TaxCategories($options: TaxCategoryListOptions) {
  19. taxCategories(options: $options) {
  20. items {
  21. id
  22. name
  23. isDefault
  24. }
  25. }
  26. }
  27. `);
  28. export function MyComponent() {
  29. const { data, isLoading, isPending, status } = useQuery({
  30. queryKey: ['taxCategories'],
  31. staleTime: 1000 * 60 * 5,
  32. queryFn: () =>
  33. api.query(taxCategoriesDocument, {
  34. options: {
  35. take: 100,
  36. },
  37. }),
  38. });
  39. }
  40. ```
  41. When performing mutations, use this example as a guide:
  42. ```tsx
  43. import { graphql } from '@/graphql/graphql.js';
  44. import { api } from '@/graphql/api.js';
  45. import { useMutation } from '@tanstack/react-query';
  46. const createProductOptionsMutation = graphql(`
  47. mutation CreateOptionGroups($input: CreateProductOptionGroupInput!) {
  48. createProductOptionGroup(input: $input) {
  49. id
  50. name
  51. options {
  52. id
  53. code
  54. name
  55. }
  56. }
  57. }
  58. `);
  59. export function MyComponent() {
  60. // Note that explicit typings or generic params should _not_ be needed since the
  61. // type info will flow from the use of the `graphql` function, which uses gql.tada.
  62. const createOptionGroupMutation = useMutation({
  63. // note that variables are not passed at this point of declaration
  64. mutationFn: api.mutate(createProductOptionsMutation),
  65. onSuccess: () => {
  66. // whatever makes sense, e.g. show toast
  67. },
  68. onError: () => {
  69. // whatever makes sense
  70. },
  71. });
  72. // ...
  73. function handleClick() {
  74. // variables are passed here
  75. createOptionGroupMutation.mutate({
  76. input: {
  77. // etc
  78. }
  79. })
  80. }
  81. //...
  82. }
  83. ```
  84. ## Package Layout
  85. The architecture of the dashboard is as follows:
  86. - /src/lib contains shared code that is used across the dashboard.
  87. - /src/app contains the routes and pages of the dashboard app.
  88. In the "app" context, we try as much as possible to use the same patterns across all pages. Most of the app routes
  89. are CRUD list/detail pages.
  90. - A representative list page is [administrators.tsx](mdc:packages/dashboard/src/app/routes/_authenticated/_administrators/administrators.tsx)
  91. - A representative detail page is [administrators_.$id.tsx](mdc:packages/dashboard/src/app/routes/_authenticated/_administrators/administrators_.$id.tsx)
  92. These examples show the common components, hooks and patterns that should be used across the app.
  93. In the "lib" context, we try to re-use components from the /src/lib/components dir, including preferring the Shadcn components
  94. as much as possible from the /src/lib/components/ui dir.
  95. ## Forms
  96. We have a special wrapper around the Shadcn react-hook-form components to make typical form controls
  97. more concise:
  98. ```
  99. <FormFieldWrapper
  100. control={form.control}
  101. name="facetValueIds"
  102. label={<Trans>Facet values</Trans>}
  103. render={({ field }) => (
  104. <AssignedFacetValues facetValues={entity?.facetValues ?? []} {...field} />
  105. )}
  106. />
  107. ```
  108. Please prefer this form over the raw Shadcn components where possible.
  109. ## Localization
  110. Any labels or user-facing messages should use localization following this example:
  111. ```tsx
  112. import { Trans, useLingui } from '@/lib/trans.js';
  113. export function MyComponent() {
  114. const { i18n } = useLingui();
  115. const message = i18n.t('This is a localized string')
  116. return (
  117. <div>
  118. <Trans>This is a localized string in the markup</Trans>
  119. </div>
  120. )
  121. }
  122. ```