orionplace-react 0.4.0 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/README.md +13 -2
  2. package/bin/orionplace-react.mjs +7 -0
  3. package/package.json +1 -1
  4. package/runtime/marketplace.d.mts +85 -0
  5. package/runtime/marketplace.mjs +490 -3
  6. package/src/project-readme.mjs +17 -2
  7. package/src/setup.mjs +1 -0
  8. package/src/sitemap.mjs +93 -0
  9. package/templates/app/StorefrontShell.tsx +8 -0
  10. package/templates/app/_storefront/PrivacyPage.tsx +15 -0
  11. package/templates/app/_storefront/storefrontRoutes.tsx +3 -0
  12. package/templates/app/privacy/page.tsx +9 -0
  13. package/templates/app/robots.txt/route.ts +11 -0
  14. package/templates/app/sitemap.xml/route.ts +12 -0
  15. package/templates/components/orionplace/account/ProfileDetailsForm.README.md +4 -0
  16. package/templates/components/orionplace/account/ProfileDetailsForm.tsx +7 -2
  17. package/templates/components/orionplace/blog/BlogArticle.README.md +16 -0
  18. package/templates/components/orionplace/blog/BlogArticle.module.css +5 -0
  19. package/templates/components/orionplace/blog/BlogArticle.tsx +60 -1
  20. package/templates/components/orionplace/cart/CartCheckoutDetails.README.md +4 -0
  21. package/templates/components/orionplace/cart/CartCheckoutDetails.tsx +20 -9
  22. package/templates/components/orionplace/legal/CookieNotice.README.md +42 -0
  23. package/templates/components/orionplace/legal/CookieNotice.module.css +48 -0
  24. package/templates/components/orionplace/legal/CookieNotice.tsx +82 -0
  25. package/templates/components/orionplace/legal/StorefrontPrivacy.README.md +49 -0
  26. package/templates/components/orionplace/legal/StorefrontPrivacy.module.css +166 -0
  27. package/templates/components/orionplace/legal/StorefrontPrivacy.tsx +83 -0
  28. package/templates/components/orionplace/products/ProductReviewImageViewer.README.md +13 -2
  29. package/templates/components/orionplace/products/ProductReviewImageViewer.module.css +10 -1
  30. package/templates/components/orionplace/products/ProductReviewImageViewer.tsx +61 -9
  31. package/templates/components/orionplace/storefront/StorefrontFooter.tsx +3 -0
  32. package/templates/interfaces/orionplace/accounts/IProfileData.ts +2 -0
  33. package/templates/interfaces/orionplace/appBase/IApploadUserProfile.ts +2 -0
  34. package/templates/lib/orionplace/blogImageViewer.ts +84 -0
  35. package/templates/lib/orionplace/blogLabels.ts +4 -0
  36. package/templates/lib/orionplace/cartLabels.ts +2 -0
  37. package/templates/lib/orionplace/footerLabels.ts +2 -0
  38. package/templates/lib/orionplace/pageMetadata.ts +1 -0
  39. package/templates/lib/orionplace/pageSeo.ts +10 -0
  40. package/templates/lib/orionplace/privacyLabels.ts +198 -0
  41. package/templates/lib/orionplace/profile.ts +12 -0
  42. package/templates/lib/orionplace/profileLabels.ts +2 -0
  43. package/templates/lib/orionplace/reviewLabels.ts +4 -0
  44. package/templates/proxy.ts +3 -2
@@ -72,6 +72,7 @@ export function storefrontSeoPage(pathname: string): StorefrontSeoPage {
72
72
  'sellers',
73
73
  'stores',
74
74
  'contact',
75
+ 'privacy',
75
76
  'tariffs',
76
77
  ...privatePages,
77
78
  ]);
@@ -44,6 +44,11 @@ const pageCopy = {
44
44
  'Контакты компании и обратная связь с магазином.',
45
45
  'контакты, сообщение',
46
46
  ],
47
+ privacy: [
48
+ 'Политика обработки персональных данных',
49
+ 'Какие данные получает магазин, зачем, кому передаёт, и какие cookie использует сайт.',
50
+ 'персональные данные, политика, cookie',
51
+ ],
47
52
  unsubscribe: [
48
53
  'Настройки рассылки',
49
54
  'Отписка от писем магазина.',
@@ -166,6 +171,11 @@ const pageCopy = {
166
171
  'Company contact details and a message form for the store.',
167
172
  'contact, message',
168
173
  ],
174
+ privacy: [
175
+ 'Privacy policy',
176
+ 'Which data the store receives, why, who receives it, and which cookies the site uses.',
177
+ 'personal data, privacy, cookies',
178
+ ],
169
179
  unsubscribe: [
170
180
  'Email preferences',
171
181
  'Unsubscribe from store emails.',
@@ -0,0 +1,198 @@
1
+ /*
2
+ * Texts of the privacy page (/privacy) and the cookie notice.
3
+ *
4
+ * The page describes what the storefront itself does: the account, orders,
5
+ * the two platform cookies and the notice's own storage mark. A store that
6
+ * adds analytics, chat widgets or other cookies lists them in the cookies
7
+ * section here. The operator is the store's company from the platform's
8
+ * contact details; `{company}` in a text is replaced with its name.
9
+ */
10
+
11
+ export interface PrivacySection {
12
+ id: string;
13
+ title: string;
14
+ text: string[];
15
+ }
16
+
17
+ export interface PrivacyLabels {
18
+ title: string;
19
+ lead: string;
20
+ contents: string;
21
+ operator: string;
22
+ operatorUnknown: string;
23
+ sections: PrivacySection[];
24
+ cookie: {
25
+ label: string;
26
+ text: string;
27
+ link: string;
28
+ ok: string;
29
+ };
30
+ }
31
+
32
+ /** Local storage mark: the visitor has dismissed the cookie notice. */
33
+ export const COOKIE_NOTICE_STORAGE_KEY = 'orionplace-cookie-notice-seen';
34
+
35
+ const ru: PrivacyLabels = {
36
+ title: 'Политика обработки персональных данных',
37
+ lead: 'Какие данные магазин получает, зачем, кому их передаёт и как долго хранит.',
38
+ contents: 'Содержание',
39
+ operator: 'Оператор персональных данных',
40
+ operatorUnknown: 'Реквизиты оператора указаны на странице «Контакты».',
41
+ sections: [
42
+ {
43
+ id: 'operator',
44
+ title: '1. Кто обрабатывает данные',
45
+ text: [
46
+ 'Оператор персональных данных — {company} (далее — Магазин). Реквизиты Магазина указаны в конце страницы.',
47
+ 'Обработка ведётся в соответствии с Федеральным законом № 152-ФЗ «О персональных данных».',
48
+ ],
49
+ },
50
+ {
51
+ id: 'data',
52
+ title: '2. Какие данные',
53
+ text: [
54
+ 'Аккаунт: номер телефона, а если вы их укажете — имя, адрес электронной почты, дата рождения и фото.',
55
+ 'Заказы: товары, адреса доставки, имя и телефон получателя, суммы, способ и статус оплаты, возвраты. Данные карты вводятся на странице платёжного провайдера; Магазин номера карт не получает.',
56
+ 'Обращения, отзывы и комментарии, избранное, подписки на товары и история поиска.',
57
+ 'История входов: дата и время, IP-адрес, браузер и тип устройства.',
58
+ ],
59
+ },
60
+ {
61
+ id: 'purposes',
62
+ title: '3. Зачем',
63
+ text: [
64
+ 'Чтобы вы могли войти, оформить, оплатить, получить и вернуть заказ, получить ответ на обращение и опубликовать отзыв; чтобы защищать аккаунт и выполнять требования закона. Письма о новинках и акциях приходят, только если вы их включили.',
65
+ ],
66
+ },
67
+ {
68
+ id: 'recipients',
69
+ title: '4. Кому передаются данные',
70
+ text: [
71
+ 'Только тем, без кого заказ не выполнить, и в нужном объёме: службам доставки, платёжным провайдерам, операторам связи (для кодов подтверждения) и платформе, на серверах которой работает Магазин. Данные не продаются.',
72
+ ],
73
+ },
74
+ {
75
+ id: 'storage',
76
+ title: '5. Сколько хранятся',
77
+ text: [
78
+ 'Пока существует аккаунт. Записи о заказах и платежах хранятся столько, сколько требует закон о бухгалтерском учёте.',
79
+ ],
80
+ },
81
+ {
82
+ id: 'rights',
83
+ title: '6. Ваши права',
84
+ text: [
85
+ 'В профиле можно изменить свои данные, отключить письма и удалить аккаунт. Также можно узнать, какие данные обрабатываются, потребовать их уточнить или удалить и отозвать согласие: напишите в поддержку или на странице «Контакты».',
86
+ ],
87
+ },
88
+ {
89
+ id: 'cookies',
90
+ title: '7. Cookie и локальное хранилище',
91
+ text: [
92
+ 'Сайт использует только необходимые для работы cookie: sessionid сохраняет вход в аккаунт, csrftoken защищает формы от подделки запросов.',
93
+ 'В локальном хранилище браузера сохраняется отметка о том, что вы видели уведомление о cookie. Рекламных и аналитических cookie нет. Если запретить cookie, вход и оформление заказа не будут работать.',
94
+ ],
95
+ },
96
+ {
97
+ id: 'changes',
98
+ title: '8. Изменение политики',
99
+ text: [
100
+ 'Новая редакция действует с момента публикации на этой странице.',
101
+ ],
102
+ },
103
+ ],
104
+ cookie: {
105
+ label: 'Уведомление о cookie',
106
+ text: 'Сайт использует только необходимые cookie: для входа в аккаунт и защиты форм.',
107
+ link: 'Подробнее',
108
+ ok: 'Понятно',
109
+ },
110
+ };
111
+
112
+ const en: PrivacyLabels = {
113
+ title: 'Privacy policy',
114
+ lead: 'Which data the store receives, why, who it shares it with and how long it keeps it.',
115
+ contents: 'Contents',
116
+ operator: 'Data controller',
117
+ operatorUnknown: 'The controller’s details are on the Contact page.',
118
+ sections: [
119
+ {
120
+ id: 'operator',
121
+ title: '1. Who processes the data',
122
+ text: [
123
+ 'The data controller is {company} (the Store). The Store’s details are at the end of this page.',
124
+ 'Data is processed under Russian Federal Law No. 152-FZ “On Personal Data”.',
125
+ ],
126
+ },
127
+ {
128
+ id: 'data',
129
+ title: '2. Which data',
130
+ text: [
131
+ 'Account: phone number and, if you add them, name, email address, date of birth and photo.',
132
+ 'Orders: products, delivery addresses, recipient name and phone, amounts, payment method and status, refunds. Card details are entered on the payment provider’s page; the Store does not receive card numbers.',
133
+ 'Support requests, reviews and comments, wishlist, product subscriptions and search history.',
134
+ 'Sign-in history: date and time, IP address, browser and device type.',
135
+ ],
136
+ },
137
+ {
138
+ id: 'purposes',
139
+ title: '3. Why',
140
+ text: [
141
+ 'To let you sign in, place, pay for, receive and return orders, get answers to requests and publish reviews; to protect the account and meet legal duties. News and promotion emails come only if you turned them on.',
142
+ ],
143
+ },
144
+ {
145
+ id: 'recipients',
146
+ title: '4. Who receives the data',
147
+ text: [
148
+ 'Only those needed to fulfil an order, and only as much as they need: delivery services, payment providers, telecom operators (for confirmation codes) and the platform whose servers run the Store. The data is not sold.',
149
+ ],
150
+ },
151
+ {
152
+ id: 'storage',
153
+ title: '5. How long it is kept',
154
+ text: [
155
+ 'While the account exists. Order and payment records are kept as long as accounting law requires.',
156
+ ],
157
+ },
158
+ {
159
+ id: 'rights',
160
+ title: '6. Your rights',
161
+ text: [
162
+ 'In the profile you can change your details, turn emails off and delete the account. You can also ask which data is processed, ask to correct or delete it and withdraw consent: write to support or use the Contact page.',
163
+ ],
164
+ },
165
+ {
166
+ id: 'cookies',
167
+ title: '7. Cookies and local storage',
168
+ text: [
169
+ 'The site uses only the cookies it needs to work: sessionid keeps you signed in, csrftoken protects forms from request forgery.',
170
+ 'The browser’s local storage keeps the fact that you have seen the cookie notice. There are no advertising or analytics cookies. If you block cookies, signing in and checking out do not work.',
171
+ ],
172
+ },
173
+ {
174
+ id: 'changes',
175
+ title: '8. Changes to this policy',
176
+ text: ['A new version applies from its publication on this page.'],
177
+ },
178
+ ],
179
+ cookie: {
180
+ label: 'Cookie notice',
181
+ text: 'The site uses only the cookies it needs: to sign you in and to protect forms.',
182
+ link: 'Learn more',
183
+ ok: 'OK',
184
+ },
185
+ };
186
+
187
+ export function privacyLabels(locale: string, company = ''): PrivacyLabels {
188
+ const copy = locale.toLowerCase().startsWith('ru') ? ru : en;
189
+ const name = company || (copy === ru ? 'Магазин' : 'the Store');
190
+
191
+ return {
192
+ ...copy,
193
+ sections: copy.sections.map((section) => ({
194
+ ...section,
195
+ text: section.text.map((line) => line.replaceAll('{company}', name)),
196
+ })),
197
+ };
198
+ }
@@ -34,6 +34,18 @@ export function profileDate(value: string | null | undefined) {
34
34
  : '';
35
35
  }
36
36
 
37
+ /** The name of a phone country code (`RU` → «Россия» / «Russia»); the code itself when the browser has no name. */
38
+ export function profileCountryName(code: string | null | undefined, locale: string) {
39
+ if (!code) {
40
+ return '';
41
+ }
42
+ try {
43
+ return new Intl.DisplayNames([locale], { type: 'region' }).of(code) || code;
44
+ } catch {
45
+ return code;
46
+ }
47
+ }
48
+
37
49
  export class ProfileRequestError extends Error {
38
50
  readonly kind = 'profile-request';
39
51
  readonly fields: Record<string, string>;
@@ -15,6 +15,7 @@ export function profileLabels(locale: string) {
15
15
  lastName: 'Фамилия',
16
16
  phone: 'Номер телефона',
17
17
  phoneHint: 'Номер телефона для входа.',
18
+ phoneCountryHint: 'Номер телефона для входа. Его страна, {country}, определяет доступные способы оплаты.',
18
19
  dob: 'Дата рождения',
19
20
  save: 'Сохранить',
20
21
  pending: 'Сохраняем…',
@@ -89,6 +90,7 @@ export function profileLabels(locale: string) {
89
90
  lastName: 'Last name',
90
91
  phone: 'Phone number',
91
92
  phoneHint: 'Your sign-in phone number.',
93
+ phoneCountryHint: 'Your sign-in phone number. Its country, {country}, decides which payment methods you can use.',
92
94
  dob: 'Date of birth',
93
95
  save: 'Save',
94
96
  pending: 'Saving…',
@@ -47,6 +47,8 @@ const en = {
47
47
  less: 'Less',
48
48
  gallery: 'Product images',
49
49
  previousImage: 'Previous image',
50
+ zoomIn: 'Show at full size',
51
+ zoomOut: 'Fit to screen',
50
52
  nextImage: 'Next image',
51
53
  thumbnailsBack: 'Show previous thumbnails',
52
54
  thumbnailsForward: 'Show next thumbnails',
@@ -124,6 +126,8 @@ const ru: typeof en = {
124
126
  less: 'Свернуть',
125
127
  gallery: 'Фотографии товара',
126
128
  previousImage: 'Предыдущая фотография',
129
+ zoomIn: 'Показать в полный размер',
130
+ zoomOut: 'Вписать в экран',
127
131
  nextImage: 'Следующая фотография',
128
132
  thumbnailsBack: 'Показать предыдущие миниатюры',
129
133
  thumbnailsForward: 'Показать следующие миниатюры',
@@ -50,7 +50,8 @@ export async function proxy(request: NextRequest) {
50
50
  return response;
51
51
  }
52
52
 
53
- // The gateway sets its own headers for /api; static assets keep their caching.
53
+ // The gateway sets its own headers for /api, robots.txt and the sitemap;
54
+ // static assets keep their caching.
54
55
  export const config = {
55
- matcher: ['/((?!api/|_next/static|_next/image|favicon.ico).*)'],
56
+ matcher: ['/((?!api/|_next/static|_next/image|favicon.ico|robots.txt|sitemap.xml).*)'],
56
57
  };