diff --git a/src/pages/account/3Software.vue b/_old/3Software.vue similarity index 100% rename from src/pages/account/3Software.vue rename to _old/3Software.vue diff --git a/backend/data/db.sqlite-shm b/backend/data/db.sqlite-shm index 98fc8ad..92721a1 100644 Binary files a/backend/data/db.sqlite-shm and b/backend/data/db.sqlite-shm differ diff --git a/backend/data/db.sqlite-wal b/backend/data/db.sqlite-wal index 212b4c1..95ef291 100644 Binary files a/backend/data/db.sqlite-wal and b/backend/data/db.sqlite-wal differ diff --git a/backend/data/log.sqlite b/backend/data/log.sqlite index f51bc02..8d18774 100644 Binary files a/backend/data/log.sqlite and b/backend/data/log.sqlite differ diff --git a/backend/docs/triggers_v2.xlsx b/backend/docs/triggers_v2.xlsx new file mode 100644 index 0000000..49a4ff4 Binary files /dev/null and b/backend/docs/triggers_v2.xlsx differ diff --git a/i18n-2.xlsm b/i18n-2.xlsm index cb52bd8..0768376 100644 Binary files a/i18n-2.xlsm and b/i18n-2.xlsm differ diff --git a/public/doc/Terms_of_use_en.txt b/public/doc/Terms_of_use_en.txt deleted file mode 100644 index c652f4d..0000000 --- a/public/doc/Terms_of_use_en.txt +++ /dev/null @@ -1,30 +0,0 @@ -Software SURVy (the “Tool”) to facilitate your selection CCTV products based on your needs. -Before you start using the Tool, we ask you to carefully read through the below terms of use ("Terms of Use") and make sure that you have understood them prior to any use of the Tool. By downloading, installing, activating, accessing or otherwise using the Tool, you agree to be bound by the terms and conditions of the Terms of Use. If you are executing the Terms of Use on behalf of an entity, you represent that you have authority to legally bind that entity. If you do not have such authority or you do not agree to the terms and conditions of the Terms of Use, neither you nor the entity is permitted to and must not download, install, access or use the Tool. -The Tool developer ("Developer") - Individual Entrepreneur/Sole Proprietor Martyshkin Alexey Alexandrovich (Russia, Moscow, PSRNSP/Primary State Registration Number of the Sole Proprietor 318774600262084, ITN/Individual Taxpayer Number 366316608346). All rights to software SURVy belong to Developer. -By "Developer Representatives" in this document means to the circle of persons involved by Developer for development and support of the Tool. - -TERMS OF USE -The Tool is provided for guidance only. The estimates, recommendations and calculation results (collectively the "Deliverables") produced by the use of the Tool are only orientational. -DEVELOPER AND/OR ITS REPRESENTATIVES WILL IN NO EVENT BE RESPONSIBLE FOR DAMAGES OF ANY NATURE WHATSOEVER RESULTING FROM THE USE OF, OR RELIANCE UPON, THE TOOL AND THE DELIVERABLES. -The Tool for authorization use HttpOnly cookies-files. Also in local memory of your web browser (known as "local storage") stored language settings. - -Consent to Use of Data -Your projects will be stored on Developer servers. By agreeing to these terms of use, you accept that your project data will be used by Developer and/or its representatives for internal purposes (such as subsequent improving the Tool). -Rest assured that will Developer and/or its representatives intentionally not share or transfer about your projects to anyone. -Developer can use email address specified in the account to send notifications about changes to these Terms, request feedback on the use of the Tool and provide technical support. - -Restrictions -You may not (and you may not allow anyone else to): -(i) reverse engineer, decompile, disassemble or otherwise attempt to derive access to the source code of the Tool, or any part thereof, -(ii) misuse the Tool by interfering with its normal operation, or attempting to access it using a method other than through the interfaces and instructions that provide, -(iii) submit or upload any data or content that is illegal or violates these Terms of Use, -(iv) use the Tool on the territory of Russian Federation for objects of state-owned enterprises/institutions (including companies with state participation), as well as for those objects whose data can be identified as classified information. -The data submitted by you by use of the Tool may not exceed 1 GB. -Developer reserves the right to delete your data (account and projects) in its sole discretion. -You undertake to indemnify and hold Developer and/or its representatives harmless for all damages and losses incurred due to any breach of the undertakings in this Section. - -DISCLAIMER -THE TOOL AND ANY DELIVERABLES ARE DELIVERED FREE OF CHARGE AND 'AS IS' WITHOUT WARRANTY OF ANY KIND. THE ENTIRE RISK AS TO THE RESULTS AND PERFORMANCE OF THE TOOL AND THE DELIVERABLES IS ASSUMED BY YOU/THE USER. DEVELOPER DISCLAIMS ALL WARRANTIES, WHETHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT, OR ANY WARRANTY ARISING OUT OF ANY PROPOSAL, SPECIFICATION OR SAMPLE WITH RESPECT TO THE TOOL AND DELIVERABLES. DEVELOPER AND/OR ITS REPRESENTATIVES SHALL NOT BE LIABLE FOR LOSS OF DATA, LOSS OF PRODUCTION, LOSS OF PROFIT, LOSS OF USE, LOSS OF CONTRACTS OR FOR ANY OTHER CONSEQUENTIAL, ECONOMIC OR INDIRECT LOSS WHATSOEVER IN RESPECT OF DELIVERY, USE OR DISPOSITION OF THE TOOL AND THE DELIVERABLES. DEVELOPER AND/OR ITS REPRESENTATIVES TOTAL LIABILITY FOR ANY AND ALL CLAIMS, DAMAGES AND LIABILITY IN ACCORDANCE WITH THE DELIVERY AND USE OF THE TOOL AND THE DELIVERABLES SHALL NOT EXCEED THE PRICE PAID FOR THE TOOL. - -Governing law and dispute resolution -These Terms of Use shall be deemed performed in and shall be construed and governed by the laws of Russian Federation. diff --git a/public/telegram_star.svg b/public/telegram_star.svg new file mode 100644 index 0000000..b89fd41 --- /dev/null +++ b/public/telegram_star.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/boot/axios.ts b/src/boot/axios.ts index adde349..e74f12d 100644 --- a/src/boot/axios.ts +++ b/src/boot/axios.ts @@ -1,5 +1,6 @@ import { defineBoot } from '#q-app/wrappers' import axios, { type AxiosError } from 'axios' +import { Notify } from 'quasar' class ServerError extends Error { constructor( @@ -19,6 +20,7 @@ const api = axios.create({ api.interceptors.response.use( response => response, async (error: AxiosError<{ error?: { code: string; message: string } }>) => { + console.log(error) const errorData = error.response?.data?.error || { code: 'ZERO', message: error.message || 'Unknown error' @@ -29,6 +31,12 @@ api.interceptors.response.use( errorData.message ) + Notify.create({ + type: 'negative', + message: errorData.code + ': ' + errorData.message, + icon: 'mdi-alert-outline', + position: 'bottom' + }) return Promise.reject(serverError) } ) diff --git a/src/components/companyInfoPersons.vue b/src/components/companyInfoPersons.vue deleted file mode 100644 index 5bb1a46..0000000 --- a/src/components/companyInfoPersons.vue +++ /dev/null @@ -1,96 +0,0 @@ - - - - - diff --git a/src/components/docBlock.vue b/src/components/docBlock.vue index 199e43f..53cc7cb 100644 --- a/src/components/docBlock.vue +++ b/src/components/docBlock.vue @@ -34,37 +34,46 @@ import { ref, onMounted } from 'vue' import { useSettingsStore } from 'stores/settings' - const fileText = ref('') - const isLoading = ref(true) - const error = ref(false) - const settingsStore = useSettingsStore() - const lang = ref('EN') - const props = defineProps<{ type: 'terms_of_use' | 'privacy' }>() - function parseLocale(locale: string): string { - return locale.split(/[-_]/)[0] ?? '' + const settingsStore = useSettingsStore() + const fileText = ref('') + const isLoading = ref(true) + const DEFAULT_LANG = 'ru' + + const baseDocName = props.type === 'terms_of_use' + ? 'Terms_of_use' + : 'Privacy' + + const parseLocale = (locale: string) => locale.split(/[-_]/)[0] || DEFAULT_LANG + + const fetchDocument = async (language: string) => { + try { + const response = await fetch(`/admin/doc/${baseDocName}_${language}.txt`) + if (!response.ok) throw new Error(`HTTP ${response.status}`) + return await response.text() + } catch (error) { + console.error(`Failed to load ${language} version:`, error) + return null + } } - const baseDocName = - props.type ==='terms_of_use' ? 'Terms_of_use' : 'Privacy' - onMounted(async () => { - const locale = settingsStore.settings.locale - lang.value = parseLocale(locale) try { - const response = await fetch('/admin/doc/' + baseDocName + '_' + lang.value +'.txt') + const lang = parseLocale(settingsStore.settings.locale) - if (!response.ok) { - throw new Error(`HTTP error! Status: ${response.status}`) + fileText.value = await fetchDocument(lang) + + if (!fileText.value && lang !== DEFAULT_LANG) { + fileText.value = await fetchDocument(DEFAULT_LANG) } - fileText.value = await response.text() - } catch (err) { - console.error('File load error:', err) - error.value = true + if (!fileText.value) throw new Error('All loading attempts failed') + + } catch (error) { + console.error('Document loading failed:', error) } finally { isLoading.value = false } diff --git a/src/components/pnItemBtmDialog.vue b/src/components/pnItemBtmDialog.vue new file mode 100644 index 0000000..c50c224 --- /dev/null +++ b/src/components/pnItemBtmDialog.vue @@ -0,0 +1,125 @@ + + + + + diff --git a/src/components/pnListSelector.vue b/src/components/pnListSelector.vue new file mode 100644 index 0000000..b70a1ee --- /dev/null +++ b/src/components/pnListSelector.vue @@ -0,0 +1,53 @@ + + + + + \ No newline at end of file diff --git a/src/components/pnSmallDialog.vue b/src/components/pnSmallDialog.vue index 39a6c88..8502ba3 100644 --- a/src/components/pnSmallDialog.vue +++ b/src/components/pnSmallDialog.vue @@ -1,8 +1,9 @@ @@ -83,5 +89,5 @@ - diff --git a/src/components/pnTimeZoneSelector.vue b/src/components/pnTimeZoneSelector.vue new file mode 100644 index 0000000..2068db4 --- /dev/null +++ b/src/components/pnTimeZoneSelector.vue @@ -0,0 +1,140 @@ + + + + + diff --git a/src/i18n/en-US/index.ts b/src/i18n/en-US/index.ts index a31af33..75c2dee 100644 --- a/src/i18n/en-US/index.ts +++ b/src/i18n/en-US/index.ts @@ -1 +1 @@ -export default { EN: 'EN', RU: 'RU', continue: 'Continue', back: 'Back', close: 'Close', cancel: 'Cancel', code: 'Code', month: 'month', months: 'months', slogan: 'Work together - it\'s magic!', under_construction: 'Under construction.', login__email: 'E-mail', login__password: 'Password', login__forgot_password: 'Forgot Password?', login__sign_in: 'Log in', login__incorrect_login_data: 'User data not found. Edit your auth details before continuing', login__or_continue_as: 'or continue as', login__terms_of_use: 'Terms of use', login__accept_terms_of_use: 'I accept the', login__register: 'Create account', login__registration_message_error: 'Error', login__licensing_agreement: 'Licensing agreement', login__have_account: 'Already have an accont?', login__incorrect_email: 'Please enter a valid email address', login__password_require: 'At least 8 characters', user__logout: 'Logout', projects__projects: 'Projects', projects__show_archive: 'Show archive', projects__hide_archive: 'Hide archive', projects__restore_archive_warning: 'Attention!', projects__restore_archive_warning_message: 'Before restoring the project from the archive, verify that the bot is present in the project chats.', project__chats: 'Chats', project__users: 'Team', project__companies: 'Companies', project__edit: 'Edit', project__backup: 'Backup', project__archive: 'Archive', project__archive_warning: 'Are you sure?', project__archive_warning_message: 'Chat tracking in the project will be disabled after moving to the archive.', project__delete: 'Delete', project__delete_warning: 'Warning!', project__delete_warning_message: 'All project data will be removed. This action cannot be undone.', project_chats__search: 'Search', project_chats__send_chat: 'Request for attach chat', project_chats__send_chat_description: 'Provide instructions to the chat admin', project_chats__attach_chat: 'Attach chat', project_chats__attach_chat_description: 'Requires chat administrator privileges', project_chats_disabled_FAB: 'To add chats, please use the Telegram app', project_chats__send_chat_title: 'To connect the chat to ProjectsNode, add the bot to it using the provided link:', project_chat__delete_warning: 'Warning!', project_chat__delete_warning_message: 'Chat tracking will be discontinued. If necessary, the cat can be attached again.', project_create__title_card: 'New project', project_create__btn: 'Create', project_edit__title_card: 'Edit project', project_edit__btn: 'Apply', project_block__project_name: 'Name', project_block__project_description: 'Description', project_block__image_use_as_background_chats: 'logo as background for chats', project_block__error_name: 'Field is required', forgot_password__password_recovery: 'Password recovery', account_helper__enter_email: 'Enter account e-mail', account_helper__email: 'E-mail', account_helper__confirm_email: 'Confirm e-mail', account_helper__confirm_email_message: 'Enter the Code from e-mail to continue. If you haven\'t received an e-mail with the Code, check the Spam folder.', account_helper__code: 'Code', account_helper__code_error: 'Incorrect code. Ensure your e-mail is correct and try again.', account_helper__set_password: 'Set password', account_helper__password: 'Password', account_helper__finish: 'Finish', account_helper__register_message1: 'Welcome!', account_helper__forgot_password_message1: 'Password set!', account_helper__change_password_message1: 'Password changed!', account_helper__change_method_message1: 'Login method changed!', account_helper__go_projects: 'Go to projects…', account_change_email__title: 'Change account e-mail', account_change_email__current_email: 'Current account e-mail', account_change_email__email: 'E-mail', account_change_email__confirm_current_email: 'Confirm current e-mail', account_change_email__confirm_email_message: 'Enter the Code from e-mail to continue. If you haven\'t received an e-mail with the Code, check the Spam folder.', account_change_email__code: 'Code', account_change_email__code_error: 'Incorrect code. Ensure your e-mail is correct and try again.', account_change_email__new_email: 'New account e-mail', account_change_email__confirm_new_email: 'Confirm new e-mail', account_change_email__set_password: 'Set password', account_change_email__password: 'Password', account_change_email__finish: 'Finish', account_change_email__finish_after_message: 'Done!', account_change_email__ok_message1: 'The email address has been successfully updated!', account_change_email__ok_message2: 'Go to account…', account__user_settings: 'User settings', account__your_company: 'Your company', account__change_auth_message_2: 'After creating a user, all data from the Telegram account will be transferred to the new account.', account__change_auth_btn: 'Create system account', account__change_auth_warning: 'WARNING!', account__change_auth_warning_message: 'Reverse data transfer is not possible.', account__chats: 'Chats', account__chats_active: 'Active', account__chats_unbound: 'Unbound', account__chats_free: 'Free', account__chats_total: 'Total', account__subscribe: 'Subscribe', account__subscribe_description: 'With a subscription, you can attach more active chats.', account__auth_change_method: 'Change authorization method', account__auth_change_method_description: 'In case of corporate use, it is recommended to log in with a username and password.', account__auth_change_password: 'Change account password', account__auth_change_password_description: 'Access to the email address used for system login is required.', account__auth_change_account: 'Change account e-mail', account__auth_change_account_description: 'Access to both the current and new email addresses used for system authentication is required.', account__company_data: 'Your company data', account__company_data_description: 'The description will be automatically added to your company list for new projects.', account__manual: 'Manual', account__manual_description: 'Go to our Telegram channel with video tutorials.', account__settings: 'Settings', account__settings_description: 'Fonts size, language and etc.', account__support: 'Support', account__support_description: 'Need help? Contact us!', account__3rd_party_software: '3rd party software', account__3rd_party_software_description: 'List of third-party software packages included in the software', account__terms_of_use: 'Terms of use', account__privacy: 'Privacy and Cookie Policy', account__change_password: 'Change password', account__change_auth_method: 'Change authorization method', account_company__title_card: 'My company', account_company__btn: 'Apply', company__no_company: 'Not specified', company__my_company: 'My company', company_edit__title_card: 'Add company', company_edit__btn: 'Add', company_edit__title_card: 'Edit company', company_edit__btn: 'Apply', company_edit__my_company: 'My company', company_edit__my_company_hint: 'Form pre-filling is configured in \n Account > Your company data', company_block__name: 'Name', company_block__error_name: 'Field is required', company_block__description: 'Description', company_block__users: 'Persons', company_create__title_card: 'Add company', company__dialog_delete_title: 'WARNING!', company__dialog_delete_message: 'Company removal is irreversible.', company__dialog_delete_ok: 'Delete', company__mask: 'Cloacking', mask__title_table: 'Excluded', mask__help_title: 'Cloaking ', mask__help_message1: 'Cloaking conceals a company by making its personnel appear as if they belong to other companies, except those listed as "Visible"', mask__help_message2: 'Use the Toggle to enable or disable cloaking. Configure exceptions using the "+" button.', mask__help_message3: 'Your company\'s employees will see all companies, regardless of the cloaking settings.', mask__table_header_company: 'Company', mask__table_header_visible: 'Visible', mask__table_visible_none: 'None', mask__table_visible_all: 'All', project_users__search: 'Search', user_edit__title_card: 'Edit person', user_edit__btn: 'Apply', user_block__name: 'Name', user_block__company: 'Company', user_block__department: 'Department', user_block__role: 'Role', user_block__no_company: 'Not specified', user_block__user_blocked: 'BLOCKED', user_block__user_leave: 'Inactive', settings__title: 'Settings', settings__language: 'Language', settings__font_size: 'Font size', terms__title: 'Terms of use', subscribe__title: 'Subscribe', subscribe__current_balance: 'Current balance', subscribe__token_formula: '1 = 1 day of access to 1 chat', subscribe__token_formula_description: 'unbound and free chats are not counted', subscribe__info: 'With a subscription, you can attach more chats. Archived chats are not counted.', subscribe__about: 'about', subscribe__select_payment_1: 'You can pay for your subscription using ', subscribe__select_payment_2: 'Telegram stars', subscribe__select_option_1: 'Telegram stars', subscribe__select_option_2: 'Telegram stars', subscribe__select_option_3: 'Telegram stars', subscribe__select_option_user: 'Telegram stars', support__title: 'Support', support__ask_question: 'Ask Question', support__work_time_text: 'Support is available on weekdays', support__work_time_time: '10:00 - 19:00 (Moscow, GMT+3)', support__or: 'or contact us via email', AUTH_ERROR: 'Incorrect e-mail or password!', projects__lets_start: 'Create a Project', projects__lets_start_description: 'Projects isolate data: contacts, tasks, documents, and chats are visible only to members', project_chat__onboard_msg1: 'Attach chats to the project', project_chat__onboard_msg2: 'Chat control is enabled from the moment of attachment', project_users__onboard_msg1: 'Project Contact List', project_users__onboard_msg2: 'After attaching chats, members are imported automatically. You’ll need to define who is who', company__onboard_msg1: 'Add Companies', company__onboard_msg2: 'Recommended for projects involving 3+ companies', software__title: '3rd party software', software__description: 'This software contains third-party software packages.', error404: 'Oops. Nothing here…' } \ No newline at end of file +export default { EN: 'EN', RU: 'RU', continue: 'Continue', back: 'Back', close: 'Close', cancel: 'Cancel', code: 'Code', month: 'month', months: 'months', slogan: 'Work together - it\'s magic!', under_construction: 'Under construction.', login__email: 'E-mail', login__password: 'Password', login__forgot_password: 'Forgot Password?', login__sign_in: 'Log in', login__incorrect_login_data: 'User data not found. Edit your auth details before continuing', login__or_continue_as: 'or continue as', login__terms_of_use: 'Terms of use', login__accept_terms_of_use: 'I accept the', login__register: 'Create account', login__registration_message_error: 'Error', login__licensing_agreement: 'Licensing agreement', login__have_account: 'Already have an accont?', login__incorrect_email: 'Please enter a valid email address', login__password_require: 'At least 8 characters', user__logout: 'Logout', projects__projects: 'Projects', projects__search: 'Search', projects__show_archive: 'Show archive', projects__hide_archive: 'Hide archive', projects__dialog_archive_title: 'Archive project?', projects__dialog_archive_message: 'Chat tracking will stop.', projects__dialog_archive_message2: 'Chat data during archiving will be lost!', projects__dialog_archive_ok: 'Archive', projects__dialog_restore_title: 'Restore project?', projects__dialog_restore_message: 'Chat tracking will resume.', projects__dialog_restore_message2: 'Archive period data won\'t be recovered!', projects__dialog_restore_ok: 'Restore', projects__lets_start: 'Create a Project', projects__lets_start_description: 'Projects isolate data: contacts, tasks, documents, and chats are visible only to members', project__chats: 'Chats', project__users: 'Team', project__companies: 'Companies', project_create__title_card: 'New project', project_create__btn: 'Create', project_edit__title_card: 'Edit project', project_edit__btn: 'Apply', project_block__project_name: 'Name', project_block__project_description: 'Description', project_block__image_use_as_background_chats: 'logo as background for chats', project_block__error_name: 'Field is required', chats__search: 'Search', chats__send_chat: 'Request for attach chat', chats__send_chat_description: 'Provide instructions to the chat admin', chats__attach_chat: 'Attach chat', chats__attach_chat_description: 'Requires chat administrator privileges', chats_disabled_FAB: 'To add chats, please use the Telegram app', chats__send_chat_title: 'To connect the chat to ProjectsNode, add the bot to it using the provided link:', chats__dialog_unlink_title: 'Unlink chat?', chats__dialog_unlink_message: 'Chat tracking will be discontinued.', chats__dialog_unlink_message2: 'If necessary, the cat can be attached again.', chats__dialog_unlink_ok: 'Unlink', chats__onboard_msg1: 'Attach chats to the project', chats__onboard_msg2: 'Chat control is enabled from the moment of attachment', users__search: 'Search', users__show_blocked_users: 'Show Blocked', users__hide_blocked_users: 'Hide Blocked', users__show_left_users: 'Show Leavers (inactive)', users__hide_left_users: 'Hide Leavers (inactive)', users__dialog_block_title: 'Block Employee?', users__dialog_block_message: 'System access will be disabled.', users__dialog_block_message2: 'The employee will be removed from all chats (except those where they are the owner).', users__dialog_block_ok: 'Block', users__dialog_restore_title: 'Restore Employee?', users__dialog_restore_message: 'System access will be restored.', users__dialog_restore_message2: 'Add them to chats manually if required.', users__dialog_restore_ok: 'Restore', users__onboard_msg1: 'Project Contact List', users__onboard_msg2: 'After attaching chats, members are imported automatically. You’ll need to define who is who', user_edit__title_card: 'Edit employee', user_edit__btn: 'Apply', user_block__name: 'Name', user_block__company: 'Company', user_block__department: 'Department', user_block__role: 'Role', user_block__no_company: 'Not specified', user_block__user_blocked: 'BLOCKED', user_block__user_leave: 'Inactive', companies__dialog_delete_title: 'Delete company?', companies__dialog_delete_message: 'This action cannot be undone!', companies__dialog_delete_message2: 'Company employees will be moved to \'No Company\'', companies__dialog_delete_ok: 'Delete', companies__mask: 'Cloacking', companies__my_company: 'My company', companies__onboard_msg1: 'Add Companies', companies__onboard_msg2: 'Recommended for projects involving 3+ companies', company_add__title_card: 'Add company', company_add__btn: 'Add', company_edit__title_card: 'Edit company', company_edit__btn: 'Apply', company_edit__my_company: 'My company', company_edit__my_company_hint: 'Form pre-filling is configured in \n Account > Your company data', company_block__name: 'Name', company_block__error_name: 'Field is required', company_block__description: 'Description', company_block__users: 'Employees', mask__title_table: 'Excluded', mask__help_title: 'Cloaking ', mask__help_message1: 'Cloaking conceals a company by making its personnel appear as if they belong to other companies, except those listed as "Visible"', mask__help_message2: 'Use the Toggle to enable or disable cloaking. Configure exceptions using the "+" button.', mask__help_message3: 'Your company\'s employees will see all companies, regardless of the cloaking settings.', mask__table_header_company: 'Company', mask__table_header_visible: 'Visible', mask__table_visible_none: 'None', mask__table_visible_all: 'All', account_helper__enter_email: 'Enter account e-mail', account_helper__email: 'E-mail', account_helper__confirm_email: 'Confirm e-mail', account_helper__confirm_email_message: 'Enter the Code from e-mail to continue. If you haven\'t received an e-mail with the Code, check the Spam folder.', account_helper__code: 'Code', account_helper__code_error: 'Incorrect code. Ensure your e-mail is correct and try again.', account_helper__set_password: 'Set password', account_helper__password: 'Password', account_helper__finish: 'Finish', account_helper__register_message1: 'Welcome!', account_helper__forgot_password_message1: 'Password set!', account_helper__change_password_message1: 'Password changed!', account_helper__change_method_message1: 'Login method changed!', account_helper__go_projects: 'Go to projects…', account_change_email__title: 'Change account e-mail', account_change_email__current_email: 'Current account e-mail', account_change_email__email: 'E-mail', account_change_email__confirm_current_email: 'Confirm current e-mail', account_change_email__confirm_email_message: 'Enter the Code from e-mail to continue. If you haven\'t received an e-mail with the Code, check the Spam folder.', account_change_email__code: 'Code', account_change_email__code_error: 'Incorrect code. Ensure your e-mail is correct and try again.', account_change_email__new_email: 'New account e-mail', account_change_email__confirm_new_email: 'Confirm new e-mail', account_change_email__set_password: 'Set password', account_change_email__password: 'Password', account_change_email__finish: 'Finish', account_change_email__finish_after_message: 'Done!', account_change_email__ok_message1: 'The email address has been successfully updated!', account_change_email__ok_message2: 'Go to account…', account__user_settings: 'User settings', account__your_company: 'Your company', account__change_auth_message_2: 'After creating a user, all data from the Telegram account will be transferred to the new account.', account__change_auth_btn: 'Create system account', account__change_auth_warning: 'WARNING!', account__change_auth_warning_message: 'Reverse data transfer is not possible.', account__chats: 'Chats', account__chats_active: 'Active', account__chats_unbound: 'Unbound', account__chats_free: 'Free', account__chats_total: 'Total', account__subscribe: 'Subscribe', account__subscribe_description: 'With a subscription, you can attach more active chats.', account__auth_change_method: 'Change authorization method', account__auth_change_method_description: 'In case of corporate use, it is recommended to log in with a username and password.', account__auth_change_password: 'Change account password', account__auth_change_password_description: 'Access to the email address used for system login is required.', account__auth_change_account: 'Change account e-mail', account__auth_change_account_description: 'Access to both the current and new email addresses used for system authentication is required.', account__company_data: 'Your company data', account__company_data_description: 'The description will be automatically added to your company list for new projects.', account__manual: 'Manual', account__manual_description: 'Go to our Telegram channel with video tutorials.', account__settings: 'Settings', account__settings_description: 'Fonts size, language and etc.', account__support: 'Support', account__support_description: 'Need help? Contact us!', account__3rd_party_software: '3rd party software', account__3rd_party_software_description: 'List of third-party software packages included in the software', account__terms_of_use: 'Terms of use', account__privacy: 'Privacy and Cookie Policy', account__change_password: 'Change password', account__change_auth_method: 'Change authorization method', account_company__title_card: 'My company', account_company__btn: 'Apply', forgot_password__password_recovery: 'Password recovery', settings__title: 'Settings', settings__software_title: 'Application', settings__bot_title: 'Messages in chats (bot)', settings__language: 'Language', settings__font_size: 'Font size', settings__fontsize_small: 'Small', settings__fontsize_medium: 'Medium (default)', settings__fontsize_large: 'Large', settings__timezone: 'Time zone', settings__timezone_search: 'Search', terms_of_use__title: 'Terms of use', terms_of_use__not_ready: 'Document not ready', privacy__title: 'Privacy and Cookie Policy', privacy_of_use__not_ready: 'Document not ready', subscribe__title: 'Subscribe', subscribe__current_balance: 'Current balance', subscribe__token_formula: '1 = 1 day of access to 1 chat', subscribe__token_formula_description: 'unbound and free chats are not counted', subscribe__info: 'With a subscription, you can attach more chats. Archived chats are not counted.', subscribe__about: 'about', subscribe__select_payment_1: 'You can pay for your subscription using ', subscribe__select_payment_2: 'Telegram stars', subscribe__select_option_1: 'Telegram stars', subscribe__select_option_2: 'Telegram stars', subscribe__select_option_3: 'Telegram stars', subscribe__select_option_user: 'Telegram stars', support__title: 'Support', support__ask_question: 'Ask Question', support__work_time_text: 'Support is available on weekdays', support__work_time_time: '10:00 - 19:00 (Moscow, GMT+3)', support__or: 'or contact us via email', AUTH_ERROR: 'Incorrect e-mail or password!', software__title: '3rd party software', software__description: 'This software contains third-party software packages.', error404: 'Oops. Nothing here…' } \ No newline at end of file diff --git a/src/i18n/ru-RU/index.ts b/src/i18n/ru-RU/index.ts index 1640907..c816a70 100644 --- a/src/i18n/ru-RU/index.ts +++ b/src/i18n/ru-RU/index.ts @@ -1 +1 @@ -export default { EN: 'EN', RU: 'RU', continue: 'Продолжить', back: 'Назад', close: 'Закрыть', cancel: 'Отмена', code: 'Код', month: 'мес.', months: 'мес.', slogan: 'Работайте вместе - это волшебство!', under_construction: 'В разработке.', login__email: 'Электронная почта', login__password: 'Пароль', login__forgot_password: 'Забыли пароль?', login__sign_in: 'Войти', login__incorrect_login_data: 'Пользователь с такими данными не найден. Отредактируйте введенные данные', login__or_continue_as: 'или продолжить', login__terms_of_use: 'Пользовательское соглашение', login__accept_terms_of_use: 'Я принимаю', login__register: 'Зарегистрироваться', login__registration_message_error: 'Ошибка', login__licensing_agreement: 'Договор о лицензировании', login__have_account: 'Есть учетная запись', login__incorrect_email: 'Адрес почты некорректный', login__password_require: 'Мин. 8 символов', user__logout: 'Выход', projects__projects: 'Проекты', projects__show_archive: 'Показать архив', projects__hide_archive: 'Скрыть архив', projects__restore_archive_warning: 'Внимание!', projects__restore_archive_warning_message: 'Перед восстановлением проекта из архива проверьте наличие бота в чатах проекта.', project__chats: 'Чаты', project__users: 'Команда', project__companies: 'Компании', project__edit: 'Редактировать', project__backup: 'Резервная копия', project__archive: 'В архив', project__archive_warning: 'Вы уверены?', project__archive_warning_message: 'После перемещения проекта в архив отслеживание чатов будет отключено.', project__delete: 'Удалить', project__delete_warning: 'Внимание!', project__delete_warning_message: 'Все данные проекта будут безвозвратно удалены.', project_chats__search: 'Поиск', project_chats__send_chat: 'Запрос на добавление чата', project_chats__send_chat_description: 'Отправить инструкцию администратору чата', project_chats__attach_chat: 'Добавить чат', project_chats__attach_chat_description: 'Необходимы права администратора чата', project_chats_disabled_FAB: 'Добавление чатов возможно только в приложении Telegram', project_chats__send_chat_title: 'Для присоединения чата к ProjectsNode необходимо добавить в него бота с помощью ссылки:', project_chat__delete_warning: 'Внимание!', project_chat__delete_warning_message: 'Отслеживание чата будет прекращено. При необходимости чат можно будет подключить снова.', project_create__title_card: 'Новый проект', project_create__btn: 'Создать', project_edit__title_card: 'Редактировать проект', project_edit__btn: 'Изменить', project_block__project_name: 'Название', project_block__project_description: 'Описание', project_block__image_use_as_background_chats: 'логотип в качестве фона для чатов', project_block__error_name: 'Поле обязательно к заполнению', forgot_password__password_recovery: 'Восстановление пароля', account_helper__enter_email: 'Введите электронную почту', account_helper__email: 'Электронная почта', account_helper__confirm_email: 'Подтверждение электронной почты', account_helper__confirm_email_message: 'Введите код из письма для продолжения . Если не получили письмо с кодом - проверьте папку Спам', account_helper__code: 'Код', account_helper__code_error: 'Был введен неверный код. Проверьте адрес электронной почты и повторите попытку.', account_helper__set_password: 'Установка пароля', account_helper__password: 'Пароль', account_helper__finish: 'Отправить', account_helper__register_message1: 'Добро пожаловать!', account_helper__forgot_password_message1: 'Пароль установлен!', account_helper__change_password_message1: 'Пароль изменен!', account_helper__change_method_message1: 'Способ входа в систему изменен!', account_helper__go_projects: 'Переходим к проектам…', account_change_email__title: 'Изменение адреса электронной почты учетной записи', account_change_email__current_email: 'Текущий адрес электронной почты ', account_change_email__email: 'Электронная почта', account_change_email__confirm_current_email: 'Подтверждение адреса текущей электронной почты', account_change_email__confirm_email_message: 'Введите код из письма для продолжения. Если не получили письмо с кодом - проверьте папку Спам', account_change_email__code: 'Код', account_change_email__code_error: 'Был введен неверный код. Проверьте адрес электронной почты и повторите попытку.', account_change_email__new_email: 'Новый адрес электронной почты ', account_change_email__confirm_new_email: 'Подтверждение адреса новой электронной почты', account_change_email__set_password: 'Установка пароля', account_change_email__password: 'Пароль', account_change_email__finish: 'Отправить', account_change_email__finish_after_message: 'Готово!', account_change_email__ok_message1: 'Адрес электронной почты успешно изменен!', account_change_email__ok_message2: 'Переходим учетной записи…', account__user_settings: 'Пользовательские настройки', account__your_company: 'Ваша компания', account__change_auth_message_2: 'После создания пользователя все данные с учетной записи Telegram будут перенесены на новую учетную запись.', account__change_auth_btn: 'Создать пользователя', account__change_auth_warning: 'ВНИМАНИЕ!', account__change_auth_warning_message: 'Обратный перенос данных не возможен.', account__chats: 'Чаты', account__chats_active: 'Активные', account__chats_unbound: 'Открепленные', account__chats_free: 'Бесплатные', account__chats_total: 'Всего', account__subscribe: 'Подписка', account__subscribe_description: 'С помощью подписки можно подключить дополнительные чаты.', account__auth_change_method: 'Сменить способ авторизации', account__auth_change_method_description: 'В случае корпоративного использования рекомендуется входить в систему, указав логин и пароль.', account__auth_change_password: 'Изменить пользовательский пароль', account__auth_change_password_description: 'Необходим доступ к электронной почте, используемой для входа в систему.', account__auth_change_account: 'Сменить электронную почту учетной записи', account__auth_change_account_description: 'Необходим доступ к текущей и новой электронной почте, используемым для входа в систему.', account__company_data: 'Данные вашей компании', account__company_data_description: 'Описание будет автоматически добавляться в перечень компаний для новых проектов. ', account__manual: 'Инструкции', account__manual_description: 'Перейдите в наш Telegram-канал с обучающими видеороликами.', account__settings: 'Настройки', account__settings_description: 'Размер шрифта, язык и т.п.', account__support: 'Поддержка', account__support_description: 'Есть вопросы - напишите нам!', account__3rd_party_software: 'Сторонее ПО', account__3rd_party_software_description: 'Список сторонних программных пакетов, включённых в ПО', account__terms_of_use: 'Пользовательское соглашение', account__privacy: 'Политика конфидециальности', account__change_password: 'Изменить пароль', account__change_auth_method: 'Сменить способ авторизации', account_company__title_card: 'Моя компания', account_company__btn: 'Применить', company__no_company: 'Не указано', company__my_company: 'Моя компания', company_edit__title_card: 'Добавить компанию', company_edit__btn: 'Применить', company_edit__title_card: 'Редактировать компанию', company_edit__btn: 'Изменить', company_edit__my_company: 'Моя компания', company_edit__my_company_hint: 'Заполнение формы преднастраивается в разделе \n Аккаунт > Данные вашей компании', company_block__name: 'Название', company_block__error_name: 'Поле обязательно к заполнению', company_block__description: 'Описание', company_block__users: 'Сотрудники', company_create__title_card: 'Добавление компании', company__dialog_delete_title: 'ВНИМАНИЕ!', company__dialog_delete_message: 'Удаление компании необратимо.', company__dialog_delete_ok: 'Удалить', company__mask: 'Маскировка', mask__title_table: 'Исключения', mask__help_title: 'Маскировка', mask__help_message1: 'Маскировка позволяет скрывать компанию, представляя ее персонал как собственный для других компаний, кроме тех, что есть в перечне исключений "Видно". ', mask__help_message2: 'Для включения и отключения маскировки используйте Переключатель. Настройка исключений осуществляется с помощью "+".', mask__help_message3: 'Сотрудники вашей компании будут видеть все компании, независимо от настроек маскировки.', mask__table_header_company: 'Компания', mask__table_header_visible: 'Видно', mask__table_visible_none: 'Никому', mask__table_visible_all: 'Всем', project_users__search: 'Поиск', user_edit__title_card: 'Редактирование данных сотрудника', user_edit__btn: 'Изменить', user_block__name: 'ФИО', user_block__company: 'Компания', user_block__department: 'Подразделение', user_block__role: 'Функционал (должность)', user_block__no_company: 'Не указано', user_block__user_blocked: 'ЗАБЛОКИРОВАН', user_block__user_leave: 'Неактивный', settings__title: 'Настройки', settings__language: 'Язык', settings__font_size: 'Размер шрифта', terms__title: 'Пользовательское соглашение', subscribe__title: 'Подписка', subscribe__current_balance: 'Текущий баланс', subscribe__token_formula: '1 = 1 день подключения к 1 чату', subscribe__token_formula_description: 'отвязанные и бесплатные чаты не учитываются', subscribe__info: 'С помощью подписки можно подключить к бесплатным групповым чатам дополнительные. Архивные чаты не учитываются. ', subscribe__about: 'около', subscribe__select_payment_1: 'Вы можете оплатить подписку с помощью', subscribe__select_payment_2: 'Telegram stars', subscribe__select_option_1: 'Telegram stars', subscribe__select_option_2: 'Telegram stars', subscribe__select_option_3: 'Telegram stars', subscribe__select_option_user: 'Telegram stars', support__title: 'Поддержка', support__ask_question: 'Задайте вопрос', support__work_time_text: 'Поддержка оказывается в рабочие дни ', support__work_time_time: '10:00 - 19:00 (Москва, GMT+3)', support__or: 'или напишите нам на электронную почту', AUTH_ERROR: 'Электронная почта или пароль введены неверно!', projects__lets_start: 'Создайте проект', projects__lets_start_description: 'Проекты помогают изолировать данные: контакты, задачи, документы и чаты доступны только участникам', project_chat__onboard_msg1: 'Прикрепите чаты к проекту', project_chat__onboard_msg2: 'Контроль чатов осуществляется только с момента прикрепления', project_users__onboard_msg1: 'Адресная книга проекта', project_users__onboard_msg2: 'После прикрепления чатов их участники добавляются автоматически. Остается указать - кто есть кто. ', company__onboard_msg1: 'Добавьте компании', company__onboard_msg2: 'Рекомендуется если в проекте участвует 3 и более компаний.', software__title: 'Стороннее ПО', software__description: 'Данное программное обеспечение содержит пакеты программного обеспечения сторонних разработчиков.', error404: 'Тут ничего нет. Как вы сюда попали?' } \ No newline at end of file +export default { EN: 'EN', RU: 'RU', continue: 'Продолжить', back: 'Назад', close: 'Закрыть', cancel: 'Отмена', code: 'Код', month: 'мес.', months: 'мес.', slogan: 'Работайте вместе - это волшебство!', under_construction: 'В разработке.', login__email: 'Электронная почта', login__password: 'Пароль', login__forgot_password: 'Забыли пароль?', login__sign_in: 'Войти', login__incorrect_login_data: 'Пользователь с такими данными не найден. Отредактируйте введенные данные', login__or_continue_as: 'или продолжить', login__terms_of_use: 'Пользовательское соглашение', login__accept_terms_of_use: 'Я принимаю', login__register: 'Зарегистрироваться', login__registration_message_error: 'Ошибка', login__licensing_agreement: 'Договор о лицензировании', login__have_account: 'Есть учетная запись', login__incorrect_email: 'Адрес почты некорректный', login__password_require: 'Мин. 8 символов', user__logout: 'Выход', projects__projects: 'Проекты', projects__search: 'Поиск', projects__show_archive: 'Показать архив', projects__hide_archive: 'Скрыть архив', projects__dialog_archive_title: 'Отправить проект в архив?', projects__dialog_archive_message: 'Отслеживание чатов будет остановлено.', projects__dialog_archive_message2: 'Данные из чатов за период архивации будут утеряны!', projects__dialog_archive_ok: 'В архив', projects__dialog_restore_title: 'Восстановить проект из архива?', projects__dialog_restore_message: 'Отслеживание чатов будет восстановлено.', projects__dialog_restore_message2: 'При восстановлении данные из чатов за период архивации не будут добавлены!', projects__dialog_restore_ok: 'Восстановить', projects__lets_start: 'Создайте проект', projects__lets_start_description: 'Проекты помогают изолировать данные: контакты, задачи, документы и чаты доступны только участникам', project__chats: 'Чаты', project__users: 'Команда', project__companies: 'Компании', project_create__title_card: 'Новый проект', project_create__btn: 'Создать', project_edit__title_card: 'Редактировать проект', project_edit__btn: 'Изменить', project_block__project_name: 'Название', project_block__project_description: 'Описание', project_block__image_use_as_background_chats: 'логотип в качестве фона для чатов', project_block__error_name: 'Поле обязательно к заполнению', chats__search: 'Поиск', chats__send_chat: 'Запрос на добавление чата', chats__send_chat_description: 'Отправить инструкцию администратору чата', chats__attach_chat: 'Добавить чат', chats__attach_chat_description: 'Необходимы права администратора чата', chats_disabled_FAB: 'Добавление чатов возможно только в приложении Telegram', chats__send_chat_title: 'Для присоединения чата к ProjectsNode необходимо добавить в него бота с помощью ссылки:', chats__dialog_unlink_title: 'Открепить чат?', chats__dialog_unlink_message: 'Отслеживание чата будет прекращено.', chats__dialog_unlink_message2: 'При необходимости чат можно будет подключить снова.', chats__dialog_unlink_ok: 'Открепить', chats__onboard_msg1: 'Прикрепите чаты к проекту', chats__onboard_msg2: 'Контроль чатов осуществляется только с момента прикрепления', users__search: 'Поиск', users__show_blocked_users: 'Показать заблокированных', users__hide_blocked_users: 'Скрыть заблокированных', users__show_left_users: 'Показать неактивных', users__hide_left_users: 'Скрыть неактивных', users__dialog_block_title: 'Заблокировать сотрудника?', users__dialog_block_message: 'Доступ к системе будет отключен.', users__dialog_block_message2: 'Сотрудник будет исключен из всех чатов (кроме тех, где он является владельцем).', users__dialog_block_ok: 'Заблокировать', users__dialog_restore_title: 'Восстановить сотрудника?', users__dialog_restore_message: 'Доступ к системе будет восстановлен.', users__dialog_restore_message2: 'При необходимости нужно добавить сотрудника в чаты вручную.', users__dialog_restore_ok: 'Восстановить', users__onboard_msg1: 'Адресная книга проекта', users__onboard_msg2: 'После прикрепления чатов их участники добавляются автоматически. Остается указать - кто есть кто. ', user_edit__title_card: 'Редактирование данных сотрудника', user_edit__btn: 'Изменить', user_block__name: 'ФИО', user_block__company: 'Компания', user_block__department: 'Подразделение', user_block__role: 'Функционал (должность)', user_block__no_company: 'Не указано', user_block__user_blocked: 'ЗАБЛОКИРОВАН', user_block__user_leave: 'Неактивный', companies__dialog_delete_title: 'Удалить компанию?', companies__dialog_delete_message: 'Это действие нельзя отменить!', companies__dialog_delete_message2: 'Сотрудники компании будут помечены "Без компании".', companies__dialog_delete_ok: 'Удалить', companies__mask: 'Маскировка', companies__my_company: 'Моя компания', companies__onboard_msg1: 'Добавьте компании', companies__onboard_msg2: 'Рекомендуется если в проекте участвует 3 и более компаний.', company_add__title_card: 'Добавить компанию', company_add__btn: 'Создать', company_edit__title_card: 'Редактировать компанию', company_edit__btn: 'Изменить', company_edit__my_company: 'Моя компания', company_edit__my_company_hint: 'Заполнение формы преднастраивается в разделе \n Аккаунт > Данные вашей компании', company_block__name: 'Название', company_block__error_name: 'Поле обязательно к заполнению', company_block__description: 'Описание', company_block__users: 'Сотрудники', mask__title_table: 'Исключения', mask__help_title: 'Маскировка', mask__help_message1: 'Маскировка позволяет скрывать компанию, представляя ее персонал как собственный для других компаний, кроме тех, что есть в перечне исключений "Видно". ', mask__help_message2: 'Для включения и отключения маскировки используйте Переключатель. Настройка исключений осуществляется с помощью "+".', mask__help_message3: 'Сотрудники вашей компании будут видеть все компании, независимо от настроек маскировки.', mask__table_header_company: 'Компания', mask__table_header_visible: 'Видно', mask__table_visible_none: 'Никому', mask__table_visible_all: 'Всем', account_helper__enter_email: 'Введите электронную почту', account_helper__email: 'Электронная почта', account_helper__confirm_email: 'Подтверждение электронной почты', account_helper__confirm_email_message: 'Введите код из письма для продолжения . Если не получили письмо с кодом - проверьте папку Спам', account_helper__code: 'Код', account_helper__code_error: 'Был введен неверный код. Проверьте адрес электронной почты и повторите попытку.', account_helper__set_password: 'Установка пароля', account_helper__password: 'Пароль', account_helper__finish: 'Отправить', account_helper__register_message1: 'Добро пожаловать!', account_helper__forgot_password_message1: 'Пароль установлен!', account_helper__change_password_message1: 'Пароль изменен!', account_helper__change_method_message1: 'Способ входа в систему изменен!', account_helper__go_projects: 'Переходим к проектам…', account_change_email__title: 'Изменение адреса электронной почты учетной записи', account_change_email__current_email: 'Текущий адрес электронной почты ', account_change_email__email: 'Электронная почта', account_change_email__confirm_current_email: 'Подтверждение адреса текущей электронной почты', account_change_email__confirm_email_message: 'Введите код из письма для продолжения. Если не получили письмо с кодом - проверьте папку Спам', account_change_email__code: 'Код', account_change_email__code_error: 'Был введен неверный код. Проверьте адрес электронной почты и повторите попытку.', account_change_email__new_email: 'Новый адрес электронной почты ', account_change_email__confirm_new_email: 'Подтверждение адреса новой электронной почты', account_change_email__set_password: 'Установка пароля', account_change_email__password: 'Пароль', account_change_email__finish: 'Отправить', account_change_email__finish_after_message: 'Готово!', account_change_email__ok_message1: 'Адрес электронной почты успешно изменен!', account_change_email__ok_message2: 'Переходим учетной записи…', account__user_settings: 'Пользовательские настройки', account__your_company: 'Ваша компания', account__change_auth_message_2: 'После создания пользователя все данные с учетной записи Telegram будут перенесены на новую учетную запись.', account__change_auth_btn: 'Создать пользователя', account__change_auth_warning: 'ВНИМАНИЕ!', account__change_auth_warning_message: 'Обратный перенос данных не возможен.', account__chats: 'Чаты', account__chats_active: 'Активные', account__chats_unbound: 'Открепленные', account__chats_free: 'Бесплатные', account__chats_total: 'Всего', account__subscribe: 'Подписка', account__subscribe_description: 'С помощью подписки можно подключить дополнительные чаты.', account__auth_change_method: 'Сменить способ авторизации', account__auth_change_method_description: 'В случае корпоративного использования рекомендуется входить в систему, указав логин и пароль.', account__auth_change_password: 'Изменить пользовательский пароль', account__auth_change_password_description: 'Необходим доступ к электронной почте, используемой для входа в систему.', account__auth_change_account: 'Сменить электронную почту учетной записи', account__auth_change_account_description: 'Необходим доступ к текущей и новой электронной почте, используемым для входа в систему.', account__company_data: 'Данные вашей компании', account__company_data_description: 'Описание будет автоматически добавляться в перечень компаний для новых проектов. ', account__manual: 'Инструкции', account__manual_description: 'Перейдите в наш Telegram-канал с обучающими видеороликами.', account__settings: 'Настройки', account__settings_description: 'Размер текста, язык и т.п.', account__support: 'Поддержка', account__support_description: 'Есть вопросы - напишите нам!', account__3rd_party_software: 'Сторонее ПО', account__3rd_party_software_description: 'Список сторонних программных пакетов, включённых в ПО', account__terms_of_use: 'Пользовательское соглашение', account__privacy: 'Политика конфидециальности', account__change_password: 'Изменить пароль', account__change_auth_method: 'Сменить способ авторизации', account_company__title_card: 'Моя компания', account_company__btn: 'Применить', forgot_password__password_recovery: 'Восстановление пароля', settings__title: 'Настройки', settings__software_title: 'Приложение', settings__bot_title: 'Сообщения в чатах (бот)', settings__language: 'Язык', settings__font_size: 'Размер текста', settings__fontsize_small: 'Мелкий', settings__fontsize_medium: 'Средний (по уиолчанию)', settings__fontsize_large: 'Большой', settings__timezone: 'Часовой пояс', settings__timezone_search: 'Поиск', terms_of_use__title: 'Пользовательское соглашение', terms_of_use__not_ready: 'Документ не готов', privacy__title: 'Политика конфидециальности', privacy_of_use__not_ready: 'Документ не готов', subscribe__title: 'Подписка', subscribe__current_balance: 'Текущий баланс', subscribe__token_formula: '1 = 1 день подключения к 1 чату', subscribe__token_formula_description: 'отвязанные и бесплатные чаты не учитываются', subscribe__info: 'С помощью подписки можно подключить к бесплатным групповым чатам дополнительные. Архивные чаты не учитываются. ', subscribe__about: 'около', subscribe__select_payment_1: 'Вы можете оплатить подписку с помощью', subscribe__select_payment_2: 'Telegram stars', subscribe__select_option_1: 'Telegram stars', subscribe__select_option_2: 'Telegram stars', subscribe__select_option_3: 'Telegram stars', subscribe__select_option_user: 'Telegram stars', support__title: 'Поддержка', support__ask_question: 'Задайте вопрос', support__work_time_text: 'Поддержка оказывается в рабочие дни ', support__work_time_time: '10:00 - 19:00 (Москва, GMT+3)', support__or: 'или напишите нам на электронную почту', AUTH_ERROR: 'Электронная почта или пароль введены неверно!', software__title: 'Стороннее ПО', software__description: 'Данное программное обеспечение содержит пакеты программного обеспечения сторонних разработчиков.', error404: 'Тут ничего нет. Как вы сюда попали?' } \ No newline at end of file diff --git a/src/pages/AccountPage.vue b/src/pages/AccountPage.vue index 6f4deb7..0f61fd6 100644 --- a/src/pages/AccountPage.vue +++ b/src/pages/AccountPage.vue @@ -68,7 +68,6 @@ { id: 5, name: 'account__company_data', icon: 'mdi-account-group-outline', description: 'account__company_data_description', pathName: 'your_company' }, { id: 6, name: 'account__settings', icon: 'mdi-cog-outline', description: 'account__settings_description', iconColor: 'info', pathName: 'settings' }, { id: 7, name: 'account__support', icon: 'mdi-lifebuoy', description: 'account__support_description', iconColor: 'info', pathName: 'support' }, - { id: 8, name: 'account__3rd_party_software', icon: 'mdi-scale-balance', description: 'account__3rd_party_software_description', iconColor: 'grey', pathName: '3software' }, { id: 9, name: 'account__terms_of_use', icon: 'mdi-book-open-variant-outline', description: '', iconColor: 'grey', pathName: 'terms' }, { id: 10, name: 'account__privacy', icon: 'mdi-lock-outline', description: '', iconColor: 'grey', pathName: 'privacy' } ])) diff --git a/src/pages/CompanyAddPage.vue b/src/pages/CompanyAddPage.vue index 2a20bd6..44178d1 100644 --- a/src/pages/CompanyAddPage.vue +++ b/src/pages/CompanyAddPage.vue @@ -1,8 +1,8 @@ diff --git a/src/pages/ProjectsPage.vue b/src/pages/ProjectsPage.vue index 0eb4696..6b8b9f6 100644 --- a/src/pages/ProjectsPage.vue +++ b/src/pages/ProjectsPage.vue @@ -25,7 +25,7 @@ v-model="searchProject" clearable clear-icon="close" - :placeholder="$t('project_chats__search')" + :placeholder="$t('projects__search')" dense class="col-grow q-px-md q-py-md" > @@ -91,22 +91,22 @@ class="flex column items-center w100" :class="showArchive ? 'bg-grey-12' : ''" > - - - + + {{ !showArchive + ? $t('projects__show_archive') + ' (' + archiveProjects.length +')' + : $t('projects__hide_archive') + }} + +
@@ -319,7 +321,17 @@ flex-wrap: nowrap; } - .fix-rotate-arrow :deep(.q-btn-dropdown--simple) { - margin-left: 0; + .rotate-icon-btn { + transition: transform 0.3s; + } + + .rotate-icon-btn.rotate-icon :deep(.q-icon) { + transform: rotate(180deg); + transition: transform 0.3s cubic-bezier(0.25, 0.8, 0.5, 1); + } + + .rotate-icon-btn :deep(.q-icon) { + transform: rotate(0deg); + transition: transform 0.3s cubic-bezier(0.25, 0.8, 0.5, 1); } diff --git a/src/pages/account/SettingsPage.vue b/src/pages/account/SettingsPage.vue index 022b6c3..4eb4c61 100644 --- a/src/pages/account/SettingsPage.vue +++ b/src/pages/account/SettingsPage.vue @@ -6,75 +6,120 @@ - - - - - - {{ $t('settings__language') }} - - - - - - - - - - - {{ $t('settings__font_size') }} - - -
- - -
-
-
+ {{ $t('settings__software_title') }} + + + + + + + + + + + + {{ $t('settings__bot_title') }} + + + + + + + + + +
diff --git a/src/pages/project-page/ProjectPageChats.vue b/src/pages/project-page/ProjectPageChats.vue index 1a4b51c..f4243c1 100644 --- a/src/pages/project-page/ProjectPageChats.vue +++ b/src/pages/project-page/ProjectPageChats.vue @@ -8,7 +8,7 @@ v-model="search" clearable clear-icon="close" - :placeholder="$t('project_chats__search')" + :placeholder="$t('chats__search')" dense class="col-grow" v-if="chats.length !== 0" @@ -71,8 +71,8 @@
- {{ $t('project_chats_disabled_FAB')}} + {{ $t('chats_disabled_FAB')}} chatsStore.isInit) const fabMenu = [ - {id: 1, icon: 'mdi-chat-plus-outline', name: 'project_chats__attach_chat', description: 'project_chats__attach_chat_description', func: attachChat}, - {id: 2, icon: 'mdi-share-outline', name: 'project_chats__send_chat', description: 'project_chats__send_chat_description', func: sendChat}, + {id: 1, icon: 'mdi-chat-plus-outline', name: 'chats__attach_chat', description: 'chats__attach_chat_description', func: attachChat}, + {id: 2, icon: 'mdi-share-outline', name: 'chats__send_chat', description: 'chats__send_chat_description', func: sendChat}, ] const displayChats = computed(() => { @@ -253,7 +254,7 @@ const key = await chatsStore.getKey() const message = urlAdmin + key + urlAdminPermission const tgShareUrl = 'https://t.me/share/url?url=' + - encodeURIComponent( t('project_chats__send_chat_title')) + + encodeURIComponent( t('chats__send_chat_title')) + '&text=' + `${encodeURIComponent(message)}` tg.openTelegramLink(tgShareUrl) } diff --git a/src/pages/project-page/ProjectPageCompanies.vue b/src/pages/project-page/ProjectPageCompanies.vue index fc233c6..6378da9 100644 --- a/src/pages/project-page/ProjectPageCompanies.vue +++ b/src/pages/project-page/ProjectPageCompanies.vue @@ -7,7 +7,7 @@ :color="companies.length <= 2 ? 'grey-6' : 'primary'" flat no-caps - @click="maskCompany()" + @click="maskCompany" :disable="companies.length <= 2" class="q-pr-md" rounded @@ -16,9 +16,10 @@ left size="sm" name="mdi-domino-mask" + class="q-mr-xs" />
- {{ $t('company__mask')}} + {{ $t('companies__mask')}}
@@ -53,7 +54,7 @@
- {{ $t('company__my_company') }} + {{ $t('companies__my_company') }}
{{ item.name }} @@ -93,9 +94,9 @@
@@ -60,27 +60,92 @@ + +
+ + + {{ !showLeaveUsers + ? $t('users__show_left_users') + ' (' + leaveUsers.length +')' + : $t('users__hide_left_users') + }} + + + +
+ + + + + + + + + {{item.section1}} + + + {{item.section3}} + + +
+ +
{{item.section2_1}}
+
{{'@' + item.section2_2}}
+
+
+
+
+
+
+
+
+ + + +
- - - + + {{ !showBlockedUsers + ? $t('users__show_blocked_users') + ' (' + blockedUsers.length +')' + : $t('users__hide_blocked_users') + }} + +
+
@@ -157,9 +224,10 @@ v-model="showDialogRestoreUser" icon="mdi-account-reactivate-outline" color="green" - title="user__dialog_restore_title" - message1="user__dialog_restore_message" - mainBtnLabel="user__dialog_restore_ok" + title="users__dialog_restore_title" + message1="users__dialog_restore_message" + message2="users__dialog_restore_message2" + mainBtnLabel="users__dialog_restore_ok" @clickMainBtn="onConfirmRestoreUser()" /> @@ -183,12 +251,18 @@ const users = usersStore.getUsers const usersInit = computed(() => usersStore.isInit) - const deleteUserId = ref(undefined) - const showDialogDeleteUser = ref(false) + const blockUserId = ref(undefined) + const showDialogBlockUser = ref(false) const currentSlideEvent = ref(null) const closedByUserAction = ref(false) - const mapUsers = computed(() => users.map(el => ({...el, ...userSection(el)}))) + const mapUsers = computed(() => users.map(el => ({ + ...el, + ...userSection(el), + companyName: el.company_id && companiesStore.companyById(el.company_id) + ? companiesStore.companyById(el.company_id)?.name + : null + }))) interface SlideEvent { reset: () => void @@ -202,12 +276,13 @@ el.section1.toLowerCase().includes(searchValue) || el.section2_1.toLowerCase().includes(searchValue) || el.section2_2.toLowerCase().includes(searchValue) || - el.section3.toLowerCase().includes(searchValue) + el.section3.toLowerCase().includes(searchValue) || + el.companyName && el.companyName.toLowerCase().includes(searchValue) ) return arrOut }) - const displayUsers = computed(() => displayUsersAll.value.filter(el => !el.is_block)) + const displayUsers = computed(() => displayUsersAll.value.filter(el => !el.is_blocked)) function userSection (user: User) { const tname = () => { @@ -244,8 +319,8 @@ function handleSlide (event: SlideEvent, id: number) { currentSlideEvent.value = event - showDialogDeleteUser.value = true - deleteUserId.value = id + showDialogBlockUser.value = true + blockUserId.value = id } function onDialogBeforeHide () { @@ -263,26 +338,29 @@ } } - async function onConfirmDeleteUser() { + async function onConfirmBlockUser() { closedByUserAction.value = true - if (deleteUserId.value) { - await usersStore.blockUser(deleteUserId.value) + if (blockUserId.value) { + await usersStore.blockUser(blockUserId.value) } currentSlideEvent.value = null } const showBlockedUsers = ref(false) - const blockedUsers = computed(() => displayUsersAll.value.filter(el => el.is_block)) + const blockedUsers = computed(() => displayUsersAll.value.filter(el => el.is_blocked)) const unblockUserId = ref (undefined) const showDialogRestoreUser = ref(false) + const showLeaveUsers = ref(false) + const leaveUsers = computed(() => displayUsersAll.value.filter(el => el.is_leave)) + function handleUnblockUser (id: number) { showDialogRestoreUser.value = true unblockUserId.value = id } async function onConfirmRestoreUser () { - if (unblockUserId.value) await usersStore.restore(unblockUserId.value) + if (unblockUserId.value) await usersStore.unblockUser(unblockUserId.value) } watch(showDialogRestoreUser, (newD :boolean) => { @@ -293,5 +371,18 @@ - diff --git a/src/router/routes.ts b/src/router/routes.ts index cb62560..efa6cf6 100644 --- a/src/router/routes.ts +++ b/src/router/routes.ts @@ -129,11 +129,6 @@ const routes: RouteRecordRaw[] = [ component: () => import('pages/account/SubscribePage.vue'), meta: { requiresAuth: true } }, - { - name: '3software', - path: '/3software', - component: () => import('pages/account/3Software.vue'), - }, { name: 'terms', path: '/terms-of-use', diff --git a/src/stores/auth.ts b/src/stores/auth.ts index 9f26395..0212470 100644 --- a/src/stores/auth.ts +++ b/src/stores/auth.ts @@ -14,6 +14,14 @@ interface Customer { company?: CompanyParams } +interface WSMessage { + id: number + action: string + entity: string + entity_id?: number + needUpdateStores: string[] +} + const ENDPOINT_MAP = { register: '/auth/email/register', forgot: '/auth/forgot', @@ -25,6 +33,7 @@ export type AuthFlowType = keyof typeof ENDPOINT_MAP export const useAuthStore = defineStore('auth', () => { const customer = ref(null) + const wsEvent = ref(null) const projectsStore = useProjectsStore() const isAuth = computed(() => !!customer.value) @@ -35,29 +44,26 @@ export const useAuthStore = defineStore('auth', () => { customer.value = data.data const socket = new WebSocket("wss://946gp81j-9000.euw.devtunnels.ms/api/admin") console.log(socket) - socket.onopen = function() { - console.log("Соединение установлено."); - }; + socket.onopen = () => console.log("Connection ws create.") - socket.onclose = function(event) { - if (event.wasClean) { - console.log('Соединение закрыто чисто'); - } else { - console.log('Обрыв соединения'); // например, "убит" процесс сервера + socket.onclose = (event) => { + if (event.wasClean) console.log('Connection ws close.') + else console.log('Connection ws failure!') + console.log('Code: ' + event.code + ', reason : ' + event.reason) + } + + socket.onmessage = (event) => { + if (wsEvent.value) { + wsEvent.value.needUpdateStores = [] + wsEvent.value = JSON.parse(event.data) + if (wsEvent.value?.entity === 'chat') wsEvent.value.needUpdateStores = ['users'] } - console.log('Код: ' + event.code + ' причина: ' + event.reason); - }; - socket.onmessage = function(event) { - console.log("Получены данные " + event.data); - }; - - socket.onerror = function(error) { - console.log("Ошибка " + error.message); - }; + socket.onerror = (event) => console.error("Ошибка ", event) + } } catch (error) { - if (isAuth.value) console.log(error) + if (isAuth.value) console.error(error) } } @@ -81,9 +87,7 @@ export const useAuthStore = defineStore('auth', () => { if (flowType !== 'changePwd') await api.post(ENDPOINT_MAP[flowType], { email }) else - {console.log(222) await api.post(ENDPOINT_MAP[flowType]) - } } const confirmCode = async (flowType: AuthFlowType, email: string, code: string) => { @@ -100,36 +104,32 @@ export const useAuthStore = defineStore('auth', () => { } //change email of account - const getCodeCurrentEmail = async () => { + const getCodeCurrentEmail = async () => await api.post('/auth/email/change-email') - } - const confirmCurrentEmailCode = async (code: string) => { + + const confirmCurrentEmailCode = async (code: string) => await api.post('/auth/email/change-email', { code }) - } - const getCodeNewEmail = async (code: string, email: string) => { + const getCodeNewEmail = async (code: string, email: string) => await api.post('/auth/email/change-email', { code, email }) - } - const confirmNewEmailCode = async (code: string, code2: string, email: string) => { + const confirmNewEmailCode = async (code: string, code2: string, email: string) => await api.post('/auth/email/change-email', { code, code2, email }) - } - const setNewEmailPassword = async (code: string, code2: string, email: string, password: string) => { + const setNewEmailPassword = async (code: string, code2: string, email: string, password: string) => await api.post('/auth/email/change-email', { code, code2, email, password }) - } // user data company const updateMyCompany = async (companyData: CompanyParams) => { const response = await api.put('/customer/profile', { company: companyData }) - console.log(response) if (response.status === 200 && customer.value) customer.value.company = companyData } return { customer, isAuth, + wsEvent, initialize, loginWithCredentials, loginWithTelegram, diff --git a/src/stores/chats.ts b/src/stores/chats.ts index c91a3ab..15ecd9b 100644 --- a/src/stores/chats.ts +++ b/src/stores/chats.ts @@ -1,8 +1,9 @@ -import { ref, computed } from 'vue' +import { ref, computed, watch } from 'vue' import { defineStore } from 'pinia' import { api } from 'boot/axios' import type { Chat } from 'types/Chat' import { useProjectsStore } from 'stores/projects' +import { useAuthStore } from 'stores/auth' export const useChatsStore = defineStore('chats', () => { const projectsStore = useProjectsStore() @@ -12,8 +13,9 @@ export const useChatsStore = defineStore('chats', () => { const currentProjectId = computed(() => projectsStore.currentProjectId) async function init () { - const response = await api.get('/project/' + currentProjectId.value + '/chat') - const chatsAPI = response.data.data + reset() + const { data } = await api.get('/project/' + currentProjectId.value + '/chat') + const chatsAPI = data.data chats.value.push(...chatsAPI) isInit.value = true } @@ -41,6 +43,12 @@ export const useChatsStore = defineStore('chats', () => { function chatById (id: number) { return chats.value.find(el =>el.id === id) } + + const authStore = useAuthStore() + watch(() => authStore.wsEvent, async (event) => { + if (!event || event.entity !== 'chat' || !event.needUpdateStores.includes('chats')) return + await init() + }, { deep: true }) return { chats, diff --git a/src/stores/companies.ts b/src/stores/companies.ts index d3ca48a..c7a4a95 100644 --- a/src/stores/companies.ts +++ b/src/stores/companies.ts @@ -14,6 +14,7 @@ export const useCompaniesStore = defineStore('companies', () => { const currentProjectId = computed(() => projectsStore.currentProjectId) async function init () { + reset() const { data }= await api.get('/project/' + currentProjectId.value + '/company') const companiesAPI = data.data companies.value.push(...(companiesAPI.sort((a: Company, b: Company) => (a.id - b.id)))) diff --git a/src/stores/settings.ts b/src/stores/settings.ts index 6941962..5dc37b2 100644 --- a/src/stores/settings.ts +++ b/src/stores/settings.ts @@ -9,16 +9,17 @@ import type { WebApp } from '@twa-dev/types' interface AppSettings { fontSize: number locale: string + timeZoneBot: { tz: string, offset: number, offsetString: string } + localeBot: string } const defaultFontSize = 16 -const minFontSize = 10 -const maxFontSize = 22 -const fontSizeStep = 2 const defaultSettings: AppSettings = { fontSize: defaultFontSize, - locale: 'en-US' + locale: 'en-US', + timeZoneBot: { tz: 'Europe/Moscow', offset: 3, offsetString: '+03:00' }, + localeBot: 'en-US' } export const useSettingsStore = defineStore('settings', () => { @@ -30,13 +31,17 @@ export const useSettingsStore = defineStore('settings', () => { const isInit = ref(false) const currentFontSize = computed(() => settings.value?.fontSize ?? defaultFontSize) - const canIncrease = computed(() => currentFontSize.value < maxFontSize) - const canDecrease = computed(() => currentFontSize.value > minFontSize) const supportLocale = [ { value: 'en-US', label: 'English' }, { value: 'ru-RU', label: 'Русский' } ] + + const supportFontSizes = [ + { value: 12, label: 'settings__fontsize_small' }, + { value: 16, label: 'settings__fontsize_medium' }, + { value: 20, label: 'settings__fontsize_large' } + ] const detectLocale = (): string => { const localeMap = { @@ -74,10 +79,12 @@ export const useSettingsStore = defineStore('settings', () => { const init = async () => { if (authStore.isAuth) { try { - const response = await api.get('/customer/settings') + const { data } = await api.get('/customer/settings') settings.value = { - fontSize: response.data.data.settings.fontSize || defaultSettings.fontSize, - locale: response.data.data.settings.locale || detectLocale() + fontSize: data.data.settings.fontSize || defaultSettings.fontSize, + locale: data.data.settings.locale || detectLocale(), + timeZoneBot: data.data.settings.timeZone || defaultSettings.timeZoneBot, + localeBot: data.data.settings.localeBot || detectLocale() } } catch { settings.value.locale = detectLocale() @@ -93,12 +100,6 @@ export const useSettingsStore = defineStore('settings', () => { isInit.value = true } - const updateLocale = async (newLocale: string) => { - settings.value.locale = newLocale - applyLocale() - await saveSettings() - } - const saveSettings = async () => { await api.put('/customer/settings', { settings: settings.value }) } @@ -110,19 +111,6 @@ export const useSettingsStore = defineStore('settings', () => { await saveSettings() } - const clampFontSize = (size: number) => - Math.max(minFontSize, Math.min(size, maxFontSize)) - - const increaseFontSize = async () => { - const newSize = clampFontSize(currentFontSize.value + fontSizeStep) - await updateSettings({ fontSize: newSize }) - } - - const decreaseFontSize = async () => { - const newSize = clampFontSize(currentFontSize.value - fontSizeStep) - await updateSettings({ fontSize: newSize }) - } - watch(() => authStore.isAuth, (newVal) => { if (newVal !== undefined) void init() }, { immediate: true }) @@ -130,14 +118,10 @@ export const useSettingsStore = defineStore('settings', () => { return { settings, supportLocale, + supportFontSizes, isInit, currentFontSize, - canIncrease, - canDecrease, init, - increaseFontSize, - decreaseFontSize, - updateSettings, - updateLocale + updateSettings } }) diff --git a/src/stores/users.ts b/src/stores/users.ts index 28dcd8c..66fe55f 100644 --- a/src/stores/users.ts +++ b/src/stores/users.ts @@ -1,8 +1,9 @@ -import { ref, computed } from 'vue' +import { ref, computed, watch } from 'vue' import { defineStore } from 'pinia' import { api } from 'boot/axios' import type { User, UserParams } from 'types/Users' import { useProjectsStore } from 'stores/projects' +import { useAuthStore } from 'stores/auth' export const useUsersStore = defineStore('users', () => { const projectsStore = useProjectsStore() @@ -12,6 +13,7 @@ export const useUsersStore = defineStore('users', () => { const currentProjectId = computed(() => projectsStore.currentProjectId) async function init () { + reset() const { data } = await api.get('/project/' + currentProjectId.value + '/user') const usersAPI = data.data users.value.push(...usersAPI) @@ -38,6 +40,13 @@ export const useUsersStore = defineStore('users', () => { if (users.value[idx]) Object.assign(users.value[idx], userAPI) } + async function unblockUser (userId: number) { + const { data } = await api.put('/project/' + currentProjectId.value + '/user/' + userId, { is_blocked: false }) + const userAPI = data.data + const idx = users.value.findIndex(item => item.id === userAPI.id) + if (users.value[idx]) Object.assign(users.value[idx], userAPI) + } + function userById (id: number) { return users.value.find(el =>el.id === id) } @@ -52,6 +61,12 @@ export const useUsersStore = defineStore('users', () => { const getUsers = computed(() => users.value) + const authStore = useAuthStore() + watch(() => authStore.wsEvent, async (event) => { + if (!event || event.entity !== 'user' || !event.needUpdateStores.includes('users')) return + await init() + }, { deep: true }) + return { users, isInit, @@ -59,6 +74,7 @@ export const useUsersStore = defineStore('users', () => { reset, update, blockUser, + unblockUser, userById, userNameById, getUsers diff --git a/todo_all.txt b/todo_all.txt new file mode 100644 index 0000000..6cd8970 --- /dev/null +++ b/todo_all.txt @@ -0,0 +1,40 @@ +1. Приложение Администратора: +1.1. Внедрение web-socket +1.2. Страница подписки и внедрение оплаты звездами +1.3. Юридические документы: +- Лицензионное соглашение (EN / RU) +- Обработка персональных данных (RU) +- Privacy police (EN) +1.4. Маскировка компаний +1.5. Взаимодействие с архивным чатом + +2. Приложение Пользователя: +2.1. Авторизация с флагом принятия документов +2.2. При выборе пользователя в задаче или совещании - предоставлять +только список пользователей в чате +2.3. Отображение владельца чата (?техническая возможность) +2.4. В файлах добавить новую сущность URL +2.5. Работа с архивом задач +2.6. Механизм передачи vCard (через медиашаринг https://telegram.tips/blog/mini-apps-media-sharing/ ) +2.7. Внедрение web-socket + +3. Чаты: +3.1. Внедрение inline-режима создания форматированного сообщения, задачи и совещания +3.2. Проверить реализацию всех фич. + +4. Сайт: +4.1. Создание сайта-лендинга +4.2. Оплата адреса + +5. Инфраструктура: +5.1. Разворачивание гипервизора +5.2. Развертывание виртуальных машин +5.3. Бекапирование +5.4. Настройка nginx + +6. Прочее: +6.1. Подача заявления в Роскомнадзор о работе с персональными данными. + + + +