commons.ts 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. import type { ColorScheme, IUserHasId } from '@growi/core';
  2. import {
  3. DevidedPagePath, Lang, AllLang,
  4. } from '@growi/core';
  5. import type { GetServerSideProps, GetServerSidePropsContext } from 'next';
  6. import type { SSRConfig, UserConfig } from 'next-i18next';
  7. import * as nextI18NextConfig from '^/config/next-i18next.config';
  8. import type { CrowiRequest } from '~/interfaces/crowi-request';
  9. import type { ISidebarConfig } from '~/interfaces/sidebar-config';
  10. import type { IUserUISettings } from '~/interfaces/user-ui-settings';
  11. import {
  12. useCurrentProductNavWidth, useCurrentSidebarContents, usePreferDrawerModeByUser, usePreferDrawerModeOnEditByUser, useSidebarCollapsed,
  13. } from '~/stores/ui';
  14. export type CommonProps = {
  15. namespacesRequired: string[], // i18next
  16. currentPathname: string,
  17. appTitle: string,
  18. siteUrl: string,
  19. confidential: string,
  20. customTitleTemplate: string,
  21. csrfToken: string,
  22. isContainerFluid: boolean,
  23. growiVersion: string,
  24. isMaintenanceMode: boolean,
  25. redirectDestination: string | null,
  26. isDefaultLogo: boolean,
  27. currentUser?: IUserHasId,
  28. forcedColorScheme?: ColorScheme,
  29. } & Partial<SSRConfig>;
  30. // eslint-disable-next-line max-len
  31. export const getServerSideCommonProps: GetServerSideProps<CommonProps> = async(context: GetServerSidePropsContext) => {
  32. const req = context.req as CrowiRequest<IUserHasId & any>;
  33. const { crowi, user } = req;
  34. const {
  35. appService, configManager, customizeService, attachmentService,
  36. } = crowi;
  37. const url = new URL(context.resolvedUrl, 'http://example.com');
  38. const currentPathname = decodeURIComponent(url.pathname);
  39. const isMaintenanceMode = appService.isMaintenanceMode();
  40. let currentUser;
  41. if (user != null) {
  42. currentUser = user.toObject();
  43. }
  44. // Redirect destination for page transition by next/link
  45. let redirectDestination: string | null = null;
  46. if (!crowi.aclService.isGuestAllowedToRead() && currentUser == null) {
  47. redirectDestination = '/login';
  48. }
  49. else if (!isMaintenanceMode && currentPathname === '/maintenance') {
  50. redirectDestination = '/';
  51. }
  52. else if (isMaintenanceMode && !currentPathname.match('/admin/*') && !(currentPathname === '/maintenance')) {
  53. redirectDestination = '/maintenance';
  54. }
  55. else {
  56. redirectDestination = null;
  57. }
  58. const isCustomizedLogoUploaded = await attachmentService.isBrandLogoExist();
  59. const isDefaultLogo = crowi.configManager.getConfig('crowi', 'customize:isDefaultLogo') || !isCustomizedLogoUploaded;
  60. const forcedColorScheme = crowi.customizeService.forcedColorScheme;
  61. const props: CommonProps = {
  62. namespacesRequired: ['translation'],
  63. currentPathname,
  64. appTitle: appService.getAppTitle(),
  65. siteUrl: configManager.getConfig('crowi', 'app:siteUrl'), // DON'T USE appService.getSiteUrl()
  66. confidential: appService.getAppConfidential() || '',
  67. customTitleTemplate: customizeService.customTitleTemplate,
  68. csrfToken: req.csrfToken(),
  69. isContainerFluid: configManager.getConfig('crowi', 'customize:isContainerFluid') ?? false,
  70. growiVersion: crowi.version,
  71. isMaintenanceMode,
  72. redirectDestination,
  73. currentUser,
  74. isDefaultLogo,
  75. forcedColorScheme,
  76. };
  77. return { props };
  78. };
  79. export const getNextI18NextConfig = async(
  80. // 'serverSideTranslations' method should be given from Next.js Page
  81. // because importing it in this file causes https://github.com/isaachinman/next-i18next/issues/1545
  82. serverSideTranslations: (
  83. initialLocale: string, namespacesRequired?: string[] | undefined, configOverride?: UserConfig | null, extraLocales?: string[] | false
  84. ) => Promise<SSRConfig>,
  85. context: GetServerSidePropsContext, namespacesRequired?: string[] | undefined, preloadAllLang = false,
  86. ): Promise<SSRConfig> => {
  87. const req: CrowiRequest = context.req as CrowiRequest;
  88. const { crowi, user } = req;
  89. const { configManager } = crowi;
  90. // determine language
  91. const locale = user?.lang
  92. ?? configManager.getConfig('crowi', 'app:globalLang') as Lang
  93. ?? Lang.en_US;
  94. const namespaces = ['commons'];
  95. if (namespacesRequired != null) {
  96. namespaces.push(...namespacesRequired);
  97. }
  98. // TODO: deprecate 'translation.json' in the future
  99. else {
  100. namespaces.push('translation');
  101. }
  102. return serverSideTranslations(locale, namespaces, nextI18NextConfig, preloadAllLang ? AllLang : false);
  103. };
  104. /**
  105. * Generate whole title string for the specified title
  106. * @param props
  107. * @param title
  108. */
  109. export const generateCustomTitle = (props: CommonProps, title: string): string => {
  110. return props.customTitleTemplate
  111. .replace('{{sitename}}', props.appTitle)
  112. .replace('{{pagepath}}', title)
  113. .replace('{{pagename}}', title);
  114. };
  115. /**
  116. * Generate whole title string for the specified page path
  117. * @param props
  118. * @param pagePath
  119. */
  120. export const generateCustomTitleForPage = (props: CommonProps, pagePath: string): string => {
  121. const dPagePath = new DevidedPagePath(pagePath, true, true);
  122. return props.customTitleTemplate
  123. .replace('{{sitename}}', props.appTitle)
  124. .replace('{{pagepath}}', pagePath)
  125. .replace('{{pagename}}', dPagePath.latter);
  126. };
  127. export const useInitSidebarConfig = (sidebarConfig: ISidebarConfig, userUISettings?: IUserUISettings): void => {
  128. // UserUISettings
  129. usePreferDrawerModeByUser(userUISettings?.preferDrawerModeByUser ?? sidebarConfig.isSidebarDrawerMode);
  130. usePreferDrawerModeOnEditByUser(userUISettings?.preferDrawerModeOnEditByUser);
  131. useSidebarCollapsed(userUISettings?.isSidebarCollapsed ?? sidebarConfig.isSidebarClosedAtDockMode);
  132. useCurrentSidebarContents(userUISettings?.currentSidebarContents);
  133. useCurrentProductNavWidth(userUISettings?.currentProductNavWidth);
  134. };