Compare commits
45 Commits
55957df00c
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a8b415b4bd | ||
|
|
394ac5ec9d | ||
|
|
4fb918f5e4 | ||
|
|
3b802b7c7b | ||
|
|
1b2a5af2be | ||
|
|
6410321895 | ||
|
|
51445a7341 | ||
|
|
56df8632cb | ||
|
|
824bed199c | ||
|
|
b5728f1238 | ||
|
|
04814aeeda | ||
|
|
9386fbc2f8 | ||
|
|
a06b654103 | ||
|
|
9aaff4d80a | ||
|
|
7a06843bf5 | ||
|
|
1decc08f77 | ||
|
|
c0cfbcbcbb | ||
|
|
688c225911 | ||
|
|
3e79304e5c | ||
|
|
e7d8ec8c63 | ||
|
|
1e3cd99c69 | ||
|
|
3ab67cbe2d | ||
|
|
b3c056980d | ||
|
|
fb3bb6c77c | ||
|
|
bdc330c885 | ||
|
|
31da7f85cf | ||
|
|
69e63fc5f3 | ||
|
|
fe6fc2cb74 | ||
|
|
80cc90d347 | ||
|
|
9b5c2dd95c | ||
|
|
58e0869916 | ||
|
|
14bdd3bcd0 | ||
|
|
a10216a392 | ||
|
|
e53c8230e6 | ||
|
|
c6bc05560e | ||
|
|
63b0e18396 | ||
|
|
1bec150822 | ||
|
|
4d8dc6b59c | ||
|
|
b0a744034b | ||
|
|
49f69f6af0 | ||
|
|
5017b62059 | ||
|
|
ea80f90d0f | ||
|
|
dd74432dd7 | ||
|
|
4aef4881e1 | ||
|
|
7bc3eb10c1 |
20
angular.json
20
angular.json
@@ -40,6 +40,10 @@
|
||||
{
|
||||
"replace": "src/environments/environment.ts",
|
||||
"with": "src/environments/environment.production.ts"
|
||||
},
|
||||
{
|
||||
"replace": "src/app/interceptors/mock-data.interceptor.ts",
|
||||
"with": "src/app/interceptors/mock-data.interceptor.production.ts"
|
||||
}
|
||||
],
|
||||
"styles": [
|
||||
@@ -49,7 +53,7 @@
|
||||
"budgets": [
|
||||
{
|
||||
"type": "initial",
|
||||
"maximumWarning": "500kB",
|
||||
"maximumWarning": "600kB",
|
||||
"maximumError": "1MB"
|
||||
},
|
||||
{
|
||||
@@ -92,6 +96,10 @@
|
||||
{
|
||||
"replace": "src/app/brands/brand-routes.ts",
|
||||
"with": "src/app/brands/brand-routes.novo.ts"
|
||||
},
|
||||
{
|
||||
"replace": "src/app/interceptors/mock-data.interceptor.ts",
|
||||
"with": "src/app/interceptors/mock-data.interceptor.production.ts"
|
||||
}
|
||||
],
|
||||
"index": "src/index.novo.html",
|
||||
@@ -124,7 +132,7 @@
|
||||
"budgets": [
|
||||
{
|
||||
"type": "initial",
|
||||
"maximumWarning": "500kB",
|
||||
"maximumWarning": "600kB",
|
||||
"maximumError": "1MB"
|
||||
},
|
||||
{
|
||||
@@ -158,6 +166,10 @@
|
||||
{
|
||||
"replace": "src/app/brands/brand-routes.ts",
|
||||
"with": "src/app/brands/brand-routes.lavero.ts"
|
||||
},
|
||||
{
|
||||
"replace": "src/app/interceptors/mock-data.interceptor.ts",
|
||||
"with": "src/app/interceptors/mock-data.interceptor.production.ts"
|
||||
}
|
||||
],
|
||||
"index": "src/index.lavero.html",
|
||||
@@ -190,7 +202,7 @@
|
||||
"budgets": [
|
||||
{
|
||||
"type": "initial",
|
||||
"maximumWarning": "500kB",
|
||||
"maximumWarning": "600kB",
|
||||
"maximumError": "1MB"
|
||||
},
|
||||
{
|
||||
@@ -225,7 +237,7 @@
|
||||
"dexarmarket.ru",
|
||||
"dexar.market",
|
||||
"localhost",
|
||||
"lavero.store"
|
||||
"lovero.store"
|
||||
],
|
||||
"proxyConfig": "proxy.conf.json"
|
||||
},
|
||||
|
||||
327
docs/TELEGRAM_USERAUTH_BACKEND.md
Normal file
327
docs/TELEGRAM_USERAUTH_BACKEND.md
Normal file
@@ -0,0 +1,327 @@
|
||||
# Telegram UserAuth Backend Contract
|
||||
|
||||
This document extracts the existing Telegram login flow into a repo-neutral contract for reuse in other projects.
|
||||
|
||||
The UI behavior, payloads, polling cadence, and session model stay the same. Only route names and cookie naming are generalized.
|
||||
|
||||
## Endpoint Renaming
|
||||
|
||||
| Current app contract | Reusable contract |
|
||||
|---|---|
|
||||
| `GET /auth/session` | `GET /userauth/session` |
|
||||
| `POST /auth/qr/create` | `POST /userauth/qr/create` |
|
||||
| `GET /auth/qr/poll?token=...` | `GET /userauth/qr/poll?token=...` |
|
||||
| `POST /auth/qr/confirm` | `POST /userauth/qr/confirm` |
|
||||
| `GET /auth/telegram/callback` | `GET /userauth/telegram/callback` |
|
||||
| `POST /auth/logout` | `POST /userauth/logout` |
|
||||
| `POST /websession/{sessionId}` | `POST /usersession/{sessionId}` |
|
||||
| Cookie `dx_session` | Cookie `userauth_session` |
|
||||
|
||||
## Flow Summary
|
||||
|
||||
There are two supported flows.
|
||||
|
||||
### 1. Direct login from button
|
||||
|
||||
1. Frontend opens `https://t.me/{botUsername}?start=auth_{callbackUrl}`.
|
||||
2. Telegram bot creates a session and sends the user a login button.
|
||||
3. The button points to `GET /userauth/telegram/callback?token={sessionId}`.
|
||||
4. Backend sets `userauth_session` cookie and redirects back to the storefront.
|
||||
5. Frontend calls `GET /userauth/session` and becomes authenticated.
|
||||
|
||||
### 2. QR login from desktop
|
||||
|
||||
1. Frontend opens dialog.
|
||||
2. Frontend calls `POST /userauth/qr/create`.
|
||||
3. Backend returns `{ token, url }` where `url` is a Telegram deep link.
|
||||
4. Frontend renders a QR from that URL.
|
||||
5. User scans QR and bot calls `POST /userauth/qr/confirm`.
|
||||
6. Frontend polls `GET /userauth/qr/poll?token=...` every 3 seconds.
|
||||
7. When status becomes `confirmed`, backend returns session payload and sets the cookie.
|
||||
8. Frontend syncs local cart using `POST /usersession/{sessionId}`.
|
||||
|
||||
## Session Shape
|
||||
|
||||
The frontend expects this exact response shape for the authenticated session.
|
||||
|
||||
```json
|
||||
{
|
||||
"sessionId": "550e8400-e29b-41d4-a716-446655440000",
|
||||
"telegramUserId": 123456789,
|
||||
"username": "ivan_petrov",
|
||||
"displayName": "Ivan Petrov",
|
||||
"active": true,
|
||||
"expiresAt": "2026-05-21T14:30:00Z"
|
||||
}
|
||||
```
|
||||
|
||||
| Field | Type | Required | Notes |
|
||||
|---|---|---|---|
|
||||
| `sessionId` | string | yes | Session identifier used in cart sync |
|
||||
| `telegramUserId` | number | yes | Telegram user ID |
|
||||
| `username` | string or null | no | Telegram username |
|
||||
| `displayName` | string | yes | User-facing full name |
|
||||
| `active` | boolean | yes | `false` means expired session |
|
||||
| `expiresAt` | ISO 8601 string | yes | Used by frontend refresh scheduling |
|
||||
|
||||
Recommended TTL:
|
||||
|
||||
- Session TTL: 24 hours
|
||||
- QR token TTL: 5 minutes
|
||||
|
||||
## HTTP Contract
|
||||
|
||||
### `POST /userauth/qr/create`
|
||||
|
||||
Creates a one-time QR login token when the dialog opens.
|
||||
|
||||
Request body:
|
||||
|
||||
```json
|
||||
{}
|
||||
```
|
||||
|
||||
Response `200`:
|
||||
|
||||
```json
|
||||
{
|
||||
"token": "dG9rZW4tYWJjMTIz",
|
||||
"url": "https://t.me/userauth_bot?start=login_dG9rZW4tYWJjMTIz"
|
||||
}
|
||||
```
|
||||
|
||||
Requirements:
|
||||
|
||||
- Generate a cryptographically secure token.
|
||||
- Save token with status `pending`.
|
||||
- Return a Telegram deep link in `url`.
|
||||
- Rate limit to 5 requests per minute per IP.
|
||||
|
||||
### `GET /userauth/qr/poll?token={token}`
|
||||
|
||||
Called every 3 seconds until confirmation or expiration.
|
||||
|
||||
Possible responses:
|
||||
|
||||
Pending:
|
||||
|
||||
```json
|
||||
{ "status": "pending" }
|
||||
```
|
||||
|
||||
Confirmed:
|
||||
|
||||
```json
|
||||
{
|
||||
"status": "confirmed",
|
||||
"session": {
|
||||
"sessionId": "550e8400-e29b-41d4-a716-446655440000",
|
||||
"telegramUserId": 123456789,
|
||||
"username": "ivan_petrov",
|
||||
"displayName": "Ivan Petrov",
|
||||
"active": true,
|
||||
"expiresAt": "2026-05-21T14:30:00Z"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Expired:
|
||||
|
||||
```json
|
||||
{ "status": "expired" }
|
||||
```
|
||||
|
||||
Behavior:
|
||||
|
||||
- If confirmed, set cookie `userauth_session` in the response.
|
||||
- Delete or invalidate the QR token after the first successful confirmed poll.
|
||||
- If token is unknown or expired, return `status: "expired"`.
|
||||
|
||||
### `POST /userauth/qr/confirm`
|
||||
|
||||
Internal endpoint called by the Telegram bot after the user scans the QR code.
|
||||
|
||||
Required header:
|
||||
|
||||
```text
|
||||
X-Bot-Secret: <shared secret between bot and backend>
|
||||
```
|
||||
|
||||
Request body:
|
||||
|
||||
```json
|
||||
{
|
||||
"token": "dG9rZW4tYWJjMTIz",
|
||||
"telegram_user": {
|
||||
"id": 123456789,
|
||||
"first_name": "Ivan",
|
||||
"last_name": "Petrov",
|
||||
"username": "ivan_petrov"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Response `200`:
|
||||
|
||||
```json
|
||||
{ "status": "ok" }
|
||||
```
|
||||
|
||||
Behavior:
|
||||
|
||||
- Validate `X-Bot-Secret`.
|
||||
- Validate token exists and is still `pending`.
|
||||
- Create a user session.
|
||||
- Store session ID on the QR token.
|
||||
- Mark QR token as `confirmed`.
|
||||
|
||||
### `GET /userauth/session`
|
||||
|
||||
Returns the currently active session based on the cookie.
|
||||
|
||||
Frontend behavior depends on this endpoint in two places:
|
||||
|
||||
- initial auth check on app startup
|
||||
- fallback polling if QR token creation fails
|
||||
|
||||
Response `200`:
|
||||
|
||||
```json
|
||||
{
|
||||
"sessionId": "550e8400-e29b-41d4-a716-446655440000",
|
||||
"telegramUserId": 123456789,
|
||||
"username": "ivan_petrov",
|
||||
"displayName": "Ivan Petrov",
|
||||
"active": true,
|
||||
"expiresAt": "2026-05-21T14:30:00Z"
|
||||
}
|
||||
```
|
||||
|
||||
Error handling:
|
||||
|
||||
- Any non-200 response is treated by the frontend as unauthenticated.
|
||||
|
||||
### `GET /userauth/telegram/callback?token={sessionId}`
|
||||
|
||||
Used for direct Telegram login from the primary button flow.
|
||||
|
||||
Behavior:
|
||||
|
||||
- Read the `token` query param.
|
||||
- Resolve it to a valid active session.
|
||||
- Set cookie `userauth_session`.
|
||||
- Redirect user to the storefront URL.
|
||||
|
||||
### `POST /userauth/logout`
|
||||
|
||||
Clears the backend session and expires the cookie.
|
||||
|
||||
Request body:
|
||||
|
||||
```json
|
||||
{}
|
||||
```
|
||||
|
||||
Response `200`:
|
||||
|
||||
```json
|
||||
{ "message": "ok" }
|
||||
```
|
||||
|
||||
### `POST /usersession/{sessionId}`
|
||||
|
||||
Synchronizes local cart immediately after successful login.
|
||||
|
||||
Request body:
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"itemID": 123,
|
||||
"quantity": 2,
|
||||
"colour": "#ff0000",
|
||||
"size": "XL",
|
||||
"price": 1500
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
Notes:
|
||||
|
||||
- This payload is unchanged from the existing implementation.
|
||||
- `price` is already discounted on the frontend side.
|
||||
- The frontend skips the call if cart is empty.
|
||||
|
||||
## Telegram Deep Link Format
|
||||
|
||||
Direct login link format:
|
||||
|
||||
```text
|
||||
https://t.me/{botUsername}?start=auth_{urlEncodedCallbackUrl}
|
||||
```
|
||||
|
||||
QR login link format:
|
||||
|
||||
```text
|
||||
https://t.me/{botUsername}?start=login_{qrToken}
|
||||
```
|
||||
|
||||
Important limit:
|
||||
|
||||
- Telegram limits the `start` payload to 64 characters.
|
||||
- A base64url encoding of 32 random bytes plus `login_` fits safely.
|
||||
|
||||
## Cookie Requirements
|
||||
|
||||
Use these cookie settings for the frontend to work correctly across site and API origins.
|
||||
|
||||
| Property | Value |
|
||||
|---|---|
|
||||
| Name | `userauth_session` |
|
||||
| Path | `/` |
|
||||
| HttpOnly | `true` |
|
||||
| Secure | `true` |
|
||||
| SameSite | `None` |
|
||||
| MaxAge | `86400` |
|
||||
| Domain | your shared parent domain, for example `.example.com` |
|
||||
|
||||
## CORS Requirements
|
||||
|
||||
Because the frontend sends credentials, backend must return an explicit origin.
|
||||
|
||||
Required headers:
|
||||
|
||||
```text
|
||||
Access-Control-Allow-Origin: https://your-frontend.example
|
||||
Access-Control-Allow-Credentials: true
|
||||
Access-Control-Allow-Methods: GET, POST, OPTIONS
|
||||
Access-Control-Allow-Headers: Content-Type
|
||||
```
|
||||
|
||||
Do not use `*` for `Access-Control-Allow-Origin` together with credentials.
|
||||
|
||||
## Frontend Runtime Expectations
|
||||
|
||||
The current dialog behavior is fixed and should be preserved by backend responses.
|
||||
|
||||
- QR polling interval: every 3 seconds
|
||||
- QR expiration on frontend: after 100 checks
|
||||
- If QR creation fails, frontend falls back to direct login URL and session polling
|
||||
- After login, frontend closes the dialog and re-checks session
|
||||
|
||||
## Minimal Backend Checklist
|
||||
|
||||
- Implement all six `userauth` endpoints and the `usersession` sync endpoint.
|
||||
- Store sessions for 24 hours.
|
||||
- Store QR tokens for 5 minutes.
|
||||
- Protect `POST /userauth/qr/confirm` with `X-Bot-Secret`.
|
||||
- Set `userauth_session` cookie on confirmed QR poll and direct callback.
|
||||
- Return the exact session JSON shape.
|
||||
- Support credentialed CORS.
|
||||
|
||||
## Bot Checklist
|
||||
|
||||
- Handle `/start login_{token}` and call `POST /userauth/qr/confirm`.
|
||||
- Handle `/start auth_{callbackUrl}` and provide a button that opens the callback URL.
|
||||
- Send success and expiration messages back to the user.
|
||||
- Share the same `X-Bot-Secret` value with backend.
|
||||
551
docs/telegram-login-dialog.html
Normal file
551
docs/telegram-login-dialog.html
Normal file
@@ -0,0 +1,551 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Telegram Login Dialog</title>
|
||||
<style>
|
||||
:root {
|
||||
--bg-page: linear-gradient(135deg, #f4f7fb 0%, #e8eef4 100%);
|
||||
--bg-card: #ffffff;
|
||||
--bg-hover: #f0f0f0;
|
||||
--text-primary: #1a1a1a;
|
||||
--text-secondary: #666666;
|
||||
--accent-color: #497671;
|
||||
--accent-light: rgba(73, 118, 113, 0.1);
|
||||
--telegram: #2aabee;
|
||||
--telegram-hover: #229ed9;
|
||||
--border: #e8e8e8;
|
||||
--shadow: 0 20px 60px rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
min-height: 100vh;
|
||||
font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif;
|
||||
color: var(--text-primary);
|
||||
background: var(--bg-page);
|
||||
}
|
||||
|
||||
.page {
|
||||
min-height: 100vh;
|
||||
display: grid;
|
||||
grid-template-columns: minmax(320px, 448px) minmax(320px, 560px);
|
||||
gap: 32px;
|
||||
padding: 40px 32px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.panel {
|
||||
background: rgba(255, 255, 255, 0.72);
|
||||
border: 1px solid rgba(255, 255, 255, 0.8);
|
||||
border-radius: 28px;
|
||||
padding: 24px;
|
||||
box-shadow: 0 18px 50px rgba(38, 52, 73, 0.12);
|
||||
backdrop-filter: blur(14px);
|
||||
}
|
||||
|
||||
.info h1 {
|
||||
margin: 0 0 12px;
|
||||
font-size: 32px;
|
||||
line-height: 1.1;
|
||||
}
|
||||
|
||||
.info p {
|
||||
margin: 0 0 18px;
|
||||
color: var(--text-secondary);
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.state-switcher {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 10px;
|
||||
margin: 20px 0 24px;
|
||||
}
|
||||
|
||||
.state-switcher button {
|
||||
border: 1px solid #cfd8e3;
|
||||
border-radius: 999px;
|
||||
background: #fff;
|
||||
color: var(--text-primary);
|
||||
padding: 10px 14px;
|
||||
font-size: 14px;
|
||||
cursor: pointer;
|
||||
transition: 0.2s ease;
|
||||
}
|
||||
|
||||
.state-switcher button.active {
|
||||
border-color: var(--accent-color);
|
||||
background: var(--accent-light);
|
||||
color: var(--accent-color);
|
||||
}
|
||||
|
||||
.api-grid {
|
||||
display: grid;
|
||||
gap: 12px;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.api-card {
|
||||
background: #fff;
|
||||
border: 1px solid #eef2f7;
|
||||
border-radius: 16px;
|
||||
padding: 14px 16px;
|
||||
}
|
||||
|
||||
.api-card strong {
|
||||
display: block;
|
||||
margin-bottom: 6px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.api-card code {
|
||||
display: inline-block;
|
||||
padding: 2px 8px;
|
||||
border-radius: 999px;
|
||||
background: #f3f7fb;
|
||||
color: #21425f;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.api-card p {
|
||||
margin: 8px 0 0;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.login-overlay {
|
||||
position: relative;
|
||||
min-height: 700px;
|
||||
border-radius: 28px;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
backdrop-filter: blur(4px);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
animation: fadeIn 0.2s ease;
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.login-dialog {
|
||||
position: relative;
|
||||
background: var(--bg-card);
|
||||
border-radius: 20px;
|
||||
padding: 32px 28px;
|
||||
max-width: 400px;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
box-shadow: var(--shadow);
|
||||
animation: scaleIn 0.25s ease;
|
||||
}
|
||||
|
||||
.close-btn {
|
||||
position: absolute;
|
||||
top: 12px;
|
||||
right: 12px;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
border: none;
|
||||
border-radius: 50%;
|
||||
background: var(--bg-hover);
|
||||
color: var(--text-secondary);
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.close-btn:hover {
|
||||
background: #e0e0e0;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.login-icon {
|
||||
margin: 0 auto 16px;
|
||||
width: 72px;
|
||||
height: 72px;
|
||||
border-radius: 50%;
|
||||
background: var(--accent-light);
|
||||
color: var(--accent-color);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.login-dialog h2 {
|
||||
margin: 0 0 8px;
|
||||
font-size: 20px;
|
||||
font-weight: 700;
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
.login-desc {
|
||||
margin: 0 0 24px;
|
||||
font-size: 14px;
|
||||
color: var(--text-secondary);
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.telegram-btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 10px;
|
||||
width: 100%;
|
||||
padding: 14px 24px;
|
||||
border: none;
|
||||
border-radius: 12px;
|
||||
background: var(--telegram);
|
||||
color: #fff;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.telegram-btn:hover {
|
||||
background: var(--telegram-hover);
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 4px 12px rgba(42, 171, 238, 0.3);
|
||||
}
|
||||
|
||||
.telegram-btn:active {
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
.tg-icon {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.qr-section {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.qr-hint {
|
||||
margin: 0 0 12px;
|
||||
font-size: 13px;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.qr-container {
|
||||
display: inline-flex;
|
||||
padding: 12px;
|
||||
background: #fff;
|
||||
border-radius: 12px;
|
||||
border: 1px solid var(--border);
|
||||
}
|
||||
|
||||
.qr-container img {
|
||||
display: block;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.qr-loading {
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 204px;
|
||||
height: 204px;
|
||||
}
|
||||
|
||||
.qr-loading .spinner,
|
||||
.login-status .spinner {
|
||||
border-radius: 50%;
|
||||
animation: spin 0.8s linear infinite;
|
||||
}
|
||||
|
||||
.qr-loading .spinner {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
border: 3px solid #e0e0e0;
|
||||
border-top-color: var(--accent-color);
|
||||
}
|
||||
|
||||
.qr-expired {
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 8px;
|
||||
width: 204px;
|
||||
height: 204px;
|
||||
cursor: pointer;
|
||||
color: #999;
|
||||
transition: color 0.2s ease;
|
||||
}
|
||||
|
||||
.qr-expired:hover {
|
||||
color: var(--accent-color);
|
||||
}
|
||||
|
||||
.qr-expired span {
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.login-note {
|
||||
margin: 16px 0 0;
|
||||
font-size: 12px;
|
||||
color: #999;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.login-status {
|
||||
display: none;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 10px;
|
||||
padding: 16px;
|
||||
color: var(--text-secondary);
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.login-status .spinner {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
border: 2px solid #e0e0e0;
|
||||
border-top-color: var(--accent-color);
|
||||
}
|
||||
|
||||
.dialog-content[data-state="checking"] .login-status {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.dialog-content[data-state="checking"] .action-block,
|
||||
.dialog-content[data-state="loading"] .qr-ready,
|
||||
.dialog-content[data-state="loading"] .qr-expired,
|
||||
.dialog-content[data-state="expired"] .qr-ready,
|
||||
.dialog-content[data-state="expired"] .qr-loading,
|
||||
.dialog-content[data-state="error"] .qr-loading,
|
||||
.dialog-content[data-state="error"] .qr-expired,
|
||||
.dialog-content[data-state="checking"] .qr-section,
|
||||
.dialog-content[data-state="checking"] .login-note {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.dialog-content[data-state="ready"] .qr-loading,
|
||||
.dialog-content[data-state="ready"] .qr-expired,
|
||||
.dialog-content[data-state="ready"] .qr-error,
|
||||
.dialog-content[data-state="loading"] .qr-ready,
|
||||
.dialog-content[data-state="loading"] .qr-expired,
|
||||
.dialog-content[data-state="loading"] .qr-error,
|
||||
.dialog-content[data-state="expired"] .qr-loading,
|
||||
.dialog-content[data-state="expired"] .qr-ready,
|
||||
.dialog-content[data-state="expired"] .qr-error,
|
||||
.dialog-content[data-state="error"] .qr-loading,
|
||||
.dialog-content[data-state="error"] .qr-expired {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.dialog-content[data-state="error"] .qr-ready {
|
||||
display: inline-flex;
|
||||
}
|
||||
|
||||
.metadata {
|
||||
margin-top: 22px;
|
||||
padding-top: 18px;
|
||||
border-top: 1px solid #e9edf2;
|
||||
font-size: 13px;
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
|
||||
.metadata ul {
|
||||
margin: 10px 0 0;
|
||||
padding-left: 18px;
|
||||
}
|
||||
|
||||
.metadata li + li {
|
||||
margin-top: 6px;
|
||||
}
|
||||
|
||||
@keyframes fadeIn {
|
||||
from { opacity: 0; }
|
||||
to { opacity: 1; }
|
||||
}
|
||||
|
||||
@keyframes scaleIn {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: scale(0.95);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: scale(1);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
to { transform: rotate(360deg); }
|
||||
}
|
||||
|
||||
@media (max-width: 980px) {
|
||||
.page {
|
||||
grid-template-columns: 1fr;
|
||||
padding: 24px 16px 32px;
|
||||
}
|
||||
|
||||
.login-overlay {
|
||||
min-height: 560px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 480px) {
|
||||
.panel {
|
||||
border-radius: 22px;
|
||||
padding: 18px;
|
||||
}
|
||||
|
||||
.login-dialog {
|
||||
padding: 24px 20px;
|
||||
border-radius: 16px;
|
||||
}
|
||||
|
||||
.qr-container img {
|
||||
width: 140px;
|
||||
height: 140px;
|
||||
}
|
||||
|
||||
.qr-loading,
|
||||
.qr-expired {
|
||||
width: 164px;
|
||||
height: 164px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<main class="page">
|
||||
<section class="panel info">
|
||||
<h1>Telegram Login Dialog</h1>
|
||||
<p>
|
||||
Standalone extraction of the current login popup: same layout, same visual states,
|
||||
same QR flow, but with reusable neutral endpoint names for moving into a separate repo.
|
||||
</p>
|
||||
|
||||
<div class="state-switcher" aria-label="Dialog state switcher">
|
||||
<button class="active" data-state-btn="ready" type="button">Ready</button>
|
||||
<button data-state-btn="loading" type="button">QR Loading</button>
|
||||
<button data-state-btn="checking" type="button">Checking</button>
|
||||
<button data-state-btn="expired" type="button">Expired</button>
|
||||
<button data-state-btn="error" type="button">Fallback</button>
|
||||
</div>
|
||||
|
||||
<div class="api-grid">
|
||||
<div class="api-card">
|
||||
<strong>Start QR session</strong>
|
||||
<code>POST /userauth/qr/create</code>
|
||||
<p>Returns a one-time token and Telegram deeplink for the QR image.</p>
|
||||
</div>
|
||||
<div class="api-card">
|
||||
<strong>Poll QR confirmation</strong>
|
||||
<code>GET /userauth/qr/poll?token=...</code>
|
||||
<p>Returns pending, confirmed, or expired. On confirmed, also returns the user session.</p>
|
||||
</div>
|
||||
<div class="api-card">
|
||||
<strong>Read current session</strong>
|
||||
<code>GET /userauth/session</code>
|
||||
<p>Cookie-based session lookup used for initial auth check and fallback polling.</p>
|
||||
</div>
|
||||
<div class="api-card">
|
||||
<strong>Sync cart after login</strong>
|
||||
<code>POST /usersession/{sessionId}</code>
|
||||
<p>Existing cart payload is preserved. Only the namespace is generalized for reuse.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="metadata">
|
||||
<strong>Behavior kept intact</strong>
|
||||
<ul>
|
||||
<li>Open Telegram directly from the primary button.</li>
|
||||
<li>Show QR immediately and poll every 3 seconds.</li>
|
||||
<li>Expire the QR after 100 checks and allow manual refresh.</li>
|
||||
<li>Re-check cookie session if QR creation fails.</li>
|
||||
</ul>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="panel">
|
||||
<div class="login-overlay">
|
||||
<div class="login-dialog">
|
||||
<button class="close-btn" type="button" aria-label="Close dialog">
|
||||
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<path d="M18 6L6 18M6 6l12 12"></path>
|
||||
</svg>
|
||||
</button>
|
||||
|
||||
<div class="dialog-content" data-state="ready" id="dialog-content">
|
||||
<div class="login-icon">
|
||||
<svg width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5">
|
||||
<path d="M21 11.5a8.38 8.38 0 0 1-.9 3.8 8.5 8.5 0 0 1-7.6 4.7 8.38 8.38 0 0 1-3.8-.9L3 21l1.9-5.7a8.38 8.38 0 0 1-.9-3.8 8.5 8.5 0 0 1 4.7-7.6 8.38 8.38 0 0 1 3.8-.9h.5a8.48 8.48 0 0 1 8 8v.5z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
<h2>Login required</h2>
|
||||
<p class="login-desc">Please log in via Telegram to proceed with your order.</p>
|
||||
|
||||
<div class="login-status checking">
|
||||
<div class="spinner"></div>
|
||||
<span>Checking...</span>
|
||||
</div>
|
||||
|
||||
<div class="action-block">
|
||||
<button class="telegram-btn" type="button">
|
||||
<svg class="tg-icon" width="22" height="22" viewBox="0 0 24 24" fill="currentColor">
|
||||
<path d="M11.944 0A12 12 0 0 0 0 12a12 12 0 0 0 12 12 12 12 0 0 0 12-12A12 12 0 0 0 12 0a12 12 0 0 0-.056 0zm4.962 7.224c.1-.002.321.023.465.14a.506.506 0 0 1 .171.325c.016.093.036.306.02.472-.18 1.898-.962 6.502-1.36 8.627-.168.9-.499 1.201-.82 1.23-.696.065-1.225-.46-1.9-.902-1.056-.693-1.653-1.124-2.678-1.8-1.185-.78-.417-1.21.258-1.91.177-.184 3.247-2.977 3.307-3.23.007-.032.014-.15-.056-.212s-.174-.041-.249-.024c-.106.024-1.793 1.14-5.061 3.345-.48.33-.913.49-1.302.48-.428-.008-1.252-.241-1.865-.44-.752-.245-1.349-.374-1.297-.789.027-.216.325-.437.893-.663 3.498-1.524 5.83-2.529 6.998-3.014 3.332-1.386 4.025-1.627 4.476-1.635z"></path>
|
||||
</svg>
|
||||
Log in with Telegram
|
||||
</button>
|
||||
|
||||
<div class="qr-section">
|
||||
<p class="qr-hint">Or scan the QR code</p>
|
||||
|
||||
<div class="qr-container qr-loading">
|
||||
<div class="spinner"></div>
|
||||
</div>
|
||||
|
||||
<div class="qr-container qr-ready">
|
||||
<img
|
||||
src="https://api.qrserver.com/v1/create-qr-code/?size=180x180&data=https%3A%2F%2Ft.me%2Fuserauth_bot%3Fstart%3Dlogin_sample_token"
|
||||
alt="QR Code"
|
||||
width="180"
|
||||
height="180"
|
||||
loading="eager"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="qr-container qr-expired" role="button" tabindex="0" aria-label="Refresh QR code">
|
||||
<svg width="32" height="32" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<path d="M1 4v6h6M23 20v-6h-6"></path>
|
||||
<path d="M20.49 9A9 9 0 0 0 5.64 5.64L1 10m22 4l-4.64 4.36A9 9 0 0 1 3.51 15"></path>
|
||||
</svg>
|
||||
<span>QR code expired. Click to refresh</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p class="login-note">You will be redirected back after login.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
|
||||
<script>
|
||||
const content = document.getElementById('dialog-content');
|
||||
const buttons = document.querySelectorAll('[data-state-btn]');
|
||||
|
||||
buttons.forEach((button) => {
|
||||
button.addEventListener('click', () => {
|
||||
const state = button.getAttribute('data-state-btn');
|
||||
content.setAttribute('data-state', state);
|
||||
|
||||
buttons.forEach((candidate) => candidate.classList.remove('active'));
|
||||
button.classList.add('active');
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,144 +1,24 @@
|
||||
bro we need to add another project, under another port. it must be the same as dexar
|
||||
here are infos:
|
||||
colors: #FD7300 #3AAA35 #E24B00
|
||||
1. lavero.store
|
||||
2. info@lavero.storre
|
||||
3. logo - public\assets\images\lavero\lavero-logo.png
|
||||
bro please read carefully.
|
||||
this must be for all projects.
|
||||
At first here is the API for only auth process:
|
||||
https://users.vitanova.network:456/ping
|
||||
|
||||
and here are other stuff regarding it:
|
||||
//Logout user by sessionID
|
||||
r.DELETE("/users/sessions/:webSessionID", Logout)
|
||||
|
||||
//creates new session for user and send code for activation
|
||||
r.POST("/users/sessions", newWebSession)
|
||||
|
||||
r.GET("/users/sessions/:webSessionID", getWebSession)
|
||||
|
||||
As you got all the info, keep all the structure of api above.
|
||||
Now when the user clicks on login, we must show the QR and the link of the telegram bot, which we already have (btw sho me, so i see wheter it is true or not)
|
||||
and add a query param "?start=GUID" and generate a guid there.
|
||||
after we post it ad a websession, we have to get it like this " r.GET("/users/sessions/:webSessionID", getWebSession)" every 5 secs untill we get a status true
|
||||
if we will be loged in, we have to keep that webSessionID in the cookies for an hour
|
||||
1. if we open our website, we have to check the cookies and do a request for that websession
|
||||
2. if we are not loged in, then we will loge in one more time
|
||||
|
||||
|
||||
info for legal:
|
||||
"ՆՇԱԹԵՐԹ
|
||||
պետական գրանցման
|
||||
մասին տեղեկությունների
|
||||
«ԼԱՎԵՐՈ»
|
||||
Սահմանափակ
|
||||
պատասխանատվությամբ ընկերություն
|
||||
Գրանցված է Հայաստանի Հանրապետության
|
||||
արդարադատության նախարարության իրավաբանական
|
||||
անձանց պետական ռեգիստրի գործակալության կողմից
|
||||
Գրանցված է`
|
||||
Աշխատակից՝
|
||||
ՀՀ ԱՆ իրավաբանական անձանց պետական
|
||||
ռեգիստրի գործակալություն
|
||||
Ինքնաշխատ էլեկտրոնային գրանցում
|
||||
Գրանցման ամսաթիվ՝
|
||||
Գրանցման համար՝
|
||||
ՀՎՀՀ՝
|
||||
18.05.2026
|
||||
999.110.1583686
|
||||
03590442
|
||||
Պետական գրանցման մասին տեղեկությունների նշաթերթը էլեկտրոնային եղանակով ձևավորված է ՀՀ ԱՆ
|
||||
իրավաբանական անձանց պետական ռեգիստրի տեղեկատվական համակարգի կողմից և հանդիսանում է
|
||||
«ԼԱՎԵՐՈ» Սահմանափակ պատասխանատվությամբ ընկերություն կանոնադրության անբաժանելի մասը։
|
||||
Սույն կանոնադրության գրանցումը հավաստվում է համակարգի կողմից գեներացված RBBE-3D66
|
||||
EF54-3DAE ծածկագրով քաղվածքով, որի իսկությունը և արդիականությունը կարող է ստուգվել
|
||||
փաստաթղթերի վավերականության ստուգման միասնական համակարգում (e-verify.am):
|
||||
Սույն կանոնադրությունը կազմված է 2026-05-18 և բաղկացած է 4 թերթից:
|
||||
Հ Ա Ս Տ Ա Տ Վ Ա Ծ Է
|
||||
«ԼԱՎԵՐՈ»
|
||||
սահմանափակ
|
||||
պատասխանատվությամբ
|
||||
ընկերության հիմնադիրների
|
||||
2026-05-18 կայացրած
|
||||
Հիմնադիր ժողովի որոշմամբ
|
||||
արձանագրություն թիվ` 1
|
||||
տնօրեն` ԳԵՎՈՐԳ ՄԱԹԵՎՈՍՅԱՆ
|
||||
Գ Ր Ա Ն Ց Վ Ա Ծ Է
|
||||
ՀԱՅԱՍՏԱՆԻ ՀԱՆՐԱՊԵՏՈՒԹՅԱՆ
|
||||
ԱՐԴԱՐԱԴԱՏՈՒԹՅԱՆ ՆԱԽԱՐԱՐՈՒԹՅԱՆ
|
||||
ԻՐԱՎԱԲԱՆԱԿԱՆ ԱՆՁԱՆՑ
|
||||
ՊԵՏԱԿԱՆ ՌԵԳԻՍՏՐԻ ԳՈՐԾԱԿԱԼՈՒԹՅԱՆ
|
||||
ԿՈՂՄԻՑ
|
||||
Աշխատակից՝ ՀՀ ԻԱ Պետական ռեգիստրի էլ․
|
||||
համակարգ
|
||||
Գրանցման հ/հ՝ - 999.110.1583686
|
||||
Գրանցման ամսաթիվ՝ 18.05.2026
|
||||
Հարկ վճարողի հաշվառման
|
||||
համար (ՀՎՀՀ)` 03590442
|
||||
«ԼԱՎԵՐՈ»
|
||||
ՍԱՀՄԱՆԱՓԱԿ ՊԱՏԱՍԽԱՆԱՏՎՈՒԹՅԱՄԲ ԸՆԿԵՐՈՒԹՅԱՆ
|
||||
ԿԱՆՈՆԱԴՐՈՒԹՅՈՒՆ
|
||||
2026
|
||||
Էջ 1 4-ից
|
||||
Սույն կանոնադրությունը կազմված է 2026-05-18 և բաղկացած է 4 թերթից:
|
||||
1. ԸՆԴՀԱՆՈՒՐ ԴՐՈՒՅԹՆԵՐ
|
||||
1.1. «ԼԱՎԵՐՈ» սահմանափակ պատասխանատվությամբ ընկերությունը (հետագայում` Ընկերություն)
|
||||
համարվում է շահույթ ստանալու նպատակով հիմնադրված առևտրային կազմակերպություն
|
||||
հանդիսացող իրավաբանական անձ, որի կանոնադրական կապիտալը բաժանված է սույն
|
||||
կանոնադրությամբ սահմանված չափերով բաժնեմասերի:
|
||||
1.2. Ընկերությունն իր գործունեության ընթացքում ղեկավարվում է Հայաստանի Հանրապետության
|
||||
Քաղաքացիական Օրենսդրությամբ, այլ իրավական ակտերով և սույն կանոնադրությամբ:
|
||||
1.3. Ընկերության ֆիրմային անվանումն է`
|
||||
հայերեն լրիվ՝ «ԼԱՎԵՐՈ» սահմանափակ պատասխանատվությամբ ընկերություն
|
||||
կրճատ՝ «ԼԱՎԵՐՈ» ՍՊԸ
|
||||
ռուսերեն լրիվ՝ «ЛАВЕРО» Общество с Ограничеенной Ответственностью
|
||||
կրճատ՝ «ЛАВЕРО» ՕՕՕ
|
||||
անգլերեն լրիվ՝ «LAVERO» LIMITED LIABILITY COMPANY
|
||||
կրճատ՝ «LAVERO» LLC
|
||||
1.4. Ընկերության գտնվելու վայրը և իրավաբանական (փոստային) հասցեն է` ԿՈՏԱՅՔ, ԱԲՈՎՅԱՆ, ՎԵՐԻՆ
|
||||
ՊՏՂՆԻ, 3-րդ փողոց, 28, Տ Փ/Դ՝ 2228:
|
||||
2. ԸՆԿԵՐՈՒԹՅԱՆ ՄԱՍՆԱԿԻՑՆԵՐԸ, ՆՐԱՆՑ ԻՐԱՎՈՒՆՔՆԵՐՆ ՈՒ ՊԱՐՏԱԿԱՆՈՒԹՅՈՒՆՆԵՐԸ
|
||||
2.1. Անձը համարվում է ընկերության մասնակից իրավաբանական անձանց պետական գրանցումն
|
||||
իրականացնող մարմնի կողմից Ընկերության մասնակիցների գրանցամատյանում նրա որպես այդպիսին
|
||||
գրանցվելու պահից:
|
||||
2.2. Ընկերության կանոնադրական կապիտալում բաժնեմասը փոխանցելը.
|
||||
2.2.1.Ընկերության մասնակիցն իրավունք ունի իր բաժնեմասը (դրա մասը) վաճառել կամ այլ` օրենքով
|
||||
չարգելված ձևով, օտարել Ընկերության մեկ կամ մի քանի մասնակիցների, ինչպես նաև երրորդ անձանց:
|
||||
Ընդ որում, մյուս մասնակիցներն ունեն այդ բաժնեմասը նույն գնով ձեռքբերման նախապատվության
|
||||
իրավունք՝ Ընկերության կանոնադրական կապիտալում իրենց բաժնեմասերին համամասնորեն: Եթե
|
||||
Ընկերության մյուս մասնակիցները չեն օգտագործել բաժնեմասը (դրա մասը) գնելու իրենց
|
||||
նախապատվության իրավունքը կամ այն օգտագործել են մասամբ, ապա Ընկերությունն ունի այդ
|
||||
բաժնեմասը նույն գնով ձեռքբերման նախապատվության իրավունք:
|
||||
2.2.2.Երրորդ անձանց օտարման անհնարինության դեպքում մասնակցի պահանջով Ընկերությունն ինքը
|
||||
պարտավոր է ձեռք բերել մասնակցի բաժնեմասը, այն իրացնել մեկ տարվա ընթացքում այլ
|
||||
մասնակիցների կամ երրորդ անձանց կամ որոշում ընդունել բաժնեմասի չբաշխված մասի մարման
|
||||
ճանապարհով Ընկերության կանոնադրական կապիտալի նվազեցման մասին:
|
||||
2.2.3.Նախապատվության իրավունքի (այլ մասնակիցների կողմից վաճառվող բաժնեմասերի ձեռքբերման)
|
||||
իրականացման ժամկետը սահմանվում է մեկ ամիս:
|
||||
2.3. Ընկերությունից դուրս եկող մասնակցի բաժնեմասը դուրս գալու դիմումը ներկայացնելու պահից
|
||||
փոխանցվում է ընկերությանը:
|
||||
2.4. Ընկերության մասնակիցները կարող են տեղեկություններ ստանալ, ընկերության գործունեության մասին
|
||||
գաղտնի փաստաթղթերից բացի, ծանոթանալ հաշվապահական հաշվառման, հաշվետվության,
|
||||
ընկերության արտադրատնտեսական գործունեության այլ փաստաթղթերի հետ:
|
||||
2.5. Ընկերության մասնակիցները պարտավոր են`– Ընկերության մասնակիցների ընդհանուր ժողովի սահմանված կարգի համաձայն կատարել
|
||||
ներդրումներ Ընկերության կանոնադրական կապիտալում:
|
||||
3. ԸՆԿԵՐՈՒԹՅԱՆ ԿԱՆՈՆԱԴՐԱԿԱՆ ԿԱՊԻՏԱԼԸ
|
||||
3.1. Ընկերության կանոնադրական կապիտալը կազմում է 1000 դրամ:
|
||||
Կանոնադրական կապիտալը սահմանում է պարտատերերի շահերը երաշխավորող ընկերության գույքի
|
||||
նվազագույն չափը:
|
||||
Ընկերության 100% բաժնեմասերը տեղաբաշխված են, լրիվ վճարված և պատկանում են սույն
|
||||
կանոնադրության հավելվածում նշված մասնակցին (մասնակիցներին):
|
||||
Էջ 2 4-ից
|
||||
Սույն կանոնադրությունը կազմված է 2026-05-18 և բաղկացած է 4 թերթից:
|
||||
4. ԸՆԿԵՐՈՒԹՅԱՆ ԿԱՌԱՎԱՐՈՒՄԸ
|
||||
4.1. Ընկերության կառավարման մարմիններն են Ընկերության մասնակիցների ընդհանուր ժողովը և
|
||||
Ընկերության գործադիր մարմինը՝ տնօրենը:
|
||||
4.2. Ընկերության կառավարման բարձրագույն մարմինը Ընկերության մասնակիցների ընդհանուր ժողովն է,
|
||||
որն ունի Ընկերության կառավարման և գործունեության ցանկացած հարցի վերջնական լուծման
|
||||
իրավունք:
|
||||
4.3. Ընկերության մասնակիցների հերթական ընդհանուր ժողովը հրավիրում է Ընկերության տնօրենի կողմից
|
||||
տարեկան մեկ անգամ ֆինանսական տարվա ավարտից ոչ շուտ, քան երկու ամիս ոչ ուշ, քան չորս ամիս
|
||||
անց: Ընկերությունը պարտավոր է ամեն տարի գումարել մասնակիցների հերթական ընդհանուր ժողովը`
|
||||
Ընկերության գործունեության տարեկան արդյունքները հաստատելու համար:
|
||||
4.4. Ընկերության ընթացիկ գործունեության ղեկավարումն իրականացնում է տնօրենը, որն ընտրվում է
|
||||
Ընկերության մասնակիցների ընդհանուր ժողովի կողմից:
|
||||
Տնօրենը իրավունք ունի առանց լիազորության գործարքներ կատարել Ընկերության անունից, եթե
|
||||
գործարքի գումարը չի գերազանցում ընկերության զուտ ակտիվների մեծության 25%-ից:
|
||||
Էջ 3 4-ից
|
||||
Սույն կանոնադրությունը կազմված է 2026-05-18 և բաղկացած է 4 թերթից:
|
||||
«ԼԱՎԵՐՈ»
|
||||
ՍԱՀՄԱՆԱՓԱԿ ՊԱՏԱՍԽԱՆԱՏՎՈՒԹՅԱՄԲ ԸՆԿԵՐՈՒԹՅԱՆ
|
||||
մասնակիցների ցուցակ
|
||||
Մասնակցի քաղաքացիությունը, անունը, ազգանունը (պետությունը
|
||||
որտեղ հիմնադրվել է, անվանումը) անձնագրի(գրանցման) տվյալները
|
||||
հասցեն (գտնվելու վայրը)
|
||||
Բաժնեմասի
|
||||
չափը - %
|
||||
Բաժնեմասը
|
||||
ՀՀ դրամով
|
||||
ԳԵՎՈՐԳ ՄԱԹԵՎՈՍՅԱՆ ՀԱՄԼԵՏԻ
|
||||
Քաղաքացիություն՝ ՀԱՅԱՍՏԱՆ
|
||||
ՀԾՀ` 2723060837
|
||||
ՀԱՅԱՍՏԱՆ ԿՈՏԱՅՔ ԱԲՈՎՅԱՆ ՎԵՐԻՆ ՊՏՂՆԻ 3 Փ. Տ 28 2228
|
||||
100.0 % 1000.0
|
||||
Էջ 4 4-ից"
|
||||
any questions?
|
||||
|
||||
12
nginx.conf
12
nginx.conf
@@ -45,3 +45,15 @@ server {
|
||||
# brotli_comp_level 6;
|
||||
# brotli_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript image/svg+xml;
|
||||
}
|
||||
|
||||
server {
|
||||
listen 80;
|
||||
server_name lovero.store www.lovero.store;
|
||||
|
||||
location / {
|
||||
proxy_pass http://127.0.0.1:4202;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
}
|
||||
}
|
||||
|
||||
968
package-lock.json
generated
968
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
34
package.json
34
package.json
@@ -12,24 +12,21 @@
|
||||
"build:dexar": "ng build --configuration=production",
|
||||
"build:novo": "ng build --configuration=novo-production",
|
||||
"watch": "ng build --watch --configuration development",
|
||||
"test": "ng test",
|
||||
"lavero": "ng serve --configuration=lavero --port 4202 --proxy-config proxy.conf.lavero.json",
|
||||
"start:lavero": "ng serve --configuration=lavero --port 4202",
|
||||
"build:lavero": "ng build --configuration=lavero-production"
|
||||
},
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@angular/animations": "^21.1.5",
|
||||
"@angular/cdk": "^21.1.5",
|
||||
"@angular/common": "^21.0.6",
|
||||
"@angular/compiler": "^21.0.6",
|
||||
"@angular/core": "^21.0.6",
|
||||
"@angular/forms": "^21.0.6",
|
||||
"@angular/material": "^21.1.5",
|
||||
"@angular/platform-browser": "^21.0.6",
|
||||
"@angular/platform-browser-dynamic": "^21.1.5",
|
||||
"@angular/router": "^21.0.6",
|
||||
"@angular/service-worker": "^21.0.6",
|
||||
"@angular/animations": "21.1.5",
|
||||
"@angular/cdk": "21.1.5",
|
||||
"@angular/common": "21.1.5",
|
||||
"@angular/compiler": "21.1.5",
|
||||
"@angular/core": "21.1.5",
|
||||
"@angular/forms": "21.1.5",
|
||||
"@angular/platform-browser": "21.1.5",
|
||||
"@angular/router": "21.1.5",
|
||||
"@angular/service-worker": "21.1.5",
|
||||
"primeicons": "^7.0.0",
|
||||
"primeng": "^21.0.3",
|
||||
"rxjs": "~7.8.0",
|
||||
@@ -37,16 +34,9 @@
|
||||
"zone.js": "~0.16.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@angular/build": "^21.0.6",
|
||||
"@angular/cli": "^21.0.6",
|
||||
"@angular/compiler-cli": "^21.0.6",
|
||||
"@types/jasmine": "~5.1.0",
|
||||
"jasmine-core": "~5.13.0",
|
||||
"karma": "~6.4.0",
|
||||
"karma-chrome-launcher": "~3.2.0",
|
||||
"karma-coverage": "~2.2.0",
|
||||
"karma-jasmine": "~5.1.0",
|
||||
"karma-jasmine-html-reporter": "~2.1.0",
|
||||
"@angular/build": "21.1.5",
|
||||
"@angular/cli": "21.1.5",
|
||||
"@angular/compiler-cli": "21.1.5",
|
||||
"typescript": "~5.9.3"
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"/api": {
|
||||
"target": "https://api.lavero.store:555",
|
||||
"target": "https://api.lovero.store:555",
|
||||
"secure": false,
|
||||
"changeOrigin": true,
|
||||
"pathRewrite": {
|
||||
|
||||
@@ -18,6 +18,10 @@
|
||||
}
|
||||
<router-outlet></router-outlet>
|
||||
</main>
|
||||
@defer (on viewport) {
|
||||
<app-footer></app-footer>
|
||||
<app-telegram-login />
|
||||
} @placeholder {
|
||||
<div class="footer-placeholder" aria-hidden="true"></div>
|
||||
}
|
||||
<!-- <app-telegram-login /> -->
|
||||
}
|
||||
@@ -5,6 +5,10 @@
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.footer-placeholder {
|
||||
min-height: 1px;
|
||||
}
|
||||
|
||||
.server-check-overlay,
|
||||
.server-error-overlay {
|
||||
display: flex;
|
||||
|
||||
@@ -2,11 +2,10 @@
|
||||
import { Component, OnInit, signal, ApplicationRef, inject, DestroyRef } from '@angular/core';
|
||||
import { Router, RouterOutlet, NavigationEnd } from '@angular/router';
|
||||
import { Title } from '@angular/platform-browser';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { HeaderComponent } from './components/header/header.component';
|
||||
import { FooterComponent } from './components/footer/footer.component';
|
||||
import { BackButtonComponent } from './components/back-button/back-button.component';
|
||||
import { TelegramLoginComponent } from './components/telegram-login/telegram-login.component';
|
||||
import { ApiService } from './services';
|
||||
import { interval, concat } from 'rxjs';
|
||||
import { filter, first } from 'rxjs/operators';
|
||||
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
||||
@@ -17,7 +16,7 @@ import { TranslateService } from './i18n/translate.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
imports: [RouterOutlet, HeaderComponent, FooterComponent, BackButtonComponent, TelegramLoginComponent, TranslatePipe],
|
||||
imports: [RouterOutlet, HeaderComponent, FooterComponent, BackButtonComponent, TranslatePipe],
|
||||
templateUrl: './app.html',
|
||||
styleUrl: './app.scss'
|
||||
})
|
||||
@@ -28,7 +27,7 @@ export class App implements OnInit {
|
||||
serverAvailable = signal(false);
|
||||
|
||||
private destroyRef = inject(DestroyRef);
|
||||
private apiService = inject(ApiService);
|
||||
private http = inject(HttpClient);
|
||||
private titleService = inject(Title);
|
||||
private swUpdate = inject(SwUpdate);
|
||||
private appRef = inject(ApplicationRef);
|
||||
@@ -56,7 +55,7 @@ export class App implements OnInit {
|
||||
|
||||
private checkServerHealth(): void {
|
||||
this.checkingServer.set(true);
|
||||
this.apiService.ping()
|
||||
this.http.get<{ message: string }>(`${environment.apiUrl}/ping`)
|
||||
.pipe(takeUntilDestroyed(this.destroyRef))
|
||||
.subscribe({
|
||||
next: () => {
|
||||
@@ -92,13 +91,5 @@ export class App implements OnInit {
|
||||
console.error('Update check failed:', err);
|
||||
}
|
||||
});
|
||||
|
||||
this.swUpdate.versionUpdates
|
||||
.pipe(takeUntilDestroyed(this.destroyRef))
|
||||
.subscribe(event => {
|
||||
if (event.type === 'VERSION_READY') {
|
||||
console.log('New app version ready');
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,19 +12,19 @@
|
||||
<p>We are a rapidly growing marketplace connecting sellers and buyers from different countries. Our platform creates convenient conditions for safe trading of various goods and services.</p>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">🎯</div>
|
||||
<h3>Our Mission</h3>
|
||||
<p>To create a simple and profitable ecosystem for businesses and buyers, where everyone finds the best deals.</p>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">🌍</div>
|
||||
<h3>Geography</h3>
|
||||
<p>We operate in Russia, Armenia, UAE, Turkey, China, Kazakhstan, Kyrgyzstan, and other countries.</p>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">💼</div>
|
||||
<h3>For Business</h3>
|
||||
<ul class="compact-list">
|
||||
@@ -35,7 +35,7 @@
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">🛍️</div>
|
||||
<h3>For Buyers</h3>
|
||||
<ul class="compact-list">
|
||||
@@ -46,7 +46,7 @@
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">🔒</div>
|
||||
<h3>Our Values</h3>
|
||||
<div class="features-list">
|
||||
@@ -79,18 +79,17 @@
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">🏢</div>
|
||||
<h3>Company Details</h3>
|
||||
<p><strong>Company:</strong> ООО «ЭЛЕКТРОМОТОРС»</p>
|
||||
<p><strong>Director:</strong> Тоноян Ваграм</p>
|
||||
<p><strong>TIN:</strong> 9909687443</p>
|
||||
<p><strong>KPP:</strong> 770287001</p>
|
||||
<p><strong>Address:</strong> АРМЕНИЯ, 0501, АРАГАЦОТНСКАЯ ОБЛАСТЬ, ТАЛИН, ул. ГАЯ, д. 12</p>
|
||||
<p><strong>Bank:</strong> To be confirmed</p>
|
||||
<p><strong>Company:</strong> «LAVERO» LLC</p>
|
||||
<p><strong>Director:</strong> GEVORG MATEVOSYAN</p>
|
||||
<p><strong>TIN (ՀVHH):</strong> 03590442</p>
|
||||
<p><strong>Registration No.:</strong> 999.110.1583686</p>
|
||||
<p><strong>Address:</strong> ARMENIA, KOTAYK, ABOVYAN, VERIN PTGHNI, 3rd Street, 28</p>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">📞</div>
|
||||
<h3>Contact Us</h3>
|
||||
<a href="mailto:info@lavero.market" class="contact-email">info@lavero.market</a>
|
||||
<a href="mailto:info@lavero.store" class="contact-email">info@lavero.store</a>
|
||||
<p><a [href]="env.phoneTel">{{ env.phones.support }}</a></p>
|
||||
<p class="support-note">We are always in touch</p>
|
||||
</div>
|
||||
|
||||
@@ -12,19 +12,19 @@
|
||||
<p>Մենք դինամիկ զարգացող մարկեթփլեյս ենք, որը միավորում է վաճառողներին և գնորդներին տարբեր երկրներից։ Մեր հարթակը ստեղծում է հարմար պայմաններ տարբեր ապրանքների և ծառայությունների անվտանգ առևտրի համար։</p>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">🎯</div>
|
||||
<h3>Մեր առաքելությունը</h3>
|
||||
<p>Ստեղծել պարզ և շահավետ էկոհամակարգ բիզնեսի և գնորդների համար, որտեղ բոլորը գտնեն լավագույն առաջարկները։</p>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">🌍</div>
|
||||
<h3>Աշխարհագրություն</h3>
|
||||
<p>Մենք աշխատում ենք Ռուսաստանում, Հայաստանում, ԱՀԷ-ում, Թուրքիայում, Չինաստանում, Ղազախստանում, Ղրղզստանում և այլ երկրներում։</p>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">💼</div>
|
||||
<h3>Բիզնեսի համար</h3>
|
||||
<ul class="compact-list">
|
||||
@@ -35,7 +35,7 @@
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">🛍️</div>
|
||||
<h3>Գնորդների համար</h3>
|
||||
<ul class="compact-list">
|
||||
@@ -46,7 +46,7 @@
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">🔒</div>
|
||||
<h3>Մեր արժեքները</h3>
|
||||
<div class="features-list">
|
||||
@@ -79,18 +79,17 @@
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">🏢</div>
|
||||
<h3>Ինկերության տվյալները</h3>
|
||||
<p><strong>Ինկերություն՝</strong> ООО «ЭЛЕКТРОМОТОРС»</p>
|
||||
<p><strong>Տնօրեն՝</strong> Тоноян Ваграм</p>
|
||||
<p><strong>ՀՍՀ՝</strong> 9909687443</p>
|
||||
<p><strong>ԿՊՊ՝</strong> 770287001</p>
|
||||
<p><strong>Հասցե՝</strong> АРМЕНИЯ, 0501, АРАГАЦОТНСКАЯ ОБЛАСТЬ, ТАЛИН, ул. ГАЯ, д. 12</p>
|
||||
<p><strong>Բանկ՝</strong> Ճշտում է</p>
|
||||
<p><strong>Ընկерություն՝</strong> «ԼАВЕРО» ՍՊԸ</p>
|
||||
<p><strong>Տнօрен՝</strong> ГЕВORG МАТЕВОСЯН (GEVORG MATEVOSYAN)</p>
|
||||
<p><strong>ՀВHH՝</strong> 03590442</p>
|
||||
<p><strong>Гранцман h/h՝</strong> 999.110.1583686</p>
|
||||
<p><strong>Hasцe՝</strong> ՀАЙАСТАН, КОТАЙК, АБОВЯН, ВЕРИН ПТГНИ, 3-рд ПOЛOC, 28</p>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">📞</div>
|
||||
<h3>Կապվել մեզ հետ</h3>
|
||||
<a href="mailto:info@lavero.market" class="contact-email">info@lavero.market</a>
|
||||
<a href="mailto:info@lavero.store" class="contact-email">info@lavero.store</a>
|
||||
<p><a [href]="env.phoneTel">{{ env.phones.support }}</a></p>
|
||||
<p class="support-note">Մենք միշտ կապի մեջ ենք</p>
|
||||
</div>
|
||||
|
||||
@@ -12,19 +12,19 @@
|
||||
<p>Мы - динамично развивающийся маркетплейс, объединяющий продавцов и покупателей из разных стран. Наша платформа создает удобные условия для безопасной торговли различными товарами и услугами.</p>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">🎯</div>
|
||||
<h3>Наша миссия</h3>
|
||||
<p>Создавать простую и выгодную экосистему для бизнеса и покупателей, где каждый находит лучшие предложения.</p>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">🌍</div>
|
||||
<h3>География</h3>
|
||||
<p>Мы работаем в России, Армении, ОАЭ, Турции, Китае, Казахстане, Кыргызстане и других странах.</p>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">💼</div>
|
||||
<h3>Для бизнеса</h3>
|
||||
<ul class="compact-list">
|
||||
@@ -35,7 +35,7 @@
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">🛍️</div>
|
||||
<h3>Для покупателей</h3>
|
||||
<ul class="compact-list">
|
||||
@@ -46,7 +46,7 @@
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">🔒</div>
|
||||
<h3>Наши ценности</h3>
|
||||
<div class="features-list">
|
||||
@@ -79,18 +79,17 @@
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">🏢</div>
|
||||
<h3>Реквизиты компании</h3>
|
||||
<p><strong>Компания:</strong> ООО «ЭЛЕКТРОМОТОРС»</p>
|
||||
<p><strong>Директор:</strong> Тоноян Ваграм</p>
|
||||
<p><strong>ИНН:</strong> 9909687443</p>
|
||||
<p><strong>КПП:</strong> 770287001</p>
|
||||
<p><strong>Адрес:</strong> АРМЕНИЯ, 0501, АРАГАЦОТНСКАЯ ОБЛАСТЬ, ТАЛИН, ул. ГАЯ, д. 12</p>
|
||||
<p><strong>Банк:</strong> Уточняется</p>
|
||||
<p><strong>Компания:</strong> «ЛАВЕРО» ООО</p>
|
||||
<p><strong>Директор:</strong> ГЕВОРГ МАТЕВОСЯН</p>
|
||||
<p><strong>ՀВՀՀ (ИНН):</strong> 03590442</p>
|
||||
<p><strong>Рег. номер:</strong> 999.110.1583686</p>
|
||||
<p><strong>Адрес:</strong> АРМЕНИЯ, КОТАЙК, АБОВЯН, ВЕРИН ПТГНИ, ул. 3-я, 28</p>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">📞</div>
|
||||
<h3>Связаться с нами</h3>
|
||||
<a href="mailto:info@lavero.market" class="contact-email">info@lavero.market</a>
|
||||
<a href="mailto:info@lavero.store" class="contact-email">info@lavero.store</a>
|
||||
<p><a [href]="env.phoneTel">{{ env.phones.support }}</a></p>
|
||||
<p class="support-note">Мы всегда на связи</p>
|
||||
</div>
|
||||
|
||||
@@ -6,33 +6,33 @@
|
||||
</div>
|
||||
|
||||
<div class="lavero-cards">
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">🏢</div>
|
||||
<h3>Organization</h3>
|
||||
<p class="org-name">LLC «ELECTROMOTORS»</p>
|
||||
<p><strong>TIN:</strong> 9909687443</p>
|
||||
<p><strong>TIN:</strong> 03590442</p>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">📞</div>
|
||||
<h3>Phone</h3>
|
||||
<p><a [href]="env.phoneTel">{{ env.phones.support }}</a></p>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">✉️</div>
|
||||
<h3>Email</h3>
|
||||
<p><a href="mailto:info@lavero.market">info@lavero.market</a></p>
|
||||
<p><a href="mailto:info@lavero.store">info@lavero.store</a></p>
|
||||
<p class="note">Response within 24 hours</p>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">📍</div>
|
||||
<h3>Address</h3>
|
||||
<p>Armenia, 0501, Aragatsotn region, Talin, 12 Gaya St.</p>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">⏰</div>
|
||||
<h3>Working Hours</h3>
|
||||
<p><strong>Support:</strong> 9:00 - 21:00</p>
|
||||
@@ -42,7 +42,7 @@
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">💬</div>
|
||||
<h3>Contact Us</h3>
|
||||
<p>If you experience technical issues with the website or have questions about placing an order, please contact us at <a href="mailto:info@lavero.market">info@lavero.market</a> with a detailed description of the problem.</p>
|
||||
<p>If you experience technical issues with the website or have questions about placing an order, please contact us at <a href="mailto:info@lavero.store">info@lavero.store</a> with a detailed description of the problem.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -6,33 +6,33 @@
|
||||
</div>
|
||||
|
||||
<div class="lavero-cards">
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">🏢</div>
|
||||
<h3>Կազմակերպություն</h3>
|
||||
<p class="org-name">ՍՊԸ «ԷԼԵԿՏՌՈՄՈՏՈՌՍ»</p>
|
||||
<p><strong>ՀՎՀՀ՝</strong> 9909687443</p>
|
||||
<p><strong>ՀՎՀՀ՝</strong> 03590442</p>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">📞</div>
|
||||
<h3>Հեռախոս</h3>
|
||||
<p><a [href]="env.phoneTel">{{ env.phones.support }}</a></p>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">✉️</div>
|
||||
<h3>Էլ. փոստ</h3>
|
||||
<p><a href="mailto:info@lavero.market">info@lavero.market</a></p>
|
||||
<p><a href="mailto:info@lavero.store">info@lavero.store</a></p>
|
||||
<p class="note">Պատասխանը 24 ժամվա ընթացքում</p>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">📍</div>
|
||||
<h3>Հասցե</h3>
|
||||
<p>Հայաստան, 0501, Արագածոտնի մարզ, ք. Տալին, Գայայի փող. 12</p>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">⏰</div>
|
||||
<h3>Աշխատանքային ժամեր</h3>
|
||||
<p><strong>Աջակցություն՝</strong> 9:00 - 21:00</p>
|
||||
@@ -42,7 +42,7 @@
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">💬</div>
|
||||
<h3>Կապվել մեզ հետ</h3>
|
||||
<p>Կայքի տեխնիկական խնդիրների դեպքում կամ պատվերի ձևակերպման հարցերի դեպքում դիմեք <a href="mailto:info@lavero.market">info@lavero.market</a> խնդրի մանրամասն նկարագրությամբ։</p>
|
||||
<p>Կայքի տեխնիկական խնդիրների դեպքում կամ պատվերի ձևակերպման հարցերի դեպքում դիմեք <a href="mailto:info@lavero.store">info@lavero.store</a> խնդրի մանրամասն նկարագրությամբ։</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -6,33 +6,33 @@
|
||||
</div>
|
||||
|
||||
<div class="lavero-cards">
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">🏢</div>
|
||||
<h3>Организация</h3>
|
||||
<p class="org-name">ООО «ЭЛЕКТРОМОТОРС»</p>
|
||||
<p><strong>ИНН:</strong> 9909687443</p>
|
||||
<p class="org-name">ООО «ЛАВЕРО»</p>
|
||||
<p><strong>ИНН:</strong> 03590442</p>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">📞</div>
|
||||
<h3>Телефон</h3>
|
||||
<p><a [href]="env.phoneTel">{{ env.phones.support }}</a></p>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">✉️</div>
|
||||
<h3>Email</h3>
|
||||
<p><a href="mailto:info@lavero.market">info@lavero.market</a></p>
|
||||
<p><a href="mailto:info@lavero.store">info@lavero.store</a></p>
|
||||
<p class="note">Ответ в течение 24 часов</p>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">📍</div>
|
||||
<h3>Адрес</h3>
|
||||
<p>Армения, 0501, Арагацотиская обл., г. Талин, ул. Гая, д. 12</p>
|
||||
<p>АРМЕНИЯ, КОТАЙК, АБОВЯН, ВЕРИН ПТГНИ, ул. 3-я, 28</p>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">⏰</div>
|
||||
<h3>Часы работы</h3>
|
||||
<p><strong>Поддержка:</strong> 9:00 - 21:00</p>
|
||||
@@ -42,7 +42,7 @@
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">💬</div>
|
||||
<h3>Связаться с нами</h3>
|
||||
<p>При возникновении технических проблем с работой сайта или вопросов по оформлению заказа обращайтесь на <a href="mailto:info@lavero.market">info@lavero.market</a> с подробным описанием проблемы.</p>
|
||||
<p>При возникновении технических проблем с работой сайта или вопросов по оформлению заказа обращайтесь на <a href="mailto:info@lavero.store">info@lavero.store</a> с подробным описанием проблемы.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
</div>
|
||||
|
||||
<div class="lavero-cards">
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">📧</div>
|
||||
<h3>Digital Products</h3>
|
||||
<div class="features-list">
|
||||
@@ -18,7 +18,7 @@
|
||||
<p class="note important" style="margin-top: 12px;">⚠️ The platform is not responsible for digital products. The seller is responsible for quality and functionality.</p>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">📦</div>
|
||||
<h3>Physical Products</h3>
|
||||
<ul class="compact-list">
|
||||
@@ -32,7 +32,7 @@
|
||||
<p class="note important" style="margin-top: 12px;">⚠️ The platform is not responsible for the actions of shipping companies. Delivery is handled by СДЭК, Почта России, Boxberry, DPD, and other carriers.</p>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">💰</div>
|
||||
<h3>Delivery Cost</h3>
|
||||
<div class="delivery-cost">
|
||||
@@ -48,7 +48,7 @@
|
||||
<p class="note">Exact cost is calculated at checkout</p>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">🔍</div>
|
||||
<h3>Tracking</h3>
|
||||
<p>After shipping, you will receive a tracking number by email. Track your package on the delivery service website or in your account.</p>
|
||||
@@ -66,11 +66,11 @@
|
||||
<p class="note important">If there are issues - file a report with the courier</p>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">📞</div>
|
||||
<h3>Questions about delivery?</h3>
|
||||
<p>Contact the seller or us:</p>
|
||||
<a href="mailto:info@lavero.market" class="contact-email">info@lavero.market</a>
|
||||
<a href="mailto:info@lavero.store" class="contact-email">info@lavero.store</a>
|
||||
<p><a [href]="env.phoneTel">{{ env.phones.support }}</a></p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
</div>
|
||||
|
||||
<div class="lavero-cards">
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">📧</div>
|
||||
<h3>Թվային ապրանքներ</h3>
|
||||
<div class="features-list">
|
||||
@@ -18,7 +18,7 @@
|
||||
<p class="note important" style="margin-top: 12px;">⚠️ Հարթակը պատասխանատվություն չի կրում թվային ապրանքների համար։ Որակի և գործունակության համար պատասխանատու է վաճառողը։</p>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">📦</div>
|
||||
<h3>Ֆիզիկական ապրանքներ</h3>
|
||||
<ul class="compact-list">
|
||||
@@ -32,7 +32,7 @@
|
||||
<p class="note important" style="margin-top: 12px;">⚠️ Հարթակը պատասխանատվություն չի կրում տրանսպորտային ընկերությունների գործողությունների համար։ Առաքման համար պատասխանատու են СДЭК, Почта России, Boxberry, DPD և այլ փոխադրողներ։</p>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">💰</div>
|
||||
<h3>Առաքման արժեքը</h3>
|
||||
<div class="delivery-cost">
|
||||
@@ -48,7 +48,7 @@
|
||||
<p class="note">Ճիշտ արժեքը հաշվարկվում է ձևակերպման ժամանակ</p>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">🔍</div>
|
||||
<h3>Հետագծում</h3>
|
||||
<p>Ուղարկմանից հետո դուք կստանաք թրեք-համար email-ով։ Հետևեք ծանրութը առաքման ծառայության կայքում կամ անձնական էջում։</p>
|
||||
@@ -66,11 +66,11 @@
|
||||
<p class="note important">Եթե խնդիրներ կան - կազմեք ակտ սուրհանդեսի հետ</p>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">📞</div>
|
||||
<h3>Առաքման հարցեր՞</h3>
|
||||
<p>Կապվեք վաճառողի կամ մեզ հետ՝</p>
|
||||
<a href="mailto:info@lavero.market" class="contact-email">info@lavero.market</a>
|
||||
<a href="mailto:info@lavero.store" class="contact-email">info@lavero.store</a>
|
||||
<p><a [href]="env.phoneTel">{{ env.phones.support }}</a></p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
</div>
|
||||
|
||||
<div class="lavero-cards">
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">📧</div>
|
||||
<h3>Цифровые товары</h3>
|
||||
<div class="features-list">
|
||||
@@ -18,7 +18,7 @@
|
||||
<p class="note important" style="margin-top: 12px;">⚠️ Платформа не несет ответственности за цифровые товары. За качество и работоспособность отвечает продавец.</p>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">📦</div>
|
||||
<h3>Физические товары</h3>
|
||||
<ul class="compact-list">
|
||||
@@ -32,7 +32,7 @@
|
||||
<p class="note important" style="margin-top: 12px;">⚠️ Платформа не несет ответственности за действия транспортных компаний. За доставку отвечают СДЭК, Почта России, Boxberry, DPD и другие перевозчики.</p>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">💰</div>
|
||||
<h3>Стоимость доставки</h3>
|
||||
<div class="delivery-cost">
|
||||
@@ -48,7 +48,7 @@
|
||||
<p class="note">Точная стоимость рассчитывается при оформлении</p>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">🔍</div>
|
||||
<h3>Отслеживание</h3>
|
||||
<p>После отправки вы получите трек-номер на email. Отслеживайте посылку на сайте службы доставки или в личном кабинете.</p>
|
||||
@@ -66,11 +66,11 @@
|
||||
<p class="note important">Если есть проблемы - составьте акт с курьером</p>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">📞</div>
|
||||
<h3>Вопросы по доставке?</h3>
|
||||
<p>Свяжитесь с продавцом или нами:</p>
|
||||
<a href="mailto:info@lavero.market" class="contact-email">info@lavero.market</a>
|
||||
<a href="mailto:info@lavero.store" class="contact-email">info@lavero.store</a>
|
||||
<p><a [href]="env.phoneTel">{{ env.phones.support }}</a></p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
</div>
|
||||
|
||||
<div class="lavero-cards">
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">🛍️</div>
|
||||
<h3>How to place an order?</h3>
|
||||
<div class="process-steps-compact">
|
||||
@@ -17,7 +17,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">💳</div>
|
||||
<h3>Payment Methods</h3>
|
||||
<ul class="compact-list">
|
||||
@@ -29,7 +29,7 @@
|
||||
<p class="note">*Depends on the seller</p>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">🚚</div>
|
||||
<h3>Delivery</h3>
|
||||
<div class="delivery-info">
|
||||
@@ -44,13 +44,13 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">↩️</div>
|
||||
<h3>Product Returns</h3>
|
||||
<p>You can return a product in good condition within 7 days, provided it has not been used and the packaging is intact.</p>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">🔒</div>
|
||||
<h3>Security</h3>
|
||||
<div class="features-list">
|
||||
@@ -60,7 +60,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">⏱️</div>
|
||||
<h3>Order Processing</h3>
|
||||
<p>Your order is processed immediately after payment. The seller ships the product within 1-3 business days.</p>
|
||||
@@ -72,7 +72,7 @@
|
||||
<div class="contacts-grid">
|
||||
<div class="contact-item">
|
||||
<strong>Email</strong>
|
||||
<a href="mailto:info@lavero.market">info@lavero.market</a>
|
||||
<a href="mailto:info@lavero.store">info@lavero.store</a>
|
||||
</div>
|
||||
<div class="contact-item">
|
||||
<strong>Phone</strong>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
</div>
|
||||
|
||||
<div class="lavero-cards">
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">🛍️</div>
|
||||
<h3>Ինչպես կատարել պատվեր՞</h3>
|
||||
<div class="process-steps-compact">
|
||||
@@ -17,7 +17,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">💳</div>
|
||||
<h3>Վճարման եղանակներ</h3>
|
||||
<ul class="compact-list">
|
||||
@@ -29,7 +29,7 @@
|
||||
<p class="note">*Կախված է վաճառողից</p>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">🚚</div>
|
||||
<h3>Առաքում</h3>
|
||||
<div class="delivery-info">
|
||||
@@ -44,13 +44,13 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">↩️</div>
|
||||
<h3>Ապրանքի վերադարձ</h3>
|
||||
<p>Կարելի է վերադարձել որակյալ ապրանքը 7 օրվա ընթացքում, եթե այն չի օգտագործվել և փաթեթավորումը պահպանված է։</p>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">🔒</div>
|
||||
<h3>Անվտանգություն</h3>
|
||||
<div class="features-list">
|
||||
@@ -60,7 +60,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">⏱️</div>
|
||||
<h3>Պատվերի մշակում</h3>
|
||||
<p>Պատվերը մշակվում է վճարումից անմիջապես հետո։ Վաճառողը ապրանքը ուղարկում է 1-3 աշխատանքային օրվա ընթացքում։</p>
|
||||
@@ -72,7 +72,7 @@
|
||||
<div class="contacts-grid">
|
||||
<div class="contact-item">
|
||||
<strong>Email</strong>
|
||||
<a href="mailto:info@lavero.market">info@lavero.market</a>
|
||||
<a href="mailto:info@lavero.store">info@lavero.store</a>
|
||||
</div>
|
||||
<div class="contact-item">
|
||||
<strong>Հեռախոս</strong>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
</div>
|
||||
|
||||
<div class="lavero-cards">
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">🛍️</div>
|
||||
<h3>Как сделать заказ?</h3>
|
||||
<div class="process-steps-compact">
|
||||
@@ -17,7 +17,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">💳</div>
|
||||
<h3>Способы оплаты</h3>
|
||||
<ul class="compact-list">
|
||||
@@ -29,7 +29,7 @@
|
||||
<p class="note">*Зависит от продавца</p>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">🚚</div>
|
||||
<h3>Доставка</h3>
|
||||
<div class="delivery-info">
|
||||
@@ -44,13 +44,13 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">↩️</div>
|
||||
<h3>Возврат товара</h3>
|
||||
<p>Можно вернуть качественный товар в течение 7 дней, если он не использовался и сохранена упаковка.</p>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">🔒</div>
|
||||
<h3>Безопасность</h3>
|
||||
<div class="features-list">
|
||||
@@ -60,7 +60,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">⏱️</div>
|
||||
<h3>Обработка заказа</h3>
|
||||
<p>Заказ обрабатывается сразу после оплаты. Продавец отправляет товар в течение 1-3 рабочих дней.</p>
|
||||
@@ -72,7 +72,7 @@
|
||||
<div class="contacts-grid">
|
||||
<div class="contact-item">
|
||||
<strong>Email</strong>
|
||||
<a href="mailto:info@lavero.market">info@lavero.market</a>
|
||||
<a href="mailto:info@lavero.store">info@lavero.store</a>
|
||||
</div>
|
||||
<div class="contact-item">
|
||||
<strong>Телефон</strong>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
</div>
|
||||
|
||||
<div class="lavero-cards">
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">🏷️</div>
|
||||
<h3>Warranty Periods</h3>
|
||||
<div class="warranty-periods">
|
||||
@@ -25,7 +25,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">✓</div>
|
||||
<h3>Warranty Conditions</h3>
|
||||
<ul class="compact-list">
|
||||
@@ -37,7 +37,7 @@
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">🛠️</div>
|
||||
<h3>Your Rights for Defects</h3>
|
||||
<ul class="compact-list">
|
||||
@@ -48,7 +48,7 @@
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">⏱️</div>
|
||||
<h3>Repair Timeframe</h3>
|
||||
<p>Maximum 45 days by law. If the deadline is violated, you can request a replacement or a refund.</p>
|
||||
@@ -67,7 +67,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">📝</div>
|
||||
<h3>How to File a Claim</h3>
|
||||
<div class="process-steps-compact">
|
||||
@@ -79,11 +79,11 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">📞</div>
|
||||
<h3>Need Help?</h3>
|
||||
<p>In case of disputes:</p>
|
||||
<a href="mailto:info@lavero.market" class="contact-email">info@lavero.market</a>
|
||||
<a href="mailto:info@lavero.store" class="contact-email">info@lavero.store</a>
|
||||
<p><a [href]="env.phoneTel">{{ env.phones.support }}</a></p>
|
||||
<p class="note">Subject: "Warranty Issue - Order #..."</p>
|
||||
</div>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
</div>
|
||||
|
||||
<div class="lavero-cards">
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">🏷️</div>
|
||||
<h3>Երաշխիքի ժամկետներ</h3>
|
||||
<div class="warranty-periods">
|
||||
@@ -25,7 +25,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">✓</div>
|
||||
<h3>Երաշխիքի պայմաններ</h3>
|
||||
<ul class="compact-list">
|
||||
@@ -37,7 +37,7 @@
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">🛠️</div>
|
||||
<h3>Ձեր իրավունքները թերության դեպքում</h3>
|
||||
<ul class="compact-list">
|
||||
@@ -48,7 +48,7 @@
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">⏱️</div>
|
||||
<h3>Նորոգման ժամկետ</h3>
|
||||
<p>Օրենքով առավելագույնը 45 օր։ Եթե ժամկետը խախտվի ՝ կարող եք պահանջել փոխարինում կամ գումարի վերադարձ։</p>
|
||||
@@ -67,7 +67,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">📝</div>
|
||||
<h3>Ինչպես դիմել հայտ</h3>
|
||||
<div class="process-steps-compact">
|
||||
@@ -79,11 +79,11 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">📞</div>
|
||||
<h3>Օգնությու՞ն պետք է՞</h3>
|
||||
<p>Վեճերի դեպքում՝</p>
|
||||
<a href="mailto:info@lavero.market" class="contact-email">info@lavero.market</a>
|
||||
<a href="mailto:info@lavero.store" class="contact-email">info@lavero.store</a>
|
||||
<p><a [href]="env.phoneTel">{{ env.phones.support }}</a></p>
|
||||
<p class="note">Թեմա՝ “Երաշխիքային հարց - Պատվեր №...”</p>
|
||||
</div>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
</div>
|
||||
|
||||
<div class="lavero-cards">
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">🏷️</div>
|
||||
<h3>Сроки гарантии</h3>
|
||||
<div class="warranty-periods">
|
||||
@@ -25,7 +25,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">✓</div>
|
||||
<h3>Условия гарантии</h3>
|
||||
<ul class="compact-list">
|
||||
@@ -37,7 +37,7 @@
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">🛠️</div>
|
||||
<h3>Ваши права при браке</h3>
|
||||
<ul class="compact-list">
|
||||
@@ -48,7 +48,7 @@
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">⏱️</div>
|
||||
<h3>Срок ремонта</h3>
|
||||
<p>Максимум 45 дней по закону. Если срок нарушен - можно требовать замену или возврат денег.</p>
|
||||
@@ -67,7 +67,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">📝</div>
|
||||
<h3>Как подать заявку</h3>
|
||||
<div class="process-steps-compact">
|
||||
@@ -79,11 +79,11 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">📞</div>
|
||||
<h3>Нужна помощь?</h3>
|
||||
<p>При возникновении споров:</p>
|
||||
<a href="mailto:info@lavero.market" class="contact-email">info@lavero.market</a>
|
||||
<a href="mailto:info@lavero.store" class="contact-email">info@lavero.store</a>
|
||||
<p><a [href]="env.phoneTel">{{ env.phones.support }}</a></p>
|
||||
<p class="note">Тема: "Гарантийный вопрос - Заказ №..."</p>
|
||||
</div>
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<section class="info-card wide">
|
||||
<div class="card-icon">📋</div>
|
||||
<h2>1. General Provisions</h2>
|
||||
<p>1.1. These Terms define the payment procedure for Goods and Services purchased by Buyers through the Lavero Market Marketplace.</p>
|
||||
<p>1.1. These Terms define the payment procedure for Goods and Services purchased by Buyers through the Lavero Store Marketplace.</p>
|
||||
<p>1.2. Payment is made for Goods/Services listed by independent Sellers. The Marketplace acts as an information intermediary and provides the technical infrastructure for processing payments.</p>
|
||||
<p>1.3. Payment for goods and services on the Marketplace is made in Russian rubles (RUB).</p>
|
||||
<p>1.4. Prices for Goods/Services are set by Sellers independently and are indicated on the corresponding Goods/Services page.</p>
|
||||
@@ -53,7 +53,7 @@
|
||||
<p>2.3. All payments are processed through certified payment systems in compliance with PCI DSS security standards.</p>
|
||||
</section>
|
||||
|
||||
<section class="info-card">
|
||||
<section class="info-card wide">
|
||||
<div class="card-icon">⚙️</div>
|
||||
<h2>3. Payment Process</h2>
|
||||
<p>3.1. The order payment procedure includes the following steps:</p>
|
||||
@@ -69,7 +69,7 @@
|
||||
<p>3.3. The Buyer's payment obligation is considered fulfilled from the moment the funds are received in the payment system account.</p>
|
||||
</section>
|
||||
|
||||
<section class="info-card">
|
||||
<section class="info-card wide">
|
||||
<div class="card-icon">🛡️</div>
|
||||
<h2>4. Payment Security</h2>
|
||||
<p>4.1. All payments are processed through a secure HTTPS connection using TLS 1.2 protocol and above.</p>
|
||||
@@ -84,7 +84,7 @@
|
||||
<p>4.4. In case of suspicious activity, the payment system has the right to request additional identity verification of the Buyer.</p>
|
||||
</section>
|
||||
|
||||
<section class="info-card">
|
||||
<section class="info-card wide">
|
||||
<div class="card-icon">✅</div>
|
||||
<h2>5. Payment Confirmation</h2>
|
||||
<p>5.1. After successful payment, the Buyer receives a confirmation to the email address provided during checkout.</p>
|
||||
@@ -124,7 +124,7 @@
|
||||
<p>6.4. The Marketplace does not charge a fee for processing refunds. Payment system and bank fees may apply in accordance with their tariffs.</p>
|
||||
</section>
|
||||
|
||||
<section class="info-card">
|
||||
<section class="info-card wide">
|
||||
<div class="card-icon">❌</div>
|
||||
<h2>7. Failed Payments</h2>
|
||||
<p>7.1. A payment may be declined for the following reasons:</p>
|
||||
@@ -141,7 +141,7 @@
|
||||
<li>Check the accuracy of the entered data</li>
|
||||
<li>Contact the card issuing bank to clarify the reason for the decline</li>
|
||||
<li>Try an alternative payment method</li>
|
||||
<li>Contact support: <a href="mailto:info@lavero.market">info@lavero.market</a></li>
|
||||
<li>Contact support: <a href="mailto:info@lavero.store">info@lavero.store</a></li>
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
@@ -150,7 +150,7 @@
|
||||
<h2>8. Payment Inquiries Contact</h2>
|
||||
<p>For questions related to order payments, you can contact us:</p>
|
||||
<ul class="compact-list">
|
||||
<li><strong>Email:</strong> <a href="mailto:info@lavero.market" class="contact-email">info@lavero.market</a></li>
|
||||
<li><strong>Email:</strong> <a href="mailto:info@lavero.store" class="contact-email">info@lavero.store</a></li>
|
||||
<li><strong>Phone:</strong> <a [href]="env.phoneTel">{{ env.phones.support }}</a></li>
|
||||
<li><strong>Working hours:</strong> 24/7 (technical support)</li>
|
||||
<li><strong>Average response time:</strong> Up to 24 hours on business days</li>
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<section class="info-card wide">
|
||||
<div class="card-icon">📋</div>
|
||||
<h2>1. Ընդհանուր դրույթներ</h2>
|
||||
<p>1.1. Սույն Կանոնները սահմանում են Lavero Market Մարկեթպլեյսի միջոցով Գնորդների կողմից ձեռք բերվող Ապրանքների և Ծառայությունների վճարման կարգը։</p>
|
||||
<p>1.1. Սույն Կանոնները սահմանում են Lavero Store Մարկեթպլեյսի միջոցով Գնորդների կողմից ձեռք բերվող Ապրանքների և Ծառայությունների վճարման կարգը։</p>
|
||||
<p>1.2. Վճարումը կատարվում է անկախ Վաճառողների կողմից տեղադրված Ապրանքների/Ծառայությունների համար։ Մարկեթպլեյսը հանդես է գալիս որպես տեղեկատվական միջնորդ և ապահովում է տեխնիկական ենթակառուցվածք վճարումների իրականացման համար։</p>
|
||||
<p>1.3. Մարկեթպլեյսում ապրանքների և ծառայությունների վճարումը կատարվում է ռուսական ռուբլով (RUB)։</p>
|
||||
<p>1.4. Ապրանքների/Ծառայությունների գները սահմանվում են Վաճառողների կողմից ինքնուրույն և նշված են համապատասխան Ապրանքի/Ծառայության էջում։</p>
|
||||
@@ -53,7 +53,7 @@
|
||||
<p>2.3. Բոլոր վճարումները մշակվում են սերտիֆիկացված վճարման համակարգերի միջոցով՝ PCI DSS անվտանգության ստանդարտներին համապատասխան։</p>
|
||||
</section>
|
||||
|
||||
<section class="info-card">
|
||||
<section class="info-card wide">
|
||||
<div class="card-icon">⚙️</div>
|
||||
<h2>3. Վճարման գործընթացը</h2>
|
||||
<p>3.1. Պատվերի վճարման գործընթացը ներառում է հետևյալ քայլերը՝</p>
|
||||
@@ -69,7 +69,7 @@
|
||||
<p>3.3. Գնորդի վճարման պարտավորությունը համարվում է կատարված վճարման համակարգի հաշվին դրամական միջոցների մուտքագրման պահից։</p>
|
||||
</section>
|
||||
|
||||
<section class="info-card">
|
||||
<section class="info-card wide">
|
||||
<div class="card-icon">🛡️</div>
|
||||
<h2>4. Վճարումների անվտանգություն</h2>
|
||||
<p>4.1. Բոլոր վճարումները մշակվում են պաշտպանված HTTPS կապակցով՝ TLS 1.2 և ավելի բարձր արթանագրի օգտագործմամբ։</p>
|
||||
@@ -84,7 +84,7 @@
|
||||
<p>4.4. Կասկածելի գործունեության դեպքում վճարման համակարգը իրավունք ունի պահանջել Գնորդի ինքնության լրացուցիչ ստուգում։</p>
|
||||
</section>
|
||||
|
||||
<section class="info-card">
|
||||
<section class="info-card wide">
|
||||
<div class="card-icon">✅</div>
|
||||
<h2>5. Վճարման հաստատում</h2>
|
||||
<p>5.1. Հաջող վճարմանից հետո Գնորդը ստանում է հաստատում պատվերի ձևակերպման թելադրված էլ. փոստի հասցեին։</p>
|
||||
@@ -124,7 +124,7 @@
|
||||
<p>6.4. Միջոցների վերադարձի մշակման համար Մարկեթպլեյսը միջնորդավճար չի գանձում։ Վճարման համակարգերի և բանկերի միջնորդավճարները կարող են կիրառվել դրանց սակագներին համապատասխան։</p>
|
||||
</section>
|
||||
|
||||
<section class="info-card">
|
||||
<section class="info-card wide">
|
||||
<div class="card-icon">❌</div>
|
||||
<h2>7. Անհաջող վճարումներ</h2>
|
||||
<p>7.1. Վճարումը կարող է մերժվել հետևյալ պատճառներով՝</p>
|
||||
@@ -141,7 +141,7 @@
|
||||
<li>Ստուգել մուտքագրված տվյալների ճշտությունը</li>
|
||||
<li>Կապվել քարտ թողարկող բանկի հետ մերժման պատճառը պարզելու համար</li>
|
||||
<li>Փորձել այլընտրանքային վճարման եղանակ</li>
|
||||
<li>Դիմել աջակցության ծառայությանը՝ <a href="mailto:info@lavero.market">info@lavero.market</a></li>
|
||||
<li>Դիմել աջակցության ծառայությանը՝ <a href="mailto:info@lavero.store">info@lavero.store</a></li>
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
@@ -150,7 +150,7 @@
|
||||
<h2>8. Վճարման հարցերի կապակցության կոնտակտներ</h2>
|
||||
<p>Պատվերների վճարման հետ կապված հարցերի համար կարող եք դիմել՝</p>
|
||||
<ul class="compact-list">
|
||||
<li><strong>Email:</strong> <a href="mailto:info@lavero.market" class="contact-email">info@lavero.market</a></li>
|
||||
<li><strong>Email:</strong> <a href="mailto:info@lavero.store" class="contact-email">info@lavero.store</a></li>
|
||||
<li><strong>Հեռախոս՝</strong> <a [href]="env.phoneTel">{{ env.phones.support }}</a></li>
|
||||
<li><strong>Աշխատանքի ժամերը՝</strong> Հստակետ (տեխնիկական աջակցություն)</li>
|
||||
<li><strong>Պատասխանի միջին ժամանակը՝</strong> Մինչև 24 ժամ աշխատանքային օրերին</li>
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<section class="info-card wide">
|
||||
<div class="card-icon">📋</div>
|
||||
<h2>1. Общие положения</h2>
|
||||
<p>1.1. Настоящие Правила определяют порядок оплаты Товаров и Услуг, приобретаемых Покупателями через Маркетплейс Lavero Market.</p>
|
||||
<p>1.1. Настоящие Правила определяют порядок оплаты Товаров и Услуг, приобретаемых Покупателями через Маркетплейс Lavero Store.</p>
|
||||
<p>1.2. Оплата производится за Товары/Услуги, размещенные независимыми Продавцами. Маркетплейс выступает в качестве информационного посредника и обеспечивает техническую инфраструктуру для проведения платежей.</p>
|
||||
<p>1.3. Оплата товаров и услуг на Маркетплейсе осуществляется в российских рублях (RUB).</p>
|
||||
<p>1.4. Цены на Товары/Услуги устанавливаются Продавцами самостоятельно и указываются на странице соответствующего Товара/Услуги.</p>
|
||||
@@ -53,7 +53,7 @@
|
||||
<p>2.3. Все платежи обрабатываются через сертифицированные платежные системы с соблюдением стандартов безопасности PCI DSS.</p>
|
||||
</section>
|
||||
|
||||
<section class="info-card">
|
||||
<section class="info-card wide">
|
||||
<div class="card-icon">⚙️</div>
|
||||
<h2>3. Процесс оплаты</h2>
|
||||
<p>3.1. Процедура оплаты заказа включает следующие этапы:</p>
|
||||
@@ -69,7 +69,7 @@
|
||||
<p>3.3. Обязательство Покупателя по оплате считается исполненным с момента поступления денежных средств на счет платежной системы.</p>
|
||||
</section>
|
||||
|
||||
<section class="info-card">
|
||||
<section class="info-card wide">
|
||||
<div class="card-icon">🛡️</div>
|
||||
<h2>4. Безопасность платежей</h2>
|
||||
<p>4.1. Все платежи обрабатываются через защищенное HTTPS-соединение с использованием протокола TLS 1.2 и выше.</p>
|
||||
@@ -84,7 +84,7 @@
|
||||
<p>4.4. В случае подозрительной активности платежная система имеет право запросить дополнительную верификацию личности Покупателя.</p>
|
||||
</section>
|
||||
|
||||
<section class="info-card">
|
||||
<section class="info-card wide">
|
||||
<div class="card-icon">✅</div>
|
||||
<h2>5. Подтверждение оплаты</h2>
|
||||
<p>5.1. После успешной оплаты Покупатель получает подтверждение на указанный при оформлении заказа адрес электронной почты.</p>
|
||||
@@ -124,7 +124,7 @@
|
||||
<p>6.4. За обработку возврата средств Маркетплейс комиссию не взимает. Комиссии платежных систем и банков могут применяться в соответствии с их тарифами.</p>
|
||||
</section>
|
||||
|
||||
<section class="info-card">
|
||||
<section class="info-card wide">
|
||||
<div class="card-icon">❌</div>
|
||||
<h2>7. Неуспешные платежи</h2>
|
||||
<p>7.1. Платеж может быть отклонен по следующим причинам:</p>
|
||||
@@ -141,7 +141,7 @@
|
||||
<li>Проверить правильность введенных данных</li>
|
||||
<li>Связаться с банком-эмитентом карты для уточнения причины отказа</li>
|
||||
<li>Попробовать альтернативный способ оплаты</li>
|
||||
<li>Обратиться в службу поддержки: <a href="mailto:info@lavero.market">info@lavero.market</a></li>
|
||||
<li>Обратиться в службу поддержки: <a href="mailto:info@lavero.store">info@lavero.store</a></li>
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
@@ -150,7 +150,7 @@
|
||||
<h2>8. Контакты для вопросов по оплате</h2>
|
||||
<p>По вопросам, связанным с оплатой заказов, вы можете обратиться:</p>
|
||||
<ul class="compact-list">
|
||||
<li><strong>Email:</strong> <a href="mailto:info@lavero.market" class="contact-email">info@lavero.market</a></li>
|
||||
<li><strong>Email:</strong> <a href="mailto:info@lavero.store" class="contact-email">info@lavero.store</a></li>
|
||||
<li><strong>Телефон:</strong> <a [href]="env.phoneTel">{{ env.phones.support }}</a></li>
|
||||
<li><strong>Время работы:</strong> Круглосуточно (техническая поддержка)</li>
|
||||
<li><strong>Среднее время ответа:</strong> До 24 часов в рабочие дни</li>
|
||||
|
||||
@@ -10,15 +10,15 @@
|
||||
<div class="card-icon">📋</div>
|
||||
<h2>1. GENERAL PROVISIONS</h2>
|
||||
|
||||
<p>1.1. This Privacy Policy (hereinafter — the Policy) defines the obligations of the Limited Liability Company «ЭЛЕКТРОМОТОРС» (hereinafter — the Operator) regarding the processing, use, storage, and protection of personal data (hereinafter PD, Personal Data) of users (hereinafter — the User).</p>
|
||||
<p>1.1. This Privacy Policy (hereinafter — the Policy) defines the obligations of the Limited Liability Company «ЛАВЕРО» (hereinafter — the Operator) regarding the processing, use, storage, and protection of personal data (hereinafter PD, Personal Data) of users (hereinafter — the User).</p>
|
||||
|
||||
<p>1.2. The Operator undertakes to strictly observe the rights and freedoms of individuals when processing their personal data, including the protection of the right to privacy, personal and family confidentiality.</p>
|
||||
|
||||
<p>1.3. The Personal Data Processing Policy (hereinafter — the Policy) has been developed in accordance with Federal Law No. 152-FZ dated July 27, 2006 «On Personal Data» (hereinafter — FZ-152).</p>
|
||||
|
||||
<p>1.4. The Policy can be reviewed on the Operator's website on the Internet at: <a href="https://lavero.market">https://lavero.market</a>.</p>
|
||||
<p>1.4. The Policy can be reviewed on the Operator's website on the Internet at: <a href="https://lavero.store">https://lavero.store</a>.</p>
|
||||
|
||||
<p>1.5. Applies to all activities related to the processing of personal data on the website <a href="https://lavero.market">https://lavero.market</a> and in the Operator's information systems.</p>
|
||||
<p>1.5. Applies to all activities related to the processing of personal data on the website <a href="https://lavero.store">https://lavero.store</a> and in the Operator's information systems.</p>
|
||||
|
||||
<p>1.6. A User who places an order, opens a personal account, or otherwise interacts with the Operator expresses consent to the processing of their personal data in accordance with the Policy and the legislation of the Russian Federation. Continued use of the website indicates agreement with the provisions of the Policy. A User who is not willing to agree to the terms should refrain from using the resource.</p>
|
||||
|
||||
@@ -42,7 +42,7 @@
|
||||
|
||||
<p><strong>PD Anonymization</strong> — actions that make it impossible to determine the ownership of data to a specific person without additional information.</p>
|
||||
|
||||
<p><strong>Website (Site)</strong> — an automated information system available on the Internet at: <a href="https://lavero.market">https://lavero.market</a>.</p>
|
||||
<p><strong>Website (Site)</strong> — an automated information system available on the Internet at: <a href="https://lavero.store">https://lavero.store</a>.</p>
|
||||
|
||||
<p><strong>PD Processing</strong> — any actions with personal data, including collection, recording, storage, updating, use, transfer, destruction, and other operations.</p>
|
||||
|
||||
@@ -60,9 +60,9 @@
|
||||
|
||||
<p><strong>PD Confidentiality</strong> — the Operator's obligation to protect data from distribution without the consent of the subject or a legal basis.</p>
|
||||
|
||||
<p><strong>Seller (Contractor)</strong> — a person offering goods or services on the website <a href="https://lavero.market">https://lavero.market</a>.</p>
|
||||
<p><strong>Seller (Contractor)</strong> — a person offering goods or services on the website <a href="https://lavero.store">https://lavero.store</a>.</p>
|
||||
|
||||
<p><strong>User</strong> — a person visiting or using resources managed by the Operator, including the website <a href="https://lavero.market">https://lavero.market</a>.</p>
|
||||
<p><strong>User</strong> — a person visiting or using resources managed by the Operator, including the website <a href="https://lavero.store">https://lavero.store</a>.</p>
|
||||
|
||||
<p><strong>Order</strong> — an order for goods or services placed by the User on the website.</p>
|
||||
|
||||
@@ -104,7 +104,7 @@
|
||||
<p>3.1.5. An agreement between the Operator and a third party, where the latter entrusts the Operator with the processing of personal data of the Personal Data Subject or transfers personal data of the Personal Data Subject based on the concluded agreement.</p>
|
||||
</section>
|
||||
|
||||
<section class="info-card">
|
||||
<section class="info-card wide">
|
||||
<div class="card-icon">👥</div>
|
||||
<h2>4. CATEGORIES OF PERSONAL DATA SUBJECTS</h2>
|
||||
|
||||
@@ -122,7 +122,7 @@
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
<section class="info-card">
|
||||
<section class="info-card wide">
|
||||
<div class="card-icon">📝</div>
|
||||
<h2>5. CATEGORIES OF PROCESSED PERSONAL DATA</h2>
|
||||
|
||||
@@ -172,7 +172,7 @@
|
||||
<p>Include conditions for processing, storage, cross-border data transfer, work with publicly available sources, special and biometric data, as well as the procedure for obtaining clarifications in accordance with the legislation of the Russian Federation.</p>
|
||||
</section>
|
||||
|
||||
<section class="info-card">
|
||||
<section class="info-card wide">
|
||||
<div class="card-icon">✅</div>
|
||||
<h2>7. RIGHTS OF THE PERSONAL DATA SUBJECT</h2>
|
||||
|
||||
@@ -189,12 +189,12 @@
|
||||
<li>clarification, blocking, or destruction of data;</li>
|
||||
</ul>
|
||||
|
||||
<p><strong>The PD Subject has the right to withdraw their Consent</strong> and request the deletion of their PD by sending a message to: <a href="mailto:info@lavero.market" class="contact-email">info@lavero.market</a></p>
|
||||
<p><strong>The PD Subject has the right to withdraw their Consent</strong> and request the deletion of their PD by sending a message to: <a href="mailto:info@lavero.store" class="contact-email">info@lavero.store</a></p>
|
||||
|
||||
<p>The Subject also has the right to protect their rights, recover damages, and receive compensation for moral harm.</p>
|
||||
</section>
|
||||
|
||||
<section class="info-card">
|
||||
<section class="info-card wide">
|
||||
<div class="card-icon">📋</div>
|
||||
<h2>8. OPERATOR'S OBLIGATIONS</h2>
|
||||
|
||||
@@ -205,7 +205,7 @@
|
||||
<p>8.3. The Operator bears other obligations established by FZ-152.</p>
|
||||
</section>
|
||||
|
||||
<section class="info-card">
|
||||
<section class="info-card wide">
|
||||
<div class="card-icon">🛡️</div>
|
||||
<h2>9. SECURITY ASSURANCE</h2>
|
||||
|
||||
@@ -222,14 +222,14 @@
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
<section class="info-card">
|
||||
<section class="info-card wide">
|
||||
<div class="card-icon">⚠️</div>
|
||||
<h2>10. LIABILITY</h2>
|
||||
|
||||
<p>10.1. Persons guilty of violating the norms of processing and protection of Personal Data bear liability in accordance with the legislation of the Russian Federation.</p>
|
||||
</section>
|
||||
|
||||
<section class="info-card">
|
||||
<section class="info-card wide">
|
||||
<div class="card-icon">🎯</div>
|
||||
<h2>11. PURPOSES OF PROCESSING</h2>
|
||||
|
||||
@@ -248,7 +248,7 @@
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
<section class="info-card">
|
||||
<section class="info-card wide">
|
||||
<div class="card-icon">🍪</div>
|
||||
<h2>12. AUTOMATICALLY COLLECTED INFORMATION</h2>
|
||||
|
||||
@@ -268,7 +268,7 @@
|
||||
<div class="card-icon">📧</div>
|
||||
<h3>Contact Information</h3>
|
||||
<p>For all questions regarding personal data processing, please contact:</p>
|
||||
<a href="mailto:info@lavero.market" class="contact-email">info@lavero.market</a>
|
||||
<a href="mailto:info@lavero.store" class="contact-email">info@lavero.store</a>
|
||||
<p><a [href]="env.phoneTel">{{ env.phones.support }}</a></p>
|
||||
<p class="note">We will respond within 30 days in accordance with the legislation of the Russian Federation</p>
|
||||
</div>
|
||||
|
||||
@@ -10,15 +10,15 @@
|
||||
<div class="card-icon">📋</div>
|
||||
<h2>1. ОБЩИЕ ПОЛОЖЕНИЯ</h2>
|
||||
|
||||
<p>1.1. Настоящая Политика конфиденциальности (далее — Политика) определяет обязательства Общества с ограниченной ответственностью «ЭЛЕКТРОМОТОРС» (далее - Оператор) по обработке, использованию, хранению и защите персональных данных (далее ПДн, Персональные данные) пользователей (далее - Пользователь).</p>
|
||||
<p>1.1. Настоящая Политика конфиденциальности (далее — Политика) определяет обязательства Общества с ограниченной ответственностью «ЛАВЕРО» (далее - Оператор) по обработке, использованию, хранению и защите персональных данных (далее ПДн, Персональные данные) пользователей (далее - Пользователь).</p>
|
||||
|
||||
<p>1.2. Оператор берет на себя обязательство строго соблюдать права и свободы человека и гражданина при обработке его персональных данных, включая защиту прав на неприкосновенность частной жизни, личную и семейную тайну.</p>
|
||||
|
||||
<p>1.3. Политика обработки персональных данных (далее — Политика) разработана в соответствии с Федеральным законом от 27.07.2006. №152-ФЗ «О персональных данных» (далее — ФЗ-152).</p>
|
||||
|
||||
<p>1.4. Ознакомиться с Политикой возможно на сайте Оператора в информационно-телекоммуникационной сети «Интернет» по адресу: <a href="https://lavero.market">https://lavero.market</a>.</p>
|
||||
<p>1.4. Ознакомиться с Политикой возможно на сайте Оператора в информационно-телекоммуникационной сети «Интернет» по адресу: <a href="https://lavero.store">https://lavero.store</a>.</p>
|
||||
|
||||
<p>1.5. Действует в отношении всех действий, связанных с обработкой персональных данных на сайте <a href="https://lavero.market">https://lavero.market</a> и в информационных системах Оператора.</p>
|
||||
<p>1.5. Действует в отношении всех действий, связанных с обработкой персональных данных на сайте <a href="https://lavero.store">https://lavero.store</a> и в информационных системах Оператора.</p>
|
||||
|
||||
<p>1.6. Пользователь, оформляющий заказ, открывающий личный кабинет или иным образом взаимодействующий с Оператором, выражает согласие на обработку своих персональных данных в соответствии с Политикой и законодательством РФ. Продолжительное использование сайта свидетельствует о согласии с Положениями Политики. Пользователь, не готовый согласиться с условиями, должен воздержаться от использования ресурса.</p>
|
||||
|
||||
@@ -42,7 +42,7 @@
|
||||
|
||||
<p><strong>Обезличивание ПДн</strong> — действия, ведущие к невозможности установления принадлежности данных конкретному лицу без дополнительной информации.</p>
|
||||
|
||||
<p><strong>Интернет-сайт (Сайт)</strong> — автоматизированная информационная система, доступная в сети Интернет по адресу: <a href="https://lavero.market">https://lavero.market</a>.</p>
|
||||
<p><strong>Интернет-сайт (Сайт)</strong> — автоматизированная информационная система, доступная в сети Интернет по адресу: <a href="https://lavero.store">https://lavero.store</a>.</p>
|
||||
|
||||
<p><strong>Обработка ПДн</strong> — любые действия с персональными данными, включая сбор, запись, хранение, обновление, использование, передачу, уничтожение и другие операции.</p>
|
||||
|
||||
@@ -60,9 +60,9 @@
|
||||
|
||||
<p><strong>Конфиденциальность ПДн</strong> — обязанность Оператора защищать данные от распространения без согласия субъекта или законного основания.</p>
|
||||
|
||||
<p><strong>Продавец (Исполнитель)</strong> — лицо, предлагающее товары или услуги на сайте <a href="https://lavero.market">https://lavero.market</a>.</p>
|
||||
<p><strong>Продавец (Исполнитель)</strong> — лицо, предлагающее товары или услуги на сайте <a href="https://lavero.store">https://lavero.store</a>.</p>
|
||||
|
||||
<p><strong>Пользователь</strong> — лицо, посещающее или использующее ресурсы, управляемые Оператором, включая сайт <a href="https://lavero.market">https://lavero.market</a>.</p>
|
||||
<p><strong>Пользователь</strong> — лицо, посещающее или использующее ресурсы, управляемые Оператором, включая сайт <a href="https://lavero.store">https://lavero.store</a>.</p>
|
||||
|
||||
<p><strong>Заказ</strong> — оформленный Пользователем заказ товаров или услуг на сайте.</p>
|
||||
|
||||
@@ -104,7 +104,7 @@
|
||||
<p>3.1.5. Договор между оператором и третьим лицом, где последнее поручает Оператору обработку персональных данных Субъекта Персональных данных или передает на основании заключенного договора персональные данные Субъекта Персональных данных.</p>
|
||||
</section>
|
||||
|
||||
<section class="info-card">
|
||||
<section class="info-card wide">
|
||||
<div class="card-icon">👥</div>
|
||||
<h2>4. КАТЕГОРИИ СУБЪЕКТОВ ПЕРСОНАЛЬНЫХ ДАННЫХ</h2>
|
||||
|
||||
@@ -122,7 +122,7 @@
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
<section class="info-card">
|
||||
<section class="info-card wide">
|
||||
<div class="card-icon">📝</div>
|
||||
<h2>5. КАТЕГОРИИ ОБРАБАТЫВАЕМЫХ ПЕРСОНАЛЬНЫХ ДАННЫХ</h2>
|
||||
|
||||
@@ -172,7 +172,7 @@
|
||||
<p>Включают условия обработки, хранения, трансграничной передачи данных, работы с общедоступными источниками, специальными и биометрическими данными, а также порядок получения разъяснений согласно законодательству РФ.</p>
|
||||
</section>
|
||||
|
||||
<section class="info-card">
|
||||
<section class="info-card wide">
|
||||
<div class="card-icon">✅</div>
|
||||
<h2>7. ПРАВА СУБЪЕКТА ПЕРСОНАЛЬНЫХ ДАННЫХ</h2>
|
||||
|
||||
@@ -189,12 +189,12 @@
|
||||
<li>уточнение, блокирование или уничтожение данных;</li>
|
||||
</ul>
|
||||
|
||||
<p><strong>Субъект ПДн имеет право отозвать свое Согласие</strong> и потребовать удалить свои ПДн, направив сообщение на: <a href="mailto:info@lavero.market" class="contact-email">info@lavero.market</a></p>
|
||||
<p><strong>Субъект ПДн имеет право отозвать свое Согласие</strong> и потребовать удалить свои ПДн, направив сообщение на: <a href="mailto:info@lavero.store" class="contact-email">info@lavero.store</a></p>
|
||||
|
||||
<p>Субъект также имеет право на защиту своих прав, возмещение убытков и компенсацию морального вреда.</p>
|
||||
</section>
|
||||
|
||||
<section class="info-card">
|
||||
<section class="info-card wide">
|
||||
<div class="card-icon">📋</div>
|
||||
<h2>8. ОБЯЗАННОСТИ ОПЕРАТОРА</h2>
|
||||
|
||||
@@ -205,7 +205,7 @@
|
||||
<p>8.3. Оператор несет иные обязанности, установленные ФЗ-152.</p>
|
||||
</section>
|
||||
|
||||
<section class="info-card">
|
||||
<section class="info-card wide">
|
||||
<div class="card-icon">🛡️</div>
|
||||
<h2>9. ОБЕСПЕЧЕНИЕ БЕЗОПАСНОСТИ</h2>
|
||||
|
||||
@@ -222,14 +222,14 @@
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
<section class="info-card">
|
||||
<section class="info-card wide">
|
||||
<div class="card-icon">⚠️</div>
|
||||
<h2>10. ОТВЕТСТВЕННОСТЬ</h2>
|
||||
|
||||
<p>10.1. Лица, виновные в нарушении норм обработки и защиты Персональных данных, несут ответственность согласно законодательству РФ.</p>
|
||||
</section>
|
||||
|
||||
<section class="info-card">
|
||||
<section class="info-card wide">
|
||||
<div class="card-icon">🎯</div>
|
||||
<h2>11. ЦЕЛИ ОБРАБОТКИ</h2>
|
||||
|
||||
@@ -248,7 +248,7 @@
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
<section class="info-card">
|
||||
<section class="info-card wide">
|
||||
<div class="card-icon">🍪</div>
|
||||
<h2>12. АВТОМАТИЧЕСКИ СОБИРАЕМАЯ ИНФОРМАЦИЯ</h2>
|
||||
|
||||
@@ -268,7 +268,7 @@
|
||||
<div class="card-icon">📧</div>
|
||||
<h3>Контакты для связи</h3>
|
||||
<p>По всем вопросам обработки персональных данных обращайтесь:</p>
|
||||
<a href="mailto:info@lavero.market" class="contact-email">info@lavero.market</a>
|
||||
<a href="mailto:info@lavero.store" class="contact-email">info@lavero.store</a>
|
||||
<p><a [href]="env.phoneTel">{{ env.phones.support }}</a></p>
|
||||
<p class="note">Мы ответим в течение 30 дней согласно законодательству РФ</p>
|
||||
</div>
|
||||
|
||||
@@ -10,11 +10,11 @@
|
||||
<div class="card-icon">📚</div>
|
||||
<h2>Key Terms</h2>
|
||||
<ul class="compact-list">
|
||||
<li><strong>Platform</strong> — the software and technical complex lavero.market. We provide the infrastructure for trading without being sellers ourselves.</li>
|
||||
<li><strong>Platform</strong> — the software and technical complex lavero.store. We provide the infrastructure for trading without being sellers ourselves.</li>
|
||||
<li><strong>Client</strong> — an individual using the website after registration and acceptance of these terms.</li>
|
||||
<li><strong>Account</strong> — the client's individual area with authorization via email or phone.</li>
|
||||
<li><strong>Customer</strong> — a client who has made a purchase through the platform.</li>
|
||||
<li><strong>Operator</strong> — the company LLC "ELEKTROMOTORS", TIN 9909687443.</li>
|
||||
<li><strong>Operator</strong> — the company LLC "LAVERO", TIN 03590442.</li>
|
||||
<li><strong>Supplier</strong> — individuals, legal entities, and sole proprietors selling goods through the platform.</li>
|
||||
<li><strong>Products</strong> — physical, electronic goods and services in the catalog.</li>
|
||||
<li><strong>Electronic Products</strong> — software, courses, subscriptions, media content in digital form.</li>
|
||||
@@ -36,12 +36,16 @@
|
||||
<p>1.9. Promotional campaigns may have special rules.</p>
|
||||
</section>
|
||||
|
||||
<section class="info-card">
|
||||
<section class="info-card wide">
|
||||
<div class="card-icon">🎯</div>
|
||||
<h2>2. Subject of the Agreement</h2>
|
||||
<p>2.1. The purpose is to provide users with the ability to purchase goods and services presented on the resource.</p>
|
||||
<p>2.2. The agreement regulates the use of the website and provided features.</p>
|
||||
<p>2.3. It applies to all types of goods, services, and products on the website.</p>
|
||||
<p>2.4. The Marketplace is an agent acting under agency agreements with Sellers (Third Parties). The Marketplace does not acquire ownership rights to the Goods/Services sold through the Platform and only provides the technical ability to conclude a transaction between the Seller and the Buyer.</p>
|
||||
<p>2.5. The Seller is an independent business entity and bears full responsibility for the quality, safety, conformity of the Goods/Services to the stated characteristics, and fulfillment of obligations to the Buyer (warranties, returns, claims).</p>
|
||||
<p>2.6. The Marketplace is not a party to the sale and purchase agreement between the Seller and the Buyer. All claims regarding the Goods/Services are submitted by the Buyer directly to the Seller.</p>
|
||||
<p>2.7. The Marketplace's agency remuneration is withheld from the amount paid by the Buyer and does not increase the price for the Buyer beyond the price set by the Seller.</p>
|
||||
</section>
|
||||
|
||||
<section class="info-card wide">
|
||||
@@ -57,13 +61,13 @@
|
||||
<p><strong>3.8. Applicable laws:</strong> Governed by Federal Law "On Consumer Rights Protection" No. 2300-1 and the Civil Code of the Russian Federation.</p>
|
||||
</section>
|
||||
|
||||
<section class="info-card">
|
||||
<section class="info-card wide">
|
||||
<div class="card-icon">📱</div>
|
||||
<h2>4. Registration and Personal Account</h2>
|
||||
<p><strong>4.1. Procedure:</strong> Registration is not required for ordering but provides access to the personal account.</p>
|
||||
<p><strong>4.2. Obligations:</strong> Provide accurate information and keep it up to date.</p>
|
||||
<p><strong>4.3. Identification:</strong> Actions performed using login and password are considered user actions.</p>
|
||||
<p><strong>4.4. Confidentiality:</strong> Keep login and password confidential. If a breach is suspected, notify <a href="mailto:info@lavero.market">info@lavero.market</a>.</p>
|
||||
<p><strong>4.4. Confidentiality:</strong> Keep login and password confidential. If a breach is suspected, notify <a href="mailto:info@lavero.store">info@lavero.store</a>.</p>
|
||||
<p><strong>4.5. Data verification:</strong> The owner may request verification of information.</p>
|
||||
<p><strong>4.6. Session termination:</strong> Log out of the personal account independently ("Log Out").</p>
|
||||
</section>
|
||||
@@ -111,10 +115,10 @@
|
||||
<li>Violating the rights of other users</li>
|
||||
<li>Behavior that violates Russian legislation</li>
|
||||
</ul>
|
||||
<p><strong>Rights:</strong> Opt out of advertising messages through the website or by writing to <a href="mailto:info@lavero.market">info@lavero.market</a>.</p>
|
||||
<p><strong>Rights:</strong> Opt out of advertising messages through the website or by writing to <a href="mailto:info@lavero.store">info@lavero.store</a>.</p>
|
||||
</section>
|
||||
|
||||
<section class="info-card">
|
||||
<section class="info-card wide">
|
||||
<div class="card-icon">©</div>
|
||||
<h2>7. Exclusive Rights to Content</h2>
|
||||
<p><strong>7.1. Intellectual property:</strong> All content (design, texts, graphics, video, software, databases) is subject to the copyright of the owner and rights holders.</p>
|
||||
@@ -122,7 +126,7 @@
|
||||
<p><strong>7.3. Personal use:</strong> For personal non-commercial use while preserving copyright notices.</p>
|
||||
</section>
|
||||
|
||||
<section class="info-card">
|
||||
<section class="info-card wide">
|
||||
<div class="card-icon">🔗</div>
|
||||
<h2>8. Third-Party Websites and Content</h2>
|
||||
<p><strong>8.1. External links:</strong> The website may contain links to third-party resources. The website owner is not responsible for their content.</p>
|
||||
@@ -218,14 +222,14 @@
|
||||
<p><strong>13.7. Return method:</strong> The return method is specified in the application.</p>
|
||||
</section>
|
||||
|
||||
<section class="info-card">
|
||||
<section class="info-card wide">
|
||||
<div class="card-icon">⏳</div>
|
||||
<h2>14. Term of the Agreement</h2>
|
||||
<p><strong>14.1. Commencement and termination:</strong> The agreement is active from the moment of acceptance by the user until revocation of acceptance.</p>
|
||||
<p><strong>14.2. Right of revocation:</strong> The owner may revoke the offer pursuant to Art. 436 of the Civil Code of the Russian Federation.</p>
|
||||
</section>
|
||||
|
||||
<section class="info-card">
|
||||
<section class="info-card wide">
|
||||
<div class="card-icon">⚡</div>
|
||||
<h2>15. Dispute Resolution Procedure</h2>
|
||||
<p><strong>15.1. Voluntary settlement:</strong> Mandatory pre-trial dispute resolution procedure.</p>
|
||||
@@ -247,16 +251,16 @@
|
||||
<p><strong>16.3. Legislation:</strong> Issues are resolved under the legislation of Armenia.</p>
|
||||
<p><strong>16.4. The term "Legislation":</strong> Refers to the laws of Armenia.</p>
|
||||
<p><strong>16.5. Free services:</strong> Do not imply the application of consumer protection regulations.</p>
|
||||
<p><strong>16.6. Absence of relationships:</strong> Do not establish agency, partnership, or employment relationships.</p>
|
||||
<p><strong>16.6. Absence of relationships:</strong> Except for the agency model under clause 2.4, the terms do not establish partnership, joint venture, or employment relationships.</p>
|
||||
<p><strong>16.7. Invalidity of clauses:</strong> Does not affect the legal force of the remaining provisions.</p>
|
||||
<p><strong>16.8. Response to violations:</strong> Non-intervention does not prevent subsequent protective measures.</p>
|
||||
</section>
|
||||
|
||||
<section class="info-card">
|
||||
<section class="info-card wide">
|
||||
<div class="card-icon">📞</div>
|
||||
<h2>Contact Us</h2>
|
||||
<p>Questions about the agreement:</p>
|
||||
<a href="mailto:info@lavero.market" class="contact-email">info@lavero.market</a>
|
||||
<a href="mailto:info@lavero.store" class="contact-email">info@lavero.store</a>
|
||||
<p><a [href]="env.phoneTel">{{ env.phones.support }}</a></p>
|
||||
<p class="support-note">We are always happy to help</p>
|
||||
</section>
|
||||
|
||||
@@ -10,11 +10,11 @@
|
||||
<div class="card-icon">📚</div>
|
||||
<h2>Հիմնական հասկացություններ</h2>
|
||||
<ul class="compact-list">
|
||||
<li><strong>Հարթակ</strong> — lavero.market ծրագրային-տեխնիկական համակարգ։ Մենք տրամադրում ենք ենթակառուցվածք առևտրի համար՝ առանց վաճառող հանդիսանալու։</li>
|
||||
<li><strong>Հարթակ</strong> — lavero.store ծրագրային-տեխնիկական համակարգ։ Մենք տրամադրում ենք ենթակառուցվածք առևտրի համար՝ առանց վաճառող հանդիսանալու։</li>
|
||||
<li><strong>Հաճախորդ</strong> — ֆիզիկական անձ՝ գրանցվելուց և սույն պայմաններն ընդունելուց հետո օգտվող կայքը։</li>
|
||||
<li><strong>Հաշիվ</strong> — հաճախորդի անհատական գոտի՝ էլ. ֆոստի կամ հեռախոսի միճոցով մուտք գործելով։</li>
|
||||
<li><strong>Պատվիրատու</strong> — հաճախորդ՝ հարթակի միճոցով գնում կատարած։</li>
|
||||
<li><strong>Օպերատոր</strong> — «ԷԼԵԿՏՐՎՍՏՎՐՍ» ՍՊԸ՝ ՀՀՀ 9909687443։</li>
|
||||
<li><strong>Օպերատոր</strong> — «ԷԼԵԿՏՐՎՍՏՎՐՍ» ՍՊԸ՝ ՀՀՀ 03590442։</li>
|
||||
<li><strong>Մատակարար</strong> — ֆիզ./իրավաբանական անձինք և անհատ ձեռներեցներ՝ հարթակի միճոցով ապրանքներ վաճառող։</li>
|
||||
<li><strong>Ապրանքներ</strong> — ֆիզիկական՝ էլեկտրոնային ապրանքներ և ծառայություններ կատալոգում։</li>
|
||||
<li><strong>Էլեկտրոնային ապրանքներ</strong> — ծրագրեր՝ դասընթացներ՝ բաժանորդագրություններ՝ մեդիաբովանդակություն թվային տեսքով։</li>
|
||||
@@ -36,12 +36,16 @@
|
||||
<p>1.9. Գովազդային ակցիաները կարող են ունենալ հատուկ կանոններ։</p>
|
||||
</section>
|
||||
|
||||
<section class="info-card">
|
||||
<section class="info-card wide">
|
||||
<div class="card-icon">🎯</div>
|
||||
<h2>2. Համաձայնագրի առարկան</h2>
|
||||
<p>2.1. Նպատակն է օգտագործողներին հնարավորություն տալ ռեսուրսում ներկայացված ապրանքներ և ծառայություններ ձեռք բերելու։</p>
|
||||
<p>2.2. Համաձայնագիրը կարգավորում է կայքի օգտագործման և տրամադրվող գործառույթների կարգը։</p>
|
||||
<p>2.3. Գործում է կայքում ներկայացված ապրանքների՝ ծառայությունների և պրոդուկտների բոլոր տեսակների նկատմամբ։</p>
|
||||
<p>2.4. Մարկետփլեյսը հանդիսանում է գործակալ, որը գործում է Վաճառողների (Երրորդ անձանց) հետ կնքված գործակալության պայմանագրի հիման վրա։ Մարկետփլեյսը չի ձեռք բերում Հարթակի միջոցով իրացվող Ապրանքների/Ծառայությունների նկատմամբ սեփականության իրավունք, այլ միայն ապահովում է Վաճառողի և Գնորդի միջև գործարք կնքելու տեխնիկական հնարավորությունը։</p>
|
||||
<p>2.5. Վաճառողը հանդիսանում է ինքնուրույն տնտեսվարող սուբյեկտ և կրում է ամբողջական պատասխանատվություն Ապրանքի/Ծառայության որակի, անվտանգության, հայտարարված բնութագրերին համապատասխանության, ինչպես նաև Գնորդի նկատմամբ պարտավորությունների կատարման համար (երաշխիքներ, վերադարձ, պահանջներ)։</p>
|
||||
<p>2.6. Մարկետփլեյսը չի հանդիսանում Վաճառողի և Գնորդի միջև առուվաճառքի պայմանագրի կողմ։ Ապրանքի/Ծառայության վերաբերյալ բոլոր պահանջները Գնորդը ներկայացնում է անմիջապես Վաճառողին։</p>
|
||||
<p>2.7. Մարկետփլեյսի գործակալական վարձատրությունը պահվում է Գնորդի վճարած գումարից և չի ավելացնում Գնորդի համար գինը Վաճառողի սահմանած գնից ավել։</p>
|
||||
</section>
|
||||
|
||||
<section class="info-card wide">
|
||||
@@ -57,13 +61,13 @@
|
||||
<p><strong>3.8. Կիրառվող օրենքներ՝</strong> Կարգավորվում են ՌԴ «Սպառողների իրավունքների պաշտպանության մասին» թիվ 2300-1 և ՌԴ քաղաքացիական օրենսգիրքով։</p>
|
||||
</section>
|
||||
|
||||
<section class="info-card">
|
||||
<section class="info-card wide">
|
||||
<div class="card-icon">📱</div>
|
||||
<h2>4. Գրանցում և անձնական հաշիվ</h2>
|
||||
<p><strong>4.1. Ըթացակարգ՝</strong> Գրանցումը պարտադիր չէ պատվերի համար՝ սակայն հնարավորություն է տալիս անձնական հաշիվ մուտք գործելու։</p>
|
||||
<p><strong>4.2. Պարտավորություններ՝</strong> Տրամադրել ճիշտ տեղեկատվություն և թարմացնել այն։</p>
|
||||
<p><strong>4.3. Նույնականացում՝</strong> Մուտքանունի և գաղտնաբառի օգտագործմամբ կատարված գործողությունները համարվում են օգտագործողի գործողություններ։</p>
|
||||
<p><strong>4.4. Գաղտնիություն՝</strong> Պահել մուտքանունը և գաղտնաբառը գաղտնի։ Կասկածի խախտման դեպքում — հաղորդել <a href="mailto:info@lavero.market">info@lavero.market</a>։</p>
|
||||
<p><strong>4.4. Գաղտնիություն՝</strong> Պահել մուտքանունը և գաղտնաբառը գաղտնի։ Կասկածի խախտման դեպքում — հաղորդել <a href="mailto:info@lavero.store">info@lavero.store</a>։</p>
|
||||
<p><strong>4.5. Տվյալների հաստատում՝</strong> Սեփականատերը կարող է պահանջել տեղեկատվության հաստատում։</p>
|
||||
<p><strong>4.6. Նիստի ավարտ՝</strong> Ինքնուրույն ավարտել աշխատանքը անձնական հաշվում («Ելք»)։</p>
|
||||
</section>
|
||||
@@ -111,10 +115,10 @@
|
||||
<li>Այլ օգտագործողների իրավունքների խախտում</li>
|
||||
<li>Ռդ օրենսդրությունը խախտող վարքագիծ</li>
|
||||
</ul>
|
||||
<p><strong>Իրավունքներ՝</strong> Հրաժարվել գովազդային հաղորդագրություններից կայքի միճոցով կամ նամակով <a href="mailto:info@lavero.market">info@lavero.market</a>։</p>
|
||||
<p><strong>Իրավունքներ՝</strong> Հրաժարվել գովազդային հաղորդագրություններից կայքի միճոցով կամ նամակով <a href="mailto:info@lavero.store">info@lavero.store</a>։</p>
|
||||
</section>
|
||||
|
||||
<section class="info-card">
|
||||
<section class="info-card wide">
|
||||
<div class="card-icon">©</div>
|
||||
<h2>7. Բովանդակության բացառիկ իրավունքներ</h2>
|
||||
<p><strong>7.1. Մտավոր սեփականություն՝</strong> Բոլոր բովանդակությունը (դիզայն՝ տեքստեր՝ գրաֆիկա՝ տեսանյութ՝ ծրագրեր՝ տվյալների բազաներ) սեփականատիրոջ և իրավատերերի հեղինակային իրավունքների առարկան է։</p>
|
||||
@@ -122,7 +126,7 @@
|
||||
<p><strong>7.3. Անձնական օգտագործում՝</strong> Անձնական ոչ առևտրային օգտագործման համար՝ հեղինակային իրավունքների նիշերի պահպանմամբ։</p>
|
||||
</section>
|
||||
|
||||
<section class="info-card">
|
||||
<section class="info-card wide">
|
||||
<div class="card-icon">🔗</div>
|
||||
<h2>8. Երրորդ կողմերի կայքեր և բովանդակություն</h2>
|
||||
<p><strong>8.1. Արտաքին հղումներ՝</strong> Կայքը կարող է պարունակել երրորդ կողմի ռեսուրսների հղումներ։ Կայքի սեփականատերը պատասխանատու չէ դրանց բովանդակության համար։</p>
|
||||
@@ -218,14 +222,14 @@
|
||||
<p><strong>13.7. Վերադարձի մեխանիզմ՝</strong> Վերադարձի եղանակը նշվում է դիմումում։</p>
|
||||
</section>
|
||||
|
||||
<section class="info-card">
|
||||
<section class="info-card wide">
|
||||
<div class="card-icon">⌛</div>
|
||||
<h2>14. Համաձայնագրի գործողության ժամկետը</h2>
|
||||
<p><strong>14.1. Սկիզբ և դադարեցում՝</strong> Համաձայնագիրը գործում է օգտագործողի ընդունման պահից մինչև ընդունման հետկանչում։</p>
|
||||
<p><strong>14.2. Հետկանչման իրավունք՝</strong> Սեփականատերը կարող է օֆերտան հետ կանչել ՌԴ 436 հոդվածի համաձայն։</p>
|
||||
</section>
|
||||
|
||||
<section class="info-card">
|
||||
<section class="info-card wide">
|
||||
<div class="card-icon">⚡</div>
|
||||
<h2>15. Վեճերի լուծման կարգը</h2>
|
||||
<p><strong>15.1. Կամավոր կարգավորում՝</strong> Պարտադիր նախադատական վեճերի լուծման ընթացակարգ։</p>
|
||||
@@ -247,16 +251,16 @@
|
||||
<p><strong>16.3. Օրենսդրություն՝</strong> Հարցերը լուծվում են Հայաստանի օրենսդրությամբ։</p>
|
||||
<p><strong>16.4. «Օրենսդրություն» տերմին՝</strong> Նշանակում է Հայաստանի օրենքները։</p>
|
||||
<p><strong>16.5. Անվճար ծառայություններ՝</strong> Չեն ենթադրում սպառողների իրավունքների պաշտպանության նորմերի կիրառում։</p>
|
||||
<p><strong>16.6. Հարաբերությունների բացակայություն՝</strong> Չեն հաստատում գործակալային՝ գործընկերային կամ աշխատանքային հարաբերություններ։</p>
|
||||
<p><strong>16.6. Հարաբերությունների բացակայություն՝</strong> Բացի 2.4 կետով նախատեսված գործակալական մոդելից՝ պայմանները չեն հաստատում գործընկերային, համատեղ ձեռնարկության կամ աշխատանքային հարաբերություններ։</p>
|
||||
<p><strong>16.7. Կետերի անվավերություն՝</strong> Չի ազդում մնացած դրույթների իրավական ուժի վրա։</p>
|
||||
<p><strong>16.8. Խախտումների նկատմամբ արձագանք՝</strong> Անգործունեությունը չի խանգարում հետագա պաշտպանության միջոցներին։</p>
|
||||
</section>
|
||||
|
||||
<section class="info-card">
|
||||
<section class="info-card wide">
|
||||
<div class="card-icon">📞</div>
|
||||
<h2>Կապ</h2>
|
||||
<p>Համաձայնագրի վերաբերյալ հարցեր՝</p>
|
||||
<a href="mailto:info@lavero.market" class="contact-email">info@lavero.market</a>
|
||||
<a href="mailto:info@lavero.store" class="contact-email">info@lavero.store</a>
|
||||
<p><a [href]="env.phoneTel">{{ env.phones.support }}</a></p>
|
||||
<p class="support-note">Մենք միշտ պատրաստ ենք օգնելու</p>
|
||||
</section>
|
||||
|
||||
@@ -10,11 +10,11 @@
|
||||
<div class="card-icon">📚</div>
|
||||
<h2>Ключевые термины</h2>
|
||||
<ul class="compact-list">
|
||||
<li><strong>Платформа</strong> — программно-технический комплекс lavero.market. Мы предоставляем инфраструктуру для торговли, не являясь продавцами.</li>
|
||||
<li><strong>Платформа</strong> — программно-технический комплекс lavero.store. Мы предоставляем инфраструктуру для торговли, не являясь продавцами.</li>
|
||||
<li><strong>Клиент</strong> — физическое лицо, использующее сайт после регистрации и принятия данных условий.</li>
|
||||
<li><strong>Аккаунт</strong> — индивидуальная зона клиента с авторизацией через email или телефон.</li>
|
||||
<li><strong>Заказчик</strong> — клиент, совершивший покупку через платформу.</li>
|
||||
<li><strong>Оператор</strong> — компания ООО «ЭЛЕКТРОМОТОРС», ИНН 9909687443.</li>
|
||||
<li><strong>Оператор</strong> — компания ООО «ЛАВЕРО», ИНН 03590442.</li>
|
||||
<li><strong>Поставщик</strong> — физ./юрлица и ИП, реализующие товары через платформу.</li>
|
||||
<li><strong>Продукция</strong> — физические, электронные товары и сервисы в каталоге.</li>
|
||||
<li><strong>Электронная продукция</strong> — софт, курсы, подписки, медиаконтент в цифровом виде.</li>
|
||||
@@ -36,12 +36,16 @@
|
||||
<p>1.9. Промо-кампании могут иметь специальные правила.</p>
|
||||
</section>
|
||||
|
||||
<section class="info-card">
|
||||
<section class="info-card wide">
|
||||
<div class="card-icon">🎯</div>
|
||||
<h2>2. Предмет соглашения</h2>
|
||||
<p>2.1. Целью является предоставление пользователям возможности покупать товары и услуги, представленные на ресурсе.</p>
|
||||
<p>2.2. Соглашение регулирует порядок использования сайта и предоставляемых функций.</p>
|
||||
<p>2.3. Действие распространяется на все типы товаров, услуг и продуктов на сайте.</p>
|
||||
<p>2.4. Маркетплейс является агентом, действующим на основании договора агентирования с Продавцами (Третьими лицами). Маркетплейс не приобретает право собственности на Товары/Услуги, реализуемые через Платформу, а лишь обеспечивает техническую возможность заключения сделки между Продавцом и Покупателем.</p>
|
||||
<p>2.5. Продавец является самостоятельным хозяйствующим субъектом и несёт полную ответственность за качество, безопасность, соответствие Товара/Услуги заявленным характеристикам, а также за исполнение обязательств перед Покупателем (гарантии, возврат, претензии).</p>
|
||||
<p>2.6. Маркетплейс не выступает стороной договора купли-продажи между Продавцом и Покупателем. Все претензии по Товару/Услуге Покупатель предъявляет непосредственно Продавцу.</p>
|
||||
<p>2.7. Агентское вознаграждение Маркетплейса удерживается из суммы, уплаченной Покупателем, и не увеличивает цену для Покупателя сверх установленной Продавцом.</p>
|
||||
</section>
|
||||
|
||||
<section class="info-card wide">
|
||||
@@ -57,13 +61,13 @@
|
||||
<p><strong>3.8. Применение законов:</strong> Регулируются ФЗ "О защите прав потребителей" №2300-1 и ГК РФ.</p>
|
||||
</section>
|
||||
|
||||
<section class="info-card">
|
||||
<section class="info-card wide">
|
||||
<div class="card-icon">📱</div>
|
||||
<h2>4. Регистрация и личный кабинет</h2>
|
||||
<p><strong>4.1. Процедура:</strong> Регистрация необязательна для заказа, но открывает доступ к личному кабинету.</p>
|
||||
<p><strong>4.2. Обязанности:</strong> Предоставлять точную информацию и поддерживать её актуальность.</p>
|
||||
<p><strong>4.3. Идентификация:</strong> Действия с использованием логина и пароля считаются действиями пользователя.</p>
|
||||
<p><strong>4.4. Конфиденциальность:</strong> Хранить логин и пароль в тайне. При подозрении на нарушение — сообщить на <a href="mailto:info@lavero.market">info@lavero.market</a>.</p>
|
||||
<p><strong>4.4. Конфиденциальность:</strong> Хранить логин и пароль в тайне. При подозрении на нарушение — сообщить на <a href="mailto:info@lavero.store">info@lavero.store</a>.</p>
|
||||
<p><strong>4.5. Подтверждение данных:</strong> Владелец может запросить подтверждение информации.</p>
|
||||
<p><strong>4.6. Завершение сеанса:</strong> Самостоятельно завершать работу в личном кабинете («Выход»).</p>
|
||||
</section>
|
||||
@@ -111,10 +115,10 @@
|
||||
<li>Нарушение прав других пользователей</li>
|
||||
<li>Поведение, нарушающее российское законодательство</li>
|
||||
</ul>
|
||||
<p><strong>Права:</strong> Отказаться от рекламных сообщений через сайт или письмом на <a href="mailto:info@lavero.market">info@lavero.market</a>.</p>
|
||||
<p><strong>Права:</strong> Отказаться от рекламных сообщений через сайт или письмом на <a href="mailto:info@lavero.store">info@lavero.store</a>.</p>
|
||||
</section>
|
||||
|
||||
<section class="info-card">
|
||||
<section class="info-card wide">
|
||||
<div class="card-icon">©</div>
|
||||
<h2>7. Исключительные права на контент</h2>
|
||||
<p><strong>7.1. Интеллектуальная собственность:</strong> Весь контент (дизайн, тексты, графика, видео, программы, базы данных) является объектом авторских прав владельца и правообладателей.</p>
|
||||
@@ -122,7 +126,7 @@
|
||||
<p><strong>7.3. Личное использование:</strong> Для личного некоммерческого использования при сохранении обозначений авторских прав.</p>
|
||||
</section>
|
||||
|
||||
<section class="info-card">
|
||||
<section class="info-card wide">
|
||||
<div class="card-icon">🔗</div>
|
||||
<h2>8. Сайты и контент третьих лиц</h2>
|
||||
<p><strong>8.1. Внешние ссылки:</strong> Сайт может содержать ссылки на сторонние ресурсы. Ответственность за их содержание не относится к владельцу сайта.</p>
|
||||
@@ -218,14 +222,14 @@
|
||||
<p><strong>13.7. Механизм возврата:</strong> Способ возврата указывается в заявлении.</p>
|
||||
</section>
|
||||
|
||||
<section class="info-card">
|
||||
<section class="info-card wide">
|
||||
<div class="card-icon">⏳</div>
|
||||
<h2>14. Срок действия соглашения</h2>
|
||||
<p><strong>14.1. Начало и прекращение:</strong> Соглашение активно с момента принятия пользователем до отзыва акцепта.</p>
|
||||
<p><strong>14.2. Право отзыва:</strong> Владелец может отозвать оферту согласно ст. 436 ГК РФ.</p>
|
||||
</section>
|
||||
|
||||
<section class="info-card">
|
||||
<section class="info-card wide">
|
||||
<div class="card-icon">⚡</div>
|
||||
<h2>15. Порядок разрешения споров</h2>
|
||||
<p><strong>15.1. Добровольное урегулирование:</strong> Обязательный досудебный порядок рассмотрения споров.</p>
|
||||
@@ -247,16 +251,16 @@
|
||||
<p><strong>16.3. Законодательство:</strong> Вопросы разрешаются по законодательству Армении.</p>
|
||||
<p><strong>16.4. Термин "Законодательство":</strong> Подразумевает законы Армении.</p>
|
||||
<p><strong>16.5. Бесплатные услуги:</strong> Не предполагают применение норм о защите прав потребителей.</p>
|
||||
<p><strong>16.6. Отсутствие отношений:</strong> Не устанавливают агентских связей, партнёрства или трудовых отношений.</p>
|
||||
<p><strong>16.6. Отсутствие отношений:</strong> Кроме агентской модели по п. 2.4, условия не устанавливают партнёрства, совместного предприятия или трудовых отношений.</p>
|
||||
<p><strong>16.7. Недействительность пунктов:</strong> Не влияет на законную силу остальных положений.</p>
|
||||
<p><strong>16.8. Реакция на нарушения:</strong> Невмешательство не препятствует последующим мерам защиты.</p>
|
||||
</section>
|
||||
|
||||
<section class="info-card">
|
||||
<section class="info-card wide">
|
||||
<div class="card-icon">📞</div>
|
||||
<h2>Контакты</h2>
|
||||
<p>Вопросы по соглашению:</p>
|
||||
<a href="mailto:info@lavero.market" class="contact-email">info@lavero.market</a>
|
||||
<a href="mailto:info@lavero.store" class="contact-email">info@lavero.store</a>
|
||||
<p><a [href]="env.phoneTel">{{ env.phones.support }}</a></p>
|
||||
<p class="support-note">Мы всегда готовы помочь</p>
|
||||
</section>
|
||||
|
||||
@@ -9,14 +9,14 @@
|
||||
<section class="info-card wide">
|
||||
<div class="card-icon">📋</div>
|
||||
<h2>1. General Provisions</h2>
|
||||
<p>1.1. This policy describes the procedure for returning products and canceling services purchased on the Lavero Market platform.</p>
|
||||
<p>1.1. This policy describes the procedure for returning products and canceling services purchased on the Lavero Store platform.</p>
|
||||
<p>1.2. Our platform acts as an information intermediary, therefore all return disputes are resolved directly between the customer and the supplier in accordance with the laws of the Republic of Armenia.</p>
|
||||
<p>1.3. For quality products, Art. 26.1 of the Consumer Protection Law applies.</p>
|
||||
<p>1.4. For products with defects, Art. 18–24 of the same law apply.</p>
|
||||
<p>1.5. Digital products are returned under special rules prescribed by legislation.</p>
|
||||
</section>
|
||||
|
||||
<section class="info-card">
|
||||
<section class="info-card wide">
|
||||
<div class="card-icon">📅</div>
|
||||
<h2>2. Time Frames</h2>
|
||||
<p><strong>2.1. Quality products:</strong></p>
|
||||
@@ -112,7 +112,7 @@
|
||||
<p>Our platform is always ready to help resolve disputes.</p>
|
||||
</section>
|
||||
|
||||
<section class="info-card">
|
||||
<section class="info-card wide">
|
||||
<div class="card-icon">💰</div>
|
||||
<h2>6. Payment Refund</h2>
|
||||
<p>Funds are refunded to the same payment method:</p>
|
||||
@@ -134,14 +134,14 @@
|
||||
<p>The customer has the right to claim compensation for defective products and shipping costs.</p>
|
||||
</section>
|
||||
|
||||
<section class="info-card">
|
||||
<section class="info-card wide">
|
||||
<div class="card-icon">🔄</div>
|
||||
<h2>7. Product Exchange</h2>
|
||||
<p>If a non-defective product does not match in dimensions, size, or specifications, the customer may exchange it with the supplier for a suitable option.</p>
|
||||
<p>If the desired model is unavailable, the customer has the right to cancel the order and receive a refund.</p>
|
||||
</section>
|
||||
|
||||
<section class="info-card">
|
||||
<section class="info-card wide">
|
||||
<div class="card-icon">🛡️</div>
|
||||
<h2>8. Warranty Service</h2>
|
||||
<p>Warranty information is displayed on the product page or available from the seller.</p>
|
||||
@@ -149,7 +149,7 @@
|
||||
<p>Warranty service does not cover physical damage, improper use, or unauthorized modifications.</p>
|
||||
</section>
|
||||
|
||||
<section class="info-card">
|
||||
<section class="info-card wide">
|
||||
<div class="card-icon">⚖️</div>
|
||||
<h2>9. Responsibilities of Parties</h2>
|
||||
<p>The supplier is responsible for product quality and timely refunds.</p>
|
||||
@@ -163,7 +163,7 @@
|
||||
<p>Return questions can be directed to the seller — contact details are provided in your order.</p>
|
||||
<p>To resolve disputes through the platform administration:</p>
|
||||
<ul class="compact-list">
|
||||
<li><strong>E-mail:</strong> <a href="mailto:info@lavero.market" class="contact-email">info@lavero.market</a></li>
|
||||
<li><strong>E-mail:</strong> <a href="mailto:info@lavero.store" class="contact-email">info@lavero.store</a></li>
|
||||
<li><strong>Phone:</strong> <a [href]="env.phoneTel">{{ env.phones.support }}</a></li>
|
||||
<li><strong>Subject:</strong> "Dispute with seller — Order #"</li>
|
||||
<li><strong>Attach:</strong> correspondence, photos, payment receipt</li>
|
||||
|
||||
@@ -9,14 +9,14 @@
|
||||
<section class="info-card wide">
|
||||
<div class="card-icon">📋</div>
|
||||
<h2>1. Ընդհանուր դրույթներ</h2>
|
||||
<p>1.1. Սույն քաղաքականությունը նկարագրում է ապրանքների վերադարձի և Lavero Market հարթակում գնված ծառայություններից հրաժարվելու կարգը։</p>
|
||||
<p>1.1. Սույն քաղաքականությունը նկարագրում է ապրանքների վերադարձի և Lavero Store հարթակում գնված ծառայություններից հրաժարվելու կարգը։</p>
|
||||
<p>1.2. Մեր հարթակը գործում է որպես տեղեկատվական միջնորդ, ուստի վերադարձի վերաբերյալ բոլոր վեճերը լուծվում են անմիջականորեն գնորդի և մատակարարի միջև ՀՀ օրենսդրության համաձայն։</p>
|
||||
<p>1.3. Որակյալ ապրանքների համար կիրառվում է սպառողների պաշտպանության օրենքի հոդված 26.1-ը։</p>
|
||||
<p>1.4. Թերություններ ունեցող ապրանքների համար գործում են նույն օրենքի 18–24 հոդվածները։</p>
|
||||
<p>1.5. Թվային ապրանքները վերադարձվում են օրենսդրությամբ նախատեսված հատուկ կանոններով։</p>
|
||||
</section>
|
||||
|
||||
<section class="info-card">
|
||||
<section class="info-card wide">
|
||||
<div class="card-icon">📅</div>
|
||||
<h2>2. Ժամանակային սահմաններ</h2>
|
||||
<p><strong>2.1. Որակյալ ապրանքներ՝</strong></p>
|
||||
@@ -112,7 +112,7 @@
|
||||
<p>Մեր հարթակը միշտ պատրաստ է օգնել վիճելի իրավիճակների կարգավորման հարցում։</p>
|
||||
</section>
|
||||
|
||||
<section class="info-card">
|
||||
<section class="info-card wide">
|
||||
<div class="card-icon">💰</div>
|
||||
<h2>6. Վճարման փոխհատուցում</h2>
|
||||
<p>Գումարը վերադարձվում է նույն վճարման եղանակով՝</p>
|
||||
@@ -134,14 +134,14 @@
|
||||
<p>Գնորդը իրավունք ունի պահանջել փոխհատուցում անորակ ապրանքների և առաքման ծախսերի համար։</p>
|
||||
</section>
|
||||
|
||||
<section class="info-card">
|
||||
<section class="info-card wide">
|
||||
<div class="card-icon">🔄</div>
|
||||
<h2>7. Ապրանքի փոխանակում</h2>
|
||||
<p>Եթե որակյալ ապրանքը չի համապատասխանում չափսերով, չափորոշներով կամ հատկանիշներով, գնորդը կարող է այն փոխանակել մատակարարի մոտ համապատասխան տարբերակով։</p>
|
||||
<p>Համապատասխան մոդելի բացակայության դեպքում գնորդը կարող է հրաժարվել պատվերից և ստանալ փոխհատուցում։</p>
|
||||
</section>
|
||||
|
||||
<section class="info-card">
|
||||
<section class="info-card wide">
|
||||
<div class="card-icon">🛡️</div>
|
||||
<h2>8. Երաշխիքային սպասարկում</h2>
|
||||
<p>Երաշխիքի պայմանները նշված են ապրանքի էջում կամ հասանելի են վաճառողից։</p>
|
||||
@@ -149,7 +149,7 @@
|
||||
<p>Երաշխիքային սպասարկումը չի տարածվում ֆիզիկական վնասների, ոչ պատշաճ օգտագործման կամ ինքնուրույն միջամտության դեպքում։</p>
|
||||
</section>
|
||||
|
||||
<section class="info-card">
|
||||
<section class="info-card wide">
|
||||
<div class="card-icon">⚖️</div>
|
||||
<h2>9. Կողմերի պարտականություններ</h2>
|
||||
<p>Մատակարարը պատասխանատու է ապրանքի որակի և ժամանակային գումարի վերադարձի համար։</p>
|
||||
@@ -163,7 +163,7 @@
|
||||
<p>Վերադարձի հարցերը կարող եք ուղղել անմիջապես վաճառողին — կոնտակտները նշված են ձեր պատվերում։</p>
|
||||
<p>Վեճերը հարթակի ադմինիստրացիայի միջոցով լուծելու համար՝</p>
|
||||
<ul class="compact-list">
|
||||
<li><strong>E-mail:</strong> <a href="mailto:info@lavero.market" class="contact-email">info@lavero.market</a></li>
|
||||
<li><strong>E-mail:</strong> <a href="mailto:info@lavero.store" class="contact-email">info@lavero.store</a></li>
|
||||
<li><strong>Հեռախոս՝</strong> <a [href]="env.phoneTel">{{ env.phones.support }}</a></li>
|
||||
<li><strong>Թեմա՝</strong> «Վեճ վաճառողի հետ — Պատվերի №»</li>
|
||||
<li><strong>Կցեք՝</strong> նամակագրություն, լուսանկարներ, վճարման կտրոն</li>
|
||||
|
||||
@@ -9,14 +9,14 @@
|
||||
<section class="info-card wide">
|
||||
<div class="card-icon">📋</div>
|
||||
<h2>1. Общие положения</h2>
|
||||
<p>1.1. Данная политика описывает порядок возврата продукции и отказа от сервисов, купленных на платформе Lavero Market.</p>
|
||||
<p>1.1. Данная политика описывает порядок возврата продукции и отказа от сервисов, купленных на платформе Lavero Store.</p>
|
||||
<p>1.2. Наша площадка действует как информационный посредник, поэтому все споры о возврате решаются напрямую между клиентом и поставщиком согласно законам РФ.</p>
|
||||
<p>1.3. Для качественной продукции применяется ст. 26.1 ФЗ «О защите прав потребителей».</p>
|
||||
<p>1.4. Для товаров с недостатками действуют ст. 18–24 того же закона.</p>
|
||||
<p>1.5. Электронные товары возвращаются по специальным правилам, прописанным в законодательстве.</p>
|
||||
</section>
|
||||
|
||||
<section class="info-card">
|
||||
<section class="info-card wide">
|
||||
<div class="card-icon">📅</div>
|
||||
<h2>2. Временные рамки</h2>
|
||||
<p><strong>2.1. Качественная продукция:</strong></p>
|
||||
@@ -112,7 +112,7 @@
|
||||
<p>Наша площадка всегда готова помочь в урегулировании спорных ситуаций.</p>
|
||||
</section>
|
||||
|
||||
<section class="info-card">
|
||||
<section class="info-card wide">
|
||||
<div class="card-icon">💰</div>
|
||||
<h2>6. Компенсация платежа</h2>
|
||||
<p>Деньги возмещаются на тот же способ оплаты:</p>
|
||||
@@ -134,14 +134,14 @@
|
||||
<p>Клиент имеет право потребовать компенсацию за некачественную продукцию и расходы по пересылке.</p>
|
||||
</section>
|
||||
|
||||
<section class="info-card">
|
||||
<section class="info-card wide">
|
||||
<div class="card-icon">🔄</div>
|
||||
<h2>7. Обмен продукции</h2>
|
||||
<p>При несоответствии исправного изделия по габаритам, размерам или параметрам, клиент может заменить его у поставщика на подходящий вариант.</p>
|
||||
<p>При отсутствии нужной модели клиент вправе отказаться от заказа и получить компенсацию.</p>
|
||||
</section>
|
||||
|
||||
<section class="info-card">
|
||||
<section class="info-card wide">
|
||||
<div class="card-icon">🛡️</div>
|
||||
<h2>8. Сервисное обслуживание</h2>
|
||||
<p>Информация о гарантийных условиях размещена в карточке товара или доступна у продавца.</p>
|
||||
@@ -149,7 +149,7 @@
|
||||
<p>Гарантийное обслуживание не распространяется на физические ущербы, неправильное применение или самостоятельное вмешательство.</p>
|
||||
</section>
|
||||
|
||||
<section class="info-card">
|
||||
<section class="info-card wide">
|
||||
<div class="card-icon">⚖️</div>
|
||||
<h2>9. Обязанности участников</h2>
|
||||
<p>Поставщик несет ответственность за качество продукции и своевременное возмещение платежей.</p>
|
||||
@@ -163,7 +163,7 @@
|
||||
<p>Вопросы по возврату можно задавать напрямую продавцу — контакты указаны в вашем заказе.</p>
|
||||
<p>Для разрешения споров через администрацию платформы:</p>
|
||||
<ul class="compact-list">
|
||||
<li><strong>E-mail:</strong> <a href="mailto:info@lavero.market" class="contact-email">info@lavero.market</a></li>
|
||||
<li><strong>E-mail:</strong> <a href="mailto:info@lavero.store" class="contact-email">info@lavero.store</a></li>
|
||||
<li><strong>Телефон:</strong> <a [href]="env.phoneTel">{{ env.phones.support }}</a></li>
|
||||
<li><strong>Тема:</strong> «Разногласия с продавцом — №Заказа»</li>
|
||||
<li><strong>Приложите:</strong> переписку, снимки, чек оплаты</li>
|
||||
|
||||
@@ -12,19 +12,19 @@
|
||||
<p>We are a rapidly growing marketplace connecting sellers and buyers from different countries. Our platform creates convenient conditions for safe trading of various goods and services.</p>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">🎯</div>
|
||||
<h3>Our Mission</h3>
|
||||
<p>To create a simple and profitable ecosystem for businesses and buyers, where everyone finds the best deals.</p>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">🌍</div>
|
||||
<h3>Geography</h3>
|
||||
<p>We operate in Russia, Armenia, UAE, Turkey, China, Kazakhstan, Kyrgyzstan, and other countries.</p>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">💼</div>
|
||||
<h3>For Business</h3>
|
||||
<ul class="compact-list">
|
||||
@@ -35,7 +35,7 @@
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">🛍️</div>
|
||||
<h3>For Buyers</h3>
|
||||
<ul class="compact-list">
|
||||
@@ -46,7 +46,7 @@
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">🔒</div>
|
||||
<h3>Our Values</h3>
|
||||
<div class="features-list">
|
||||
@@ -87,7 +87,7 @@
|
||||
<p><strong>Bank:</strong> To be confirmed</p>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">📞</div>
|
||||
<h3>Contact Us</h3>
|
||||
<a href="mailto:info@novo.market" class="contact-email">info@novo.market</a>
|
||||
|
||||
@@ -12,19 +12,19 @@
|
||||
<p>Մենք դինամիկ զարգացող մարկեթփլեյս ենք, որը միավորում է վաճառողներին և գնորդներին տարբեր երկրներից։ Մեր հարթակը ստեղծում է հարմար պայմաններ տարբեր ապրանքների և ծառայությունների անվտանգ առևտրի համար։</p>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">🎯</div>
|
||||
<h3>Մեր առաքելությունը</h3>
|
||||
<p>Ստեղծել պարզ և շահավետ էկոհամակարգ բիզնեսի և գնորդների համար, որտեղ բոլորը գտնեն լավագույն առաջարկները։</p>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">🌍</div>
|
||||
<h3>Աշխարհագրություն</h3>
|
||||
<p>Մենք աշխատում ենք Ռուսաստանում, Հայաստանում, ԱՀԷ-ում, Թուրքիայում, Չինաստանում, Ղազախստանում, Ղրղզստանում և այլ երկրներում։</p>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">💼</div>
|
||||
<h3>Բիզնեսի համար</h3>
|
||||
<ul class="compact-list">
|
||||
@@ -35,7 +35,7 @@
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">🛍️</div>
|
||||
<h3>Գնորդների համար</h3>
|
||||
<ul class="compact-list">
|
||||
@@ -46,7 +46,7 @@
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">🔒</div>
|
||||
<h3>Մեր արժեքները</h3>
|
||||
<div class="features-list">
|
||||
@@ -87,7 +87,7 @@
|
||||
<p><strong>Բանկ՝</strong> Ճշտում է</p>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">📞</div>
|
||||
<h3>Կապվել մեզ հետ</h3>
|
||||
<a href="mailto:info@novo.market" class="contact-email">info@novo.market</a>
|
||||
|
||||
@@ -12,19 +12,19 @@
|
||||
<p>Мы - динамично развивающийся маркетплейс, объединяющий продавцов и покупателей из разных стран. Наша платформа создает удобные условия для безопасной торговли различными товарами и услугами.</p>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">🎯</div>
|
||||
<h3>Наша миссия</h3>
|
||||
<p>Создавать простую и выгодную экосистему для бизнеса и покупателей, где каждый находит лучшие предложения.</p>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">🌍</div>
|
||||
<h3>География</h3>
|
||||
<p>Мы работаем в России, Армении, ОАЭ, Турции, Китае, Казахстане, Кыргызстане и других странах.</p>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">💼</div>
|
||||
<h3>Для бизнеса</h3>
|
||||
<ul class="compact-list">
|
||||
@@ -35,7 +35,7 @@
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">🛍️</div>
|
||||
<h3>Для покупателей</h3>
|
||||
<ul class="compact-list">
|
||||
@@ -46,7 +46,7 @@
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">🔒</div>
|
||||
<h3>Наши ценности</h3>
|
||||
<div class="features-list">
|
||||
@@ -87,7 +87,7 @@
|
||||
<p><strong>Банк:</strong> Уточняется</p>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">📞</div>
|
||||
<h3>Связаться с нами</h3>
|
||||
<a href="mailto:info@novo.market" class="contact-email">info@novo.market</a>
|
||||
|
||||
@@ -6,33 +6,33 @@
|
||||
</div>
|
||||
|
||||
<div class="novo-cards">
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">🏢</div>
|
||||
<h3>Organization</h3>
|
||||
<p class="org-name">LLC «ELECTROMOTORS»</p>
|
||||
<p><strong>TIN:</strong> 9909687443</p>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">📞</div>
|
||||
<h3>Phone</h3>
|
||||
<p><a [href]="env.phoneTel">{{ env.phones.support }}</a></p>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">✉️</div>
|
||||
<h3>Email</h3>
|
||||
<p><a href="mailto:info@novo.market">info@novo.market</a></p>
|
||||
<p class="note">Response within 24 hours</p>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">📍</div>
|
||||
<h3>Address</h3>
|
||||
<p>Armenia, 0501, Aragatsotn region, Talin, 12 Gaya St.</p>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">⏰</div>
|
||||
<h3>Working Hours</h3>
|
||||
<p><strong>Support:</strong> 9:00 - 21:00</p>
|
||||
|
||||
@@ -6,33 +6,33 @@
|
||||
</div>
|
||||
|
||||
<div class="novo-cards">
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">🏢</div>
|
||||
<h3>Կազմակերպություն</h3>
|
||||
<p class="org-name">ՍՊԸ «ԷԼԵԿՏՌՈՄՈՏՈՌՍ»</p>
|
||||
<p><strong>ՀՎՀՀ՝</strong> 9909687443</p>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">📞</div>
|
||||
<h3>Հեռախոս</h3>
|
||||
<p><a [href]="env.phoneTel">{{ env.phones.support }}</a></p>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">✉️</div>
|
||||
<h3>Էլ. փոստ</h3>
|
||||
<p><a href="mailto:info@novo.market">info@novo.market</a></p>
|
||||
<p class="note">Պատասխանը 24 ժամվա ընթացքում</p>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">📍</div>
|
||||
<h3>Հասցե</h3>
|
||||
<p>Հայաստան, 0501, Արագածոտնի մարզ, ք. Տալին, Գայայի փող. 12</p>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">⏰</div>
|
||||
<h3>Աշխատանքային ժամեր</h3>
|
||||
<p><strong>Աջակցություն՝</strong> 9:00 - 21:00</p>
|
||||
|
||||
@@ -6,33 +6,33 @@
|
||||
</div>
|
||||
|
||||
<div class="novo-cards">
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">🏢</div>
|
||||
<h3>Организация</h3>
|
||||
<p class="org-name">ООО «ЭЛЕКТРОМОТОРС»</p>
|
||||
<p><strong>ИНН:</strong> 9909687443</p>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">📞</div>
|
||||
<h3>Телефон</h3>
|
||||
<p><a [href]="env.phoneTel">{{ env.phones.support }}</a></p>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">✉️</div>
|
||||
<h3>Email</h3>
|
||||
<p><a href="mailto:info@novo.market">info@novo.market</a></p>
|
||||
<p class="note">Ответ в течение 24 часов</p>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">📍</div>
|
||||
<h3>Адрес</h3>
|
||||
<p>Армения, 0501, Арагацотиская обл., г. Талин, ул. Гая, д. 12</p>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">⏰</div>
|
||||
<h3>Часы работы</h3>
|
||||
<p><strong>Поддержка:</strong> 9:00 - 21:00</p>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
</div>
|
||||
|
||||
<div class="novo-cards">
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">📧</div>
|
||||
<h3>Digital Products</h3>
|
||||
<div class="features-list">
|
||||
@@ -18,7 +18,7 @@
|
||||
<p class="note important" style="margin-top: 12px;">⚠️ The platform is not responsible for digital products. The seller is responsible for quality and functionality.</p>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">📦</div>
|
||||
<h3>Physical Products</h3>
|
||||
<ul class="compact-list">
|
||||
@@ -32,7 +32,7 @@
|
||||
<p class="note important" style="margin-top: 12px;">⚠️ The platform is not responsible for the actions of shipping companies. Delivery is handled by СДЭК, Почта России, Boxberry, DPD, and other carriers.</p>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">💰</div>
|
||||
<h3>Delivery Cost</h3>
|
||||
<div class="delivery-cost">
|
||||
@@ -48,7 +48,7 @@
|
||||
<p class="note">Exact cost is calculated at checkout</p>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">🔍</div>
|
||||
<h3>Tracking</h3>
|
||||
<p>After shipping, you will receive a tracking number by email. Track your package on the delivery service website or in your account.</p>
|
||||
@@ -66,7 +66,7 @@
|
||||
<p class="note important">If there are issues - file a report with the courier</p>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">📞</div>
|
||||
<h3>Questions about delivery?</h3>
|
||||
<p>Contact the seller or us:</p>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
</div>
|
||||
|
||||
<div class="novo-cards">
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">📧</div>
|
||||
<h3>Թվային ապրանքներ</h3>
|
||||
<div class="features-list">
|
||||
@@ -18,7 +18,7 @@
|
||||
<p class="note important" style="margin-top: 12px;">⚠️ Հարթակը պատասխանատվություն չի կրում թվային ապրանքների համար։ Որակի և գործունակության համար պատասխանատու է վաճառողը։</p>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">📦</div>
|
||||
<h3>Ֆիզիկական ապրանքներ</h3>
|
||||
<ul class="compact-list">
|
||||
@@ -32,7 +32,7 @@
|
||||
<p class="note important" style="margin-top: 12px;">⚠️ Հարթակը պատասխանատվություն չի կրում տրանսպորտային ընկերությունների գործողությունների համար։ Առաքման համար պատասխանատու են СДЭК, Почта России, Boxberry, DPD և այլ փոխադրողներ։</p>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">💰</div>
|
||||
<h3>Առաքման արժեքը</h3>
|
||||
<div class="delivery-cost">
|
||||
@@ -48,7 +48,7 @@
|
||||
<p class="note">Ճիշտ արժեքը հաշվարկվում է ձևակերպման ժամանակ</p>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">🔍</div>
|
||||
<h3>Հետագծում</h3>
|
||||
<p>Ուղարկմանից հետո դուք կստանաք թրեք-համար email-ով։ Հետևեք ծանրութը առաքման ծառայության կայքում կամ անձնական էջում։</p>
|
||||
@@ -66,7 +66,7 @@
|
||||
<p class="note important">Եթե խնդիրներ կան - կազմեք ակտ սուրհանդեսի հետ</p>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">📞</div>
|
||||
<h3>Առաքման հարցեր՞</h3>
|
||||
<p>Կապվեք վաճառողի կամ մեզ հետ՝</p>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
</div>
|
||||
|
||||
<div class="novo-cards">
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">📧</div>
|
||||
<h3>Цифровые товары</h3>
|
||||
<div class="features-list">
|
||||
@@ -18,7 +18,7 @@
|
||||
<p class="note important" style="margin-top: 12px;">⚠️ Платформа не несет ответственности за цифровые товары. За качество и работоспособность отвечает продавец.</p>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">📦</div>
|
||||
<h3>Физические товары</h3>
|
||||
<ul class="compact-list">
|
||||
@@ -32,7 +32,7 @@
|
||||
<p class="note important" style="margin-top: 12px;">⚠️ Платформа не несет ответственности за действия транспортных компаний. За доставку отвечают СДЭК, Почта России, Boxberry, DPD и другие перевозчики.</p>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">💰</div>
|
||||
<h3>Стоимость доставки</h3>
|
||||
<div class="delivery-cost">
|
||||
@@ -48,7 +48,7 @@
|
||||
<p class="note">Точная стоимость рассчитывается при оформлении</p>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">🔍</div>
|
||||
<h3>Отслеживание</h3>
|
||||
<p>После отправки вы получите трек-номер на email. Отслеживайте посылку на сайте службы доставки или в личном кабинете.</p>
|
||||
@@ -66,7 +66,7 @@
|
||||
<p class="note important">Если есть проблемы - составьте акт с курьером</p>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">📞</div>
|
||||
<h3>Вопросы по доставке?</h3>
|
||||
<p>Свяжитесь с продавцом или нами:</p>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
</div>
|
||||
|
||||
<div class="novo-cards">
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">🛍️</div>
|
||||
<h3>How to place an order?</h3>
|
||||
<div class="process-steps-compact">
|
||||
@@ -17,7 +17,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">💳</div>
|
||||
<h3>Payment Methods</h3>
|
||||
<ul class="compact-list">
|
||||
@@ -29,7 +29,7 @@
|
||||
<p class="note">*Depends on the seller</p>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">🚚</div>
|
||||
<h3>Delivery</h3>
|
||||
<div class="delivery-info">
|
||||
@@ -44,13 +44,13 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">↩️</div>
|
||||
<h3>Product Returns</h3>
|
||||
<p>You can return a product in good condition within 7 days, provided it has not been used and the packaging is intact.</p>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">🔒</div>
|
||||
<h3>Security</h3>
|
||||
<div class="features-list">
|
||||
@@ -60,7 +60,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">⏱️</div>
|
||||
<h3>Order Processing</h3>
|
||||
<p>Your order is processed immediately after payment. The seller ships the product within 1-3 business days.</p>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
</div>
|
||||
|
||||
<div class="novo-cards">
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">🛍️</div>
|
||||
<h3>Ինչպես կատարել պատվեր՞</h3>
|
||||
<div class="process-steps-compact">
|
||||
@@ -17,7 +17,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">💳</div>
|
||||
<h3>Վճարման եղանակներ</h3>
|
||||
<ul class="compact-list">
|
||||
@@ -29,7 +29,7 @@
|
||||
<p class="note">*Կախված է վաճառողից</p>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">🚚</div>
|
||||
<h3>Առաքում</h3>
|
||||
<div class="delivery-info">
|
||||
@@ -44,13 +44,13 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">↩️</div>
|
||||
<h3>Ապրանքի վերադարձ</h3>
|
||||
<p>Կարելի է վերադարձել որակյալ ապրանքը 7 օրվա ընթացքում, եթե այն չի օգտագործվել և փաթեթավորումը պահպանված է։</p>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">🔒</div>
|
||||
<h3>Անվտանգություն</h3>
|
||||
<div class="features-list">
|
||||
@@ -60,7 +60,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">⏱️</div>
|
||||
<h3>Պատվերի մշակում</h3>
|
||||
<p>Պատվերը մշակվում է վճարումից անմիջապես հետո։ Վաճառողը ապրանքը ուղարկում է 1-3 աշխատանքային օրվա ընթացքում։</p>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
</div>
|
||||
|
||||
<div class="novo-cards">
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">🛍️</div>
|
||||
<h3>Как сделать заказ?</h3>
|
||||
<div class="process-steps-compact">
|
||||
@@ -17,7 +17,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">💳</div>
|
||||
<h3>Способы оплаты</h3>
|
||||
<ul class="compact-list">
|
||||
@@ -29,7 +29,7 @@
|
||||
<p class="note">*Зависит от продавца</p>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">🚚</div>
|
||||
<h3>Доставка</h3>
|
||||
<div class="delivery-info">
|
||||
@@ -44,13 +44,13 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">↩️</div>
|
||||
<h3>Возврат товара</h3>
|
||||
<p>Можно вернуть качественный товар в течение 7 дней, если он не использовался и сохранена упаковка.</p>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">🔒</div>
|
||||
<h3>Безопасность</h3>
|
||||
<div class="features-list">
|
||||
@@ -60,7 +60,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">⏱️</div>
|
||||
<h3>Обработка заказа</h3>
|
||||
<p>Заказ обрабатывается сразу после оплаты. Продавец отправляет товар в течение 1-3 рабочих дней.</p>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
</div>
|
||||
|
||||
<div class="novo-cards">
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">🏷️</div>
|
||||
<h3>Warranty Periods</h3>
|
||||
<div class="warranty-periods">
|
||||
@@ -25,7 +25,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">✓</div>
|
||||
<h3>Warranty Conditions</h3>
|
||||
<ul class="compact-list">
|
||||
@@ -37,7 +37,7 @@
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">🛠️</div>
|
||||
<h3>Your Rights for Defects</h3>
|
||||
<ul class="compact-list">
|
||||
@@ -48,7 +48,7 @@
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">⏱️</div>
|
||||
<h3>Repair Timeframe</h3>
|
||||
<p>Maximum 45 days by law. If the deadline is violated, you can request a replacement or a refund.</p>
|
||||
@@ -67,7 +67,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">📝</div>
|
||||
<h3>How to File a Claim</h3>
|
||||
<div class="process-steps-compact">
|
||||
@@ -79,7 +79,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">📞</div>
|
||||
<h3>Need Help?</h3>
|
||||
<p>In case of disputes:</p>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
</div>
|
||||
|
||||
<div class="novo-cards">
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">🏷️</div>
|
||||
<h3>Երաշխիքի ժամկետներ</h3>
|
||||
<div class="warranty-periods">
|
||||
@@ -25,7 +25,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">✓</div>
|
||||
<h3>Երաշխիքի պայմաններ</h3>
|
||||
<ul class="compact-list">
|
||||
@@ -37,7 +37,7 @@
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">🛠️</div>
|
||||
<h3>Ձեր իրավունքները թերության դեպքում</h3>
|
||||
<ul class="compact-list">
|
||||
@@ -48,7 +48,7 @@
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">⏱️</div>
|
||||
<h3>Նորոգման ժամկետ</h3>
|
||||
<p>Օրենքով առավելագույնը 45 օր։ Եթե ժամկետը խախտվի ՝ կարող եք պահանջել փոխարինում կամ գումարի վերադարձ։</p>
|
||||
@@ -67,7 +67,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">📝</div>
|
||||
<h3>Ինչպես դիմել հայտ</h3>
|
||||
<div class="process-steps-compact">
|
||||
@@ -79,7 +79,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">📞</div>
|
||||
<h3>Օգնությու՞ն պետք է՞</h3>
|
||||
<p>Վեճերի դեպքում՝</p>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
</div>
|
||||
|
||||
<div class="novo-cards">
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">🏷️</div>
|
||||
<h3>Сроки гарантии</h3>
|
||||
<div class="warranty-periods">
|
||||
@@ -25,7 +25,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">✓</div>
|
||||
<h3>Условия гарантии</h3>
|
||||
<ul class="compact-list">
|
||||
@@ -37,7 +37,7 @@
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">🛠️</div>
|
||||
<h3>Ваши права при браке</h3>
|
||||
<ul class="compact-list">
|
||||
@@ -48,7 +48,7 @@
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">⏱️</div>
|
||||
<h3>Срок ремонта</h3>
|
||||
<p>Максимум 45 дней по закону. Если срок нарушен - можно требовать замену или возврат денег.</p>
|
||||
@@ -67,7 +67,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">📝</div>
|
||||
<h3>Как подать заявку</h3>
|
||||
<div class="process-steps-compact">
|
||||
@@ -79,7 +79,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">📞</div>
|
||||
<h3>Нужна помощь?</h3>
|
||||
<p>При возникновении споров:</p>
|
||||
|
||||
@@ -6,14 +6,14 @@
|
||||
</div>
|
||||
|
||||
<div class="novo-cards">
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">🏢</div>
|
||||
<h3>Company Name</h3>
|
||||
<p class="org-name">ОБЩЕСТВО С ОГРАНИЧЕННОЙ ОТВЕТСТВЕННОСТЬЮ «ЭЛЕКТРОМОТОРС»</p>
|
||||
<p class="org-short">Abbreviated: ООО «ЭЛЕКТРОМОТОРС»</p>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">📍</div>
|
||||
<h3>Registered Address</h3>
|
||||
<p>АРМЕНИЯ, 0501, АРАГАЦОТИСКАЯ ОБЛАСТЬ, ТАЛИН, ул. ГАЯ, д. 12</p>
|
||||
@@ -30,7 +30,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">📋</div>
|
||||
<h3>Details</h3>
|
||||
<div class="requisites">
|
||||
@@ -45,7 +45,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">💳</div>
|
||||
<h3>Bank Details</h3>
|
||||
<div class="requisites">
|
||||
@@ -101,7 +101,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">👤</div>
|
||||
<h3>Management</h3>
|
||||
<p><strong>General Director</strong></p>
|
||||
|
||||
@@ -6,14 +6,14 @@
|
||||
</div>
|
||||
|
||||
<div class="novo-cards">
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">🏢</div>
|
||||
<h3>Անվանում</h3>
|
||||
<p class="org-name">ОБЩЕСТВО С ОГРАНИЧЕННОЙ ОТВЕТСТВЕННОСТЬЮ «ЭЛЕКТРОМОТОРС»</p>
|
||||
<p class="org-short">Կրճատ՝ ООО «ЭЛЕКТРОМОТОРС»</p>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">📍</div>
|
||||
<h3>Գրանցման հասցե</h3>
|
||||
<p>АРМЕНИЯ, 0501, АРАГАЦОТИСКАЯ ОБЛАСТЬ, ТАЛИН, ул. ГАЯ, д. 12</p>
|
||||
@@ -30,7 +30,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">📋</div>
|
||||
<h3>Ռեկվիզիտներ</h3>
|
||||
<div class="requisites">
|
||||
@@ -45,7 +45,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">💳</div>
|
||||
<h3>Բանկային տվյալներ</h3>
|
||||
<div class="requisites">
|
||||
@@ -101,7 +101,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">👤</div>
|
||||
<h3>Ղեկավարություն</h3>
|
||||
<p><strong>Գլխավոր տնօրեն</strong></p>
|
||||
|
||||
@@ -6,14 +6,14 @@
|
||||
</div>
|
||||
|
||||
<div class="novo-cards">
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">🏢</div>
|
||||
<h3>Наименование</h3>
|
||||
<p class="org-name">ОБЩЕСТВО С ОГРАНИЧЕННОЙ ОТВЕТСТВЕННОСТЬЮ «ЭЛЕКТРОМОТОРС»</p>
|
||||
<p class="org-short">Сокращенно: ООО «ЭЛЕКТРОМОТОРС»</p>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">📍</div>
|
||||
<h3>Адрес регистрации</h3>
|
||||
<p>АРМЕНИЯ, 0501, АРАГАЦОТИСКАЯ ОБЛАСТЬ, ТАЛИН, ул. ГАЯ, д. 12</p>
|
||||
@@ -30,7 +30,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">📋</div>
|
||||
<h3>Реквизиты</h3>
|
||||
<div class="requisites">
|
||||
@@ -45,7 +45,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">💳</div>
|
||||
<h3>Банковские реквизиты</h3>
|
||||
<div class="requisites">
|
||||
@@ -101,7 +101,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<div class="info-card wide">
|
||||
<div class="card-icon">👤</div>
|
||||
<h3>Руководство</h3>
|
||||
<p><strong>Генеральный директор</strong></p>
|
||||
|
||||
@@ -53,7 +53,7 @@
|
||||
<p>2.3. All payments are processed through certified payment systems in compliance with PCI DSS security standards.</p>
|
||||
</section>
|
||||
|
||||
<section class="info-card">
|
||||
<section class="info-card wide">
|
||||
<div class="card-icon">⚙️</div>
|
||||
<h2>3. Payment Process</h2>
|
||||
<p>3.1. The order payment procedure includes the following steps:</p>
|
||||
@@ -69,7 +69,7 @@
|
||||
<p>3.3. The Buyer's payment obligation is considered fulfilled from the moment the funds are received in the payment system account.</p>
|
||||
</section>
|
||||
|
||||
<section class="info-card">
|
||||
<section class="info-card wide">
|
||||
<div class="card-icon">🛡️</div>
|
||||
<h2>4. Payment Security</h2>
|
||||
<p>4.1. All payments are processed through a secure HTTPS connection using TLS 1.2 protocol and above.</p>
|
||||
@@ -84,7 +84,7 @@
|
||||
<p>4.4. In case of suspicious activity, the payment system has the right to request additional identity verification of the Buyer.</p>
|
||||
</section>
|
||||
|
||||
<section class="info-card">
|
||||
<section class="info-card wide">
|
||||
<div class="card-icon">✅</div>
|
||||
<h2>5. Payment Confirmation</h2>
|
||||
<p>5.1. After successful payment, the Buyer receives a confirmation to the email address provided during checkout.</p>
|
||||
@@ -124,7 +124,7 @@
|
||||
<p>6.4. The Marketplace does not charge a fee for processing refunds. Payment system and bank fees may apply in accordance with their tariffs.</p>
|
||||
</section>
|
||||
|
||||
<section class="info-card">
|
||||
<section class="info-card wide">
|
||||
<div class="card-icon">❌</div>
|
||||
<h2>7. Failed Payments</h2>
|
||||
<p>7.1. A payment may be declined for the following reasons:</p>
|
||||
|
||||
@@ -53,7 +53,7 @@
|
||||
<p>2.3. Բոլոր վճարումները մշակվում են սերտիֆիկացված վճարման համակարգերի միջոցով՝ PCI DSS անվտանգության ստանդարտներին համապատասխան։</p>
|
||||
</section>
|
||||
|
||||
<section class="info-card">
|
||||
<section class="info-card wide">
|
||||
<div class="card-icon">⚙️</div>
|
||||
<h2>3. Վճարման գործընթացը</h2>
|
||||
<p>3.1. Պատվերի վճարման գործընթացը ներառում է հետևյալ քայլերը՝</p>
|
||||
@@ -69,7 +69,7 @@
|
||||
<p>3.3. Գնորդի վճարման պարտավորությունը համարվում է կատարված վճարման համակարգի հաշվին դրամական միջոցների մուտքագրման պահից։</p>
|
||||
</section>
|
||||
|
||||
<section class="info-card">
|
||||
<section class="info-card wide">
|
||||
<div class="card-icon">🛡️</div>
|
||||
<h2>4. Վճարումների անվտանգություն</h2>
|
||||
<p>4.1. Բոլոր վճարումները մշակվում են պաշտպանված HTTPS կապակցով՝ TLS 1.2 և ավելի բարձր արթանագրի օգտագործմամբ։</p>
|
||||
@@ -84,7 +84,7 @@
|
||||
<p>4.4. Կասկածելի գործունեության դեպքում վճարման համակարգը իրավունք ունի պահանջել Գնորդի ինքնության լրացուցիչ ստուգում։</p>
|
||||
</section>
|
||||
|
||||
<section class="info-card">
|
||||
<section class="info-card wide">
|
||||
<div class="card-icon">✅</div>
|
||||
<h2>5. Վճարման հաստատում</h2>
|
||||
<p>5.1. Հաջող վճարմանից հետո Գնորդը ստանում է հաստատում պատվերի ձևակերպման թելադրված էլ. փոստի հասցեին։</p>
|
||||
@@ -124,7 +124,7 @@
|
||||
<p>6.4. Միջոցների վերադարձի մշակման համար Մարկեթպլեյսը միջնորդավճար չի գանձում։ Վճարման համակարգերի և բանկերի միջնորդավճարները կարող են կիրառվել դրանց սակագներին համապատասխան։</p>
|
||||
</section>
|
||||
|
||||
<section class="info-card">
|
||||
<section class="info-card wide">
|
||||
<div class="card-icon">❌</div>
|
||||
<h2>7. Անհաջող վճարումներ</h2>
|
||||
<p>7.1. Վճարումը կարող է մերժվել հետևյալ պատճառներով՝</p>
|
||||
|
||||
@@ -53,7 +53,7 @@
|
||||
<p>2.3. Все платежи обрабатываются через сертифицированные платежные системы с соблюдением стандартов безопасности PCI DSS.</p>
|
||||
</section>
|
||||
|
||||
<section class="info-card">
|
||||
<section class="info-card wide">
|
||||
<div class="card-icon">⚙️</div>
|
||||
<h2>3. Процесс оплаты</h2>
|
||||
<p>3.1. Процедура оплаты заказа включает следующие этапы:</p>
|
||||
@@ -69,7 +69,7 @@
|
||||
<p>3.3. Обязательство Покупателя по оплате считается исполненным с момента поступления денежных средств на счет платежной системы.</p>
|
||||
</section>
|
||||
|
||||
<section class="info-card">
|
||||
<section class="info-card wide">
|
||||
<div class="card-icon">🛡️</div>
|
||||
<h2>4. Безопасность платежей</h2>
|
||||
<p>4.1. Все платежи обрабатываются через защищенное HTTPS-соединение с использованием протокола TLS 1.2 и выше.</p>
|
||||
@@ -84,7 +84,7 @@
|
||||
<p>4.4. В случае подозрительной активности платежная система имеет право запросить дополнительную верификацию личности Покупателя.</p>
|
||||
</section>
|
||||
|
||||
<section class="info-card">
|
||||
<section class="info-card wide">
|
||||
<div class="card-icon">✅</div>
|
||||
<h2>5. Подтверждение оплаты</h2>
|
||||
<p>5.1. После успешной оплаты Покупатель получает подтверждение на указанный при оформлении заказа адрес электронной почты.</p>
|
||||
@@ -124,7 +124,7 @@
|
||||
<p>6.4. За обработку возврата средств Маркетплейс комиссию не взимает. Комиссии платежных систем и банков могут применяться в соответствии с их тарифами.</p>
|
||||
</section>
|
||||
|
||||
<section class="info-card">
|
||||
<section class="info-card wide">
|
||||
<div class="card-icon">❌</div>
|
||||
<h2>7. Неуспешные платежи</h2>
|
||||
<p>7.1. Платеж может быть отклонен по следующим причинам:</p>
|
||||
|
||||
@@ -104,7 +104,7 @@
|
||||
<p>3.1.5. An agreement between the Operator and a third party, where the latter entrusts the Operator with the processing of personal data of the Personal Data Subject or transfers personal data of the Personal Data Subject based on the concluded agreement.</p>
|
||||
</section>
|
||||
|
||||
<section class="info-card">
|
||||
<section class="info-card wide">
|
||||
<div class="card-icon">👥</div>
|
||||
<h2>4. CATEGORIES OF PERSONAL DATA SUBJECTS</h2>
|
||||
|
||||
@@ -122,7 +122,7 @@
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
<section class="info-card">
|
||||
<section class="info-card wide">
|
||||
<div class="card-icon">📝</div>
|
||||
<h2>5. CATEGORIES OF PROCESSED PERSONAL DATA</h2>
|
||||
|
||||
@@ -172,7 +172,7 @@
|
||||
<p>Include conditions for processing, storage, cross-border data transfer, work with publicly available sources, special and biometric data, as well as the procedure for obtaining clarifications in accordance with the legislation of the Russian Federation.</p>
|
||||
</section>
|
||||
|
||||
<section class="info-card">
|
||||
<section class="info-card wide">
|
||||
<div class="card-icon">✅</div>
|
||||
<h2>7. RIGHTS OF THE PERSONAL DATA SUBJECT</h2>
|
||||
|
||||
@@ -194,7 +194,7 @@
|
||||
<p>The Subject also has the right to protect their rights, recover damages, and receive compensation for moral harm.</p>
|
||||
</section>
|
||||
|
||||
<section class="info-card">
|
||||
<section class="info-card wide">
|
||||
<div class="card-icon">📋</div>
|
||||
<h2>8. OPERATOR'S OBLIGATIONS</h2>
|
||||
|
||||
@@ -205,7 +205,7 @@
|
||||
<p>8.3. The Operator bears other obligations established by FZ-152.</p>
|
||||
</section>
|
||||
|
||||
<section class="info-card">
|
||||
<section class="info-card wide">
|
||||
<div class="card-icon">🛡️</div>
|
||||
<h2>9. SECURITY ASSURANCE</h2>
|
||||
|
||||
@@ -222,14 +222,14 @@
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
<section class="info-card">
|
||||
<section class="info-card wide">
|
||||
<div class="card-icon">⚠️</div>
|
||||
<h2>10. LIABILITY</h2>
|
||||
|
||||
<p>10.1. Persons guilty of violating the norms of processing and protection of Personal Data bear liability in accordance with the legislation of the Russian Federation.</p>
|
||||
</section>
|
||||
|
||||
<section class="info-card">
|
||||
<section class="info-card wide">
|
||||
<div class="card-icon">🎯</div>
|
||||
<h2>11. PURPOSES OF PROCESSING</h2>
|
||||
|
||||
@@ -248,7 +248,7 @@
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
<section class="info-card">
|
||||
<section class="info-card wide">
|
||||
<div class="card-icon">🍪</div>
|
||||
<h2>12. AUTOMATICALLY COLLECTED INFORMATION</h2>
|
||||
|
||||
|
||||
@@ -104,7 +104,7 @@
|
||||
<p>3.1.5. Договор между оператором и третьим лицом, где последнее поручает Оператору обработку персональных данных Субъекта Персональных данных или передает на основании заключенного договора персональные данные Субъекта Персональных данных.</p>
|
||||
</section>
|
||||
|
||||
<section class="info-card">
|
||||
<section class="info-card wide">
|
||||
<div class="card-icon">👥</div>
|
||||
<h2>4. КАТЕГОРИИ СУБЪЕКТОВ ПЕРСОНАЛЬНЫХ ДАННЫХ</h2>
|
||||
|
||||
@@ -122,7 +122,7 @@
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
<section class="info-card">
|
||||
<section class="info-card wide">
|
||||
<div class="card-icon">📝</div>
|
||||
<h2>5. КАТЕГОРИИ ОБРАБАТЫВАЕМЫХ ПЕРСОНАЛЬНЫХ ДАННЫХ</h2>
|
||||
|
||||
@@ -172,7 +172,7 @@
|
||||
<p>Включают условия обработки, хранения, трансграничной передачи данных, работы с общедоступными источниками, специальными и биометрическими данными, а также порядок получения разъяснений согласно законодательству РФ.</p>
|
||||
</section>
|
||||
|
||||
<section class="info-card">
|
||||
<section class="info-card wide">
|
||||
<div class="card-icon">✅</div>
|
||||
<h2>7. ПРАВА СУБЪЕКТА ПЕРСОНАЛЬНЫХ ДАННЫХ</h2>
|
||||
|
||||
@@ -194,7 +194,7 @@
|
||||
<p>Субъект также имеет право на защиту своих прав, возмещение убытков и компенсацию морального вреда.</p>
|
||||
</section>
|
||||
|
||||
<section class="info-card">
|
||||
<section class="info-card wide">
|
||||
<div class="card-icon">📋</div>
|
||||
<h2>8. ОБЯЗАННОСТИ ОПЕРАТОРА</h2>
|
||||
|
||||
@@ -205,7 +205,7 @@
|
||||
<p>8.3. Оператор несет иные обязанности, установленные ФЗ-152.</p>
|
||||
</section>
|
||||
|
||||
<section class="info-card">
|
||||
<section class="info-card wide">
|
||||
<div class="card-icon">🛡️</div>
|
||||
<h2>9. ОБЕСПЕЧЕНИЕ БЕЗОПАСНОСТИ</h2>
|
||||
|
||||
@@ -222,14 +222,14 @@
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
<section class="info-card">
|
||||
<section class="info-card wide">
|
||||
<div class="card-icon">⚠️</div>
|
||||
<h2>10. ОТВЕТСТВЕННОСТЬ</h2>
|
||||
|
||||
<p>10.1. Лица, виновные в нарушении норм обработки и защиты Персональных данных, несут ответственность согласно законодательству РФ.</p>
|
||||
</section>
|
||||
|
||||
<section class="info-card">
|
||||
<section class="info-card wide">
|
||||
<div class="card-icon">🎯</div>
|
||||
<h2>11. ЦЕЛИ ОБРАБОТКИ</h2>
|
||||
|
||||
@@ -248,7 +248,7 @@
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
<section class="info-card">
|
||||
<section class="info-card wide">
|
||||
<div class="card-icon">🍪</div>
|
||||
<h2>12. АВТОМАТИЧЕСКИ СОБИРАЕМАЯ ИНФОРМАЦИЯ</h2>
|
||||
|
||||
|
||||
@@ -36,12 +36,16 @@
|
||||
<p>1.9. Promotional campaigns may have special rules.</p>
|
||||
</section>
|
||||
|
||||
<section class="info-card">
|
||||
<section class="info-card wide">
|
||||
<div class="card-icon">🎯</div>
|
||||
<h2>2. Subject of the Agreement</h2>
|
||||
<p>2.1. The purpose is to provide users with the ability to purchase goods and services presented on the resource.</p>
|
||||
<p>2.2. The agreement regulates the use of the website and provided features.</p>
|
||||
<p>2.3. It applies to all types of goods, services, and products on the website.</p>
|
||||
<p>2.4. The Marketplace is an agent acting under agency agreements with Sellers (Third Parties). The Marketplace does not acquire ownership rights to the Goods/Services sold through the Platform and only provides the technical ability to conclude a transaction between the Seller and the Buyer.</p>
|
||||
<p>2.5. The Seller is an independent business entity and bears full responsibility for the quality, safety, conformity of the Goods/Services to the stated characteristics, and fulfillment of obligations to the Buyer (warranties, returns, claims).</p>
|
||||
<p>2.6. The Marketplace is not a party to the sale and purchase agreement between the Seller and the Buyer. All claims regarding the Goods/Services are submitted by the Buyer directly to the Seller.</p>
|
||||
<p>2.7. The Marketplace's agency remuneration is withheld from the amount paid by the Buyer and does not increase the price for the Buyer beyond the price set by the Seller.</p>
|
||||
</section>
|
||||
|
||||
<section class="info-card wide">
|
||||
@@ -57,7 +61,7 @@
|
||||
<p><strong>3.8. Applicable laws:</strong> Governed by Federal Law "On Consumer Rights Protection" No. 2300-1 and the Civil Code of the Russian Federation.</p>
|
||||
</section>
|
||||
|
||||
<section class="info-card">
|
||||
<section class="info-card wide">
|
||||
<div class="card-icon">📱</div>
|
||||
<h2>4. Registration and Personal Account</h2>
|
||||
<p><strong>4.1. Procedure:</strong> Registration is not required for ordering but provides access to the personal account.</p>
|
||||
@@ -114,7 +118,7 @@
|
||||
<p><strong>Rights:</strong> Opt out of advertising messages through the website or by writing to <a href="mailto:info@novo.market">info@novo.market</a>.</p>
|
||||
</section>
|
||||
|
||||
<section class="info-card">
|
||||
<section class="info-card wide">
|
||||
<div class="card-icon">©</div>
|
||||
<h2>7. Exclusive Rights to Content</h2>
|
||||
<p><strong>7.1. Intellectual property:</strong> All content (design, texts, graphics, video, software, databases) is subject to the copyright of the owner and rights holders.</p>
|
||||
@@ -122,7 +126,7 @@
|
||||
<p><strong>7.3. Personal use:</strong> For personal non-commercial use while preserving copyright notices.</p>
|
||||
</section>
|
||||
|
||||
<section class="info-card">
|
||||
<section class="info-card wide">
|
||||
<div class="card-icon">🔗</div>
|
||||
<h2>8. Third-Party Websites and Content</h2>
|
||||
<p><strong>8.1. External links:</strong> The website may contain links to third-party resources. The website owner is not responsible for their content.</p>
|
||||
@@ -218,14 +222,14 @@
|
||||
<p><strong>13.7. Return method:</strong> The return method is specified in the application.</p>
|
||||
</section>
|
||||
|
||||
<section class="info-card">
|
||||
<section class="info-card wide">
|
||||
<div class="card-icon">⏳</div>
|
||||
<h2>14. Term of the Agreement</h2>
|
||||
<p><strong>14.1. Commencement and termination:</strong> The agreement is active from the moment of acceptance by the user until revocation of acceptance.</p>
|
||||
<p><strong>14.2. Right of revocation:</strong> The owner may revoke the offer pursuant to Art. 436 of the Civil Code of the Russian Federation.</p>
|
||||
</section>
|
||||
|
||||
<section class="info-card">
|
||||
<section class="info-card wide">
|
||||
<div class="card-icon">⚡</div>
|
||||
<h2>15. Dispute Resolution Procedure</h2>
|
||||
<p><strong>15.1. Voluntary settlement:</strong> Mandatory pre-trial dispute resolution procedure.</p>
|
||||
@@ -247,12 +251,12 @@
|
||||
<p><strong>16.3. Legislation:</strong> Issues are resolved under the legislation of Armenia.</p>
|
||||
<p><strong>16.4. The term "Legislation":</strong> Refers to the laws of Armenia.</p>
|
||||
<p><strong>16.5. Free services:</strong> Do not imply the application of consumer protection regulations.</p>
|
||||
<p><strong>16.6. Absence of relationships:</strong> Do not establish agency, partnership, or employment relationships.</p>
|
||||
<p><strong>16.6. Absence of relationships:</strong> Except for the agency model under clause 2.4, the terms do not establish partnership, joint venture, or employment relationships.</p>
|
||||
<p><strong>16.7. Invalidity of clauses:</strong> Does not affect the legal force of the remaining provisions.</p>
|
||||
<p><strong>16.8. Response to violations:</strong> Non-intervention does not prevent subsequent protective measures.</p>
|
||||
</section>
|
||||
|
||||
<section class="info-card">
|
||||
<section class="info-card wide">
|
||||
<div class="card-icon">📞</div>
|
||||
<h2>Contact Us</h2>
|
||||
<p>Questions about the agreement:</p>
|
||||
|
||||
@@ -36,12 +36,16 @@
|
||||
<p>1.9. Գովազդային ակցիաները կարող են ունենալ հատուկ կանոններ։</p>
|
||||
</section>
|
||||
|
||||
<section class="info-card">
|
||||
<section class="info-card wide">
|
||||
<div class="card-icon">🎯</div>
|
||||
<h2>2. Համաձայնագրի առարկան</h2>
|
||||
<p>2.1. Նպատակն է օգտագործողներին հնարավորություն տալ ռեսուրսում ներկայացված ապրանքներ և ծառայություններ ձեռք բերելու։</p>
|
||||
<p>2.2. Համաձայնագիրը կարգավորում է կայքի օգտագործման և տրամադրվող գործառույթների կարգը։</p>
|
||||
<p>2.3. Գործում է կայքում ներկայացված ապրանքների՝ ծառայությունների և պրոդուկտների բոլոր տեսակների նկատմամբ։</p>
|
||||
<p>2.4. Մարկետփլեյսը հանդիսանում է գործակալ, որը գործում է Վաճառողների (Երրորդ անձանց) հետ կնքված գործակալության պայմանագրի հիման վրա։ Մարկետփլեյսը չի ձեռք բերում Հարթակի միջոցով իրացվող Ապրանքների/Ծառայությունների նկատմամբ սեփականության իրավունք, այլ միայն ապահովում է Վաճառողի և Գնորդի միջև գործարք կնքելու տեխնիկական հնարավորությունը։</p>
|
||||
<p>2.5. Վաճառողը հանդիսանում է ինքնուրույն տնտեսվարող սուբյեկտ և կրում է ամբողջական պատասխանատվություն Ապրանքի/Ծառայության որակի, անվտանգության, հայտարարված բնութագրերին համապատասխանության, ինչպես նաև Գնորդի նկատմամբ պարտավորությունների կատարման համար (երաշխիքներ, վերադարձ, պահանջներ)։</p>
|
||||
<p>2.6. Մարկետփլեյսը չի հանդիսանում Վաճառողի և Գնորդի միջև առուվաճառքի պայմանագրի կողմ։ Ապրանքի/Ծառայության վերաբերյալ բոլոր պահանջները Գնորդը ներկայացնում է անմիջապես Վաճառողին։</p>
|
||||
<p>2.7. Մարկետփլեյսի գործակալական վարձատրությունը պահվում է Գնորդի վճարած գումարից և չի ավելացնում Գնորդի համար գինը Վաճառողի սահմանած գնից ավել։</p>
|
||||
</section>
|
||||
|
||||
<section class="info-card wide">
|
||||
@@ -57,7 +61,7 @@
|
||||
<p><strong>3.8. Կիրառվող օրենքներ՝</strong> Կարգավորվում են ՌԴ «Սպառողների իրավունքների պաշտպանության մասին» թիվ 2300-1 և ՌԴ քաղաքացիական օրենսգիրքով։</p>
|
||||
</section>
|
||||
|
||||
<section class="info-card">
|
||||
<section class="info-card wide">
|
||||
<div class="card-icon">📱</div>
|
||||
<h2>4. Գրանցում և անձնական հաշիվ</h2>
|
||||
<p><strong>4.1. Ըթացակարգ՝</strong> Գրանցումը պարտադիր չէ պատվերի համար՝ սակայն հնարավորություն է տալիս անձնական հաշիվ մուտք գործելու։</p>
|
||||
@@ -114,7 +118,7 @@
|
||||
<p><strong>Իրավունքներ՝</strong> Հրաժարվել գովազդային հաղորդագրություններից կայքի միճոցով կամ նամակով <a href="mailto:info@novo.market">info@novo.market</a>։</p>
|
||||
</section>
|
||||
|
||||
<section class="info-card">
|
||||
<section class="info-card wide">
|
||||
<div class="card-icon">©</div>
|
||||
<h2>7. Բովանդակության բացառիկ իրավունքներ</h2>
|
||||
<p><strong>7.1. Մտավոր սեփականություն՝</strong> Բոլոր բովանդակությունը (դիզայն՝ տեքստեր՝ գրաֆիկա՝ տեսանյութ՝ ծրագրեր՝ տվյալների բազաներ) սեփականատիրոջ և իրավատերերի հեղինակային իրավունքների առարկան է։</p>
|
||||
@@ -122,7 +126,7 @@
|
||||
<p><strong>7.3. Անձնական օգտագործում՝</strong> Անձնական ոչ առևտրային օգտագործման համար՝ հեղինակային իրավունքների նիշերի պահպանմամբ։</p>
|
||||
</section>
|
||||
|
||||
<section class="info-card">
|
||||
<section class="info-card wide">
|
||||
<div class="card-icon">🔗</div>
|
||||
<h2>8. Երրորդ կողմերի կայքեր և բովանդակություն</h2>
|
||||
<p><strong>8.1. Արտաքին հղումներ՝</strong> Կայքը կարող է պարունակել երրորդ կողմի ռեսուրսների հղումներ։ Կայքի սեփականատերը պատասխանատու չէ դրանց բովանդակության համար։</p>
|
||||
@@ -218,14 +222,14 @@
|
||||
<p><strong>13.7. Վերադարձի մեխանիզմ՝</strong> Վերադարձի եղանակը նշվում է դիմումում։</p>
|
||||
</section>
|
||||
|
||||
<section class="info-card">
|
||||
<section class="info-card wide">
|
||||
<div class="card-icon">⌛</div>
|
||||
<h2>14. Համաձայնագրի գործողության ժամկետը</h2>
|
||||
<p><strong>14.1. Սկիզբ և դադարեցում՝</strong> Համաձայնագիրը գործում է օգտագործողի ընդունման պահից մինչև ընդունման հետկանչում։</p>
|
||||
<p><strong>14.2. Հետկանչման իրավունք՝</strong> Սեփականատերը կարող է օֆերտան հետ կանչել ՌԴ 436 հոդվածի համաձայն։</p>
|
||||
</section>
|
||||
|
||||
<section class="info-card">
|
||||
<section class="info-card wide">
|
||||
<div class="card-icon">⚡</div>
|
||||
<h2>15. Վեճերի լուծման կարգը</h2>
|
||||
<p><strong>15.1. Կամավոր կարգավորում՝</strong> Պարտադիր նախադատական վեճերի լուծման ընթացակարգ։</p>
|
||||
@@ -247,12 +251,12 @@
|
||||
<p><strong>16.3. Օրենսդրություն՝</strong> Հարցերը լուծվում են Հայաստանի օրենսդրությամբ։</p>
|
||||
<p><strong>16.4. «Օրենսդրություն» տերմին՝</strong> Նշանակում է Հայաստանի օրենքները։</p>
|
||||
<p><strong>16.5. Անվճար ծառայություններ՝</strong> Չեն ենթադրում սպառողների իրավունքների պաշտպանության նորմերի կիրառում։</p>
|
||||
<p><strong>16.6. Հարաբերությունների բացակայություն՝</strong> Չեն հաստատում գործակալային՝ գործընկերային կամ աշխատանքային հարաբերություններ։</p>
|
||||
<p><strong>16.6. Հարաբերությունների բացակայություն՝</strong> Բացի 2.4 կետով նախատեսված գործակալական մոդելից՝ պայմանները չեն հաստատում գործընկերային, համատեղ ձեռնարկության կամ աշխատանքային հարաբերություններ։</p>
|
||||
<p><strong>16.7. Կետերի անվավերություն՝</strong> Չի ազդում մնացած դրույթների իրավական ուժի վրա։</p>
|
||||
<p><strong>16.8. Խախտումների նկատմամբ արձագանք՝</strong> Անգործունեությունը չի խանգարում հետագա պաշտպանության միջոցներին։</p>
|
||||
</section>
|
||||
|
||||
<section class="info-card">
|
||||
<section class="info-card wide">
|
||||
<div class="card-icon">📞</div>
|
||||
<h2>Կապ</h2>
|
||||
<p>Համաձայնագրի վերաբերյալ հարցեր՝</p>
|
||||
|
||||
@@ -36,12 +36,16 @@
|
||||
<p>1.9. Промо-кампании могут иметь специальные правила.</p>
|
||||
</section>
|
||||
|
||||
<section class="info-card">
|
||||
<section class="info-card wide">
|
||||
<div class="card-icon">🎯</div>
|
||||
<h2>2. Предмет соглашения</h2>
|
||||
<p>2.1. Целью является предоставление пользователям возможности покупать товары и услуги, представленные на ресурсе.</p>
|
||||
<p>2.2. Соглашение регулирует порядок использования сайта и предоставляемых функций.</p>
|
||||
<p>2.3. Действие распространяется на все типы товаров, услуг и продуктов на сайте.</p>
|
||||
<p>2.4. Маркетплейс является агентом, действующим на основании договора агентирования с Продавцами (Третьими лицами). Маркетплейс не приобретает право собственности на Товары/Услуги, реализуемые через Платформу, а лишь обеспечивает техническую возможность заключения сделки между Продавцом и Покупателем.</p>
|
||||
<p>2.5. Продавец является самостоятельным хозяйствующим субъектом и несёт полную ответственность за качество, безопасность, соответствие Товара/Услуги заявленным характеристикам, а также за исполнение обязательств перед Покупателем (гарантии, возврат, претензии).</p>
|
||||
<p>2.6. Маркетплейс не выступает стороной договора купли-продажи между Продавцом и Покупателем. Все претензии по Товару/Услуге Покупатель предъявляет непосредственно Продавцу.</p>
|
||||
<p>2.7. Агентское вознаграждение Маркетплейса удерживается из суммы, уплаченной Покупателем, и не увеличивает цену для Покупателя сверх установленной Продавцом.</p>
|
||||
</section>
|
||||
|
||||
<section class="info-card wide">
|
||||
@@ -57,7 +61,7 @@
|
||||
<p><strong>3.8. Применение законов:</strong> Регулируются ФЗ "О защите прав потребителей" №2300-1 и ГК РФ.</p>
|
||||
</section>
|
||||
|
||||
<section class="info-card">
|
||||
<section class="info-card wide">
|
||||
<div class="card-icon">📱</div>
|
||||
<h2>4. Регистрация и личный кабинет</h2>
|
||||
<p><strong>4.1. Процедура:</strong> Регистрация необязательна для заказа, но открывает доступ к личному кабинету.</p>
|
||||
@@ -114,7 +118,7 @@
|
||||
<p><strong>Права:</strong> Отказаться от рекламных сообщений через сайт или письмом на <a href="mailto:info@novo.market">info@novo.market</a>.</p>
|
||||
</section>
|
||||
|
||||
<section class="info-card">
|
||||
<section class="info-card wide">
|
||||
<div class="card-icon">©</div>
|
||||
<h2>7. Исключительные права на контент</h2>
|
||||
<p><strong>7.1. Интеллектуальная собственность:</strong> Весь контент (дизайн, тексты, графика, видео, программы, базы данных) является объектом авторских прав владельца и правообладателей.</p>
|
||||
@@ -122,7 +126,7 @@
|
||||
<p><strong>7.3. Личное использование:</strong> Для личного некоммерческого использования при сохранении обозначений авторских прав.</p>
|
||||
</section>
|
||||
|
||||
<section class="info-card">
|
||||
<section class="info-card wide">
|
||||
<div class="card-icon">🔗</div>
|
||||
<h2>8. Сайты и контент третьих лиц</h2>
|
||||
<p><strong>8.1. Внешние ссылки:</strong> Сайт может содержать ссылки на сторонние ресурсы. Ответственность за их содержание не относится к владельцу сайта.</p>
|
||||
@@ -218,14 +222,14 @@
|
||||
<p><strong>13.7. Механизм возврата:</strong> Способ возврата указывается в заявлении.</p>
|
||||
</section>
|
||||
|
||||
<section class="info-card">
|
||||
<section class="info-card wide">
|
||||
<div class="card-icon">⏳</div>
|
||||
<h2>14. Срок действия соглашения</h2>
|
||||
<p><strong>14.1. Начало и прекращение:</strong> Соглашение активно с момента принятия пользователем до отзыва акцепта.</p>
|
||||
<p><strong>14.2. Право отзыва:</strong> Владелец может отозвать оферту согласно ст. 436 ГК РФ.</p>
|
||||
</section>
|
||||
|
||||
<section class="info-card">
|
||||
<section class="info-card wide">
|
||||
<div class="card-icon">⚡</div>
|
||||
<h2>15. Порядок разрешения споров</h2>
|
||||
<p><strong>15.1. Добровольное урегулирование:</strong> Обязательный досудебный порядок рассмотрения споров.</p>
|
||||
@@ -247,12 +251,12 @@
|
||||
<p><strong>16.3. Законодательство:</strong> Вопросы разрешаются по законодательству Армении.</p>
|
||||
<p><strong>16.4. Термин "Законодательство":</strong> Подразумевает законы Армении.</p>
|
||||
<p><strong>16.5. Бесплатные услуги:</strong> Не предполагают применение норм о защите прав потребителей.</p>
|
||||
<p><strong>16.6. Отсутствие отношений:</strong> Не устанавливают агентских связей, партнёрства или трудовых отношений.</p>
|
||||
<p><strong>16.6. Отсутствие отношений:</strong> Кроме агентской модели по п. 2.4, условия не устанавливают партнёрства, совместного предприятия или трудовых отношений.</p>
|
||||
<p><strong>16.7. Недействительность пунктов:</strong> Не влияет на законную силу остальных положений.</p>
|
||||
<p><strong>16.8. Реакция на нарушения:</strong> Невмешательство не препятствует последующим мерам защиты.</p>
|
||||
</section>
|
||||
|
||||
<section class="info-card">
|
||||
<section class="info-card wide">
|
||||
<div class="card-icon">📞</div>
|
||||
<h2>Контакты</h2>
|
||||
<p>Вопросы по соглашению:</p>
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
<p>1.5. Digital products are returned under special rules prescribed by legislation.</p>
|
||||
</section>
|
||||
|
||||
<section class="info-card">
|
||||
<section class="info-card wide">
|
||||
<div class="card-icon">📅</div>
|
||||
<h2>2. Time Frames</h2>
|
||||
<p><strong>2.1. Quality products:</strong></p>
|
||||
@@ -112,7 +112,7 @@
|
||||
<p>Our platform is always ready to help resolve disputes.</p>
|
||||
</section>
|
||||
|
||||
<section class="info-card">
|
||||
<section class="info-card wide">
|
||||
<div class="card-icon">💰</div>
|
||||
<h2>6. Payment Refund</h2>
|
||||
<p>Funds are refunded to the same payment method:</p>
|
||||
@@ -134,14 +134,14 @@
|
||||
<p>The customer has the right to claim compensation for defective products and shipping costs.</p>
|
||||
</section>
|
||||
|
||||
<section class="info-card">
|
||||
<section class="info-card wide">
|
||||
<div class="card-icon">🔄</div>
|
||||
<h2>7. Product Exchange</h2>
|
||||
<p>If a non-defective product does not match in dimensions, size, or specifications, the customer may exchange it with the supplier for a suitable option.</p>
|
||||
<p>If the desired model is unavailable, the customer has the right to cancel the order and receive a refund.</p>
|
||||
</section>
|
||||
|
||||
<section class="info-card">
|
||||
<section class="info-card wide">
|
||||
<div class="card-icon">🛡️</div>
|
||||
<h2>8. Warranty Service</h2>
|
||||
<p>Warranty information is displayed on the product page or available from the seller.</p>
|
||||
@@ -149,7 +149,7 @@
|
||||
<p>Warranty service does not cover physical damage, improper use, or unauthorized modifications.</p>
|
||||
</section>
|
||||
|
||||
<section class="info-card">
|
||||
<section class="info-card wide">
|
||||
<div class="card-icon">⚖️</div>
|
||||
<h2>9. Responsibilities of Parties</h2>
|
||||
<p>The supplier is responsible for product quality and timely refunds.</p>
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
<p>1.5. Թվային ապրանքները վերադարձվում են օրենսդրությամբ նախատեսված հատուկ կանոններով։</p>
|
||||
</section>
|
||||
|
||||
<section class="info-card">
|
||||
<section class="info-card wide">
|
||||
<div class="card-icon">📅</div>
|
||||
<h2>2. Ժամանակային սահմաններ</h2>
|
||||
<p><strong>2.1. Որակյալ ապրանքներ՝</strong></p>
|
||||
@@ -112,7 +112,7 @@
|
||||
<p>Մեր հարթակը միշտ պատրաստ է օգնել վիճելի իրավիճակների կարգավորման հարցում։</p>
|
||||
</section>
|
||||
|
||||
<section class="info-card">
|
||||
<section class="info-card wide">
|
||||
<div class="card-icon">💰</div>
|
||||
<h2>6. Վճարման փոխհատուցում</h2>
|
||||
<p>Գումարը վերադարձվում է նույն վճարման եղանակով՝</p>
|
||||
@@ -134,14 +134,14 @@
|
||||
<p>Գնորդը իրավունք ունի պահանջել փոխհատուցում անորակ ապրանքների և առաքման ծախսերի համար։</p>
|
||||
</section>
|
||||
|
||||
<section class="info-card">
|
||||
<section class="info-card wide">
|
||||
<div class="card-icon">🔄</div>
|
||||
<h2>7. Ապրանքի փոխանակում</h2>
|
||||
<p>Եթե որակյալ ապրանքը չի համապատասխանում չափսերով, չափորոշներով կամ հատկանիշներով, գնորդը կարող է այն փոխանակել մատակարարի մոտ համապատասխան տարբերակով։</p>
|
||||
<p>Համապատասխան մոդելի բացակայության դեպքում գնորդը կարող է հրաժարվել պատվերից և ստանալ փոխհատուցում։</p>
|
||||
</section>
|
||||
|
||||
<section class="info-card">
|
||||
<section class="info-card wide">
|
||||
<div class="card-icon">🛡️</div>
|
||||
<h2>8. Երաշխիքային սպասարկում</h2>
|
||||
<p>Երաշխիքի պայմանները նշված են ապրանքի էջում կամ հասանելի են վաճառողից։</p>
|
||||
@@ -149,7 +149,7 @@
|
||||
<p>Երաշխիքային սպասարկումը չի տարածվում ֆիզիկական վնասների, ոչ պատշաճ օգտագործման կամ ինքնուրույն միջամտության դեպքում։</p>
|
||||
</section>
|
||||
|
||||
<section class="info-card">
|
||||
<section class="info-card wide">
|
||||
<div class="card-icon">⚖️</div>
|
||||
<h2>9. Կողմերի պարտականություններ</h2>
|
||||
<p>Մատակարարը պատասխանատու է ապրանքի որակի և ժամանակային գումարի վերադարձի համար։</p>
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
<p>1.5. Электронные товары возвращаются по специальным правилам, прописанным в законодательстве.</p>
|
||||
</section>
|
||||
|
||||
<section class="info-card">
|
||||
<section class="info-card wide">
|
||||
<div class="card-icon">📅</div>
|
||||
<h2>2. Временные рамки</h2>
|
||||
<p><strong>2.1. Качественная продукция:</strong></p>
|
||||
@@ -112,7 +112,7 @@
|
||||
<p>Наша площадка всегда готова помочь в урегулировании спорных ситуаций.</p>
|
||||
</section>
|
||||
|
||||
<section class="info-card">
|
||||
<section class="info-card wide">
|
||||
<div class="card-icon">💰</div>
|
||||
<h2>6. Компенсация платежа</h2>
|
||||
<p>Деньги возмещаются на тот же способ оплаты:</p>
|
||||
@@ -134,14 +134,14 @@
|
||||
<p>Клиент имеет право потребовать компенсацию за некачественную продукцию и расходы по пересылке.</p>
|
||||
</section>
|
||||
|
||||
<section class="info-card">
|
||||
<section class="info-card wide">
|
||||
<div class="card-icon">🔄</div>
|
||||
<h2>7. Обмен продукции</h2>
|
||||
<p>При несоответствии исправного изделия по габаритам, размерам или параметрам, клиент может заменить его у поставщика на подходящий вариант.</p>
|
||||
<p>При отсутствии нужной модели клиент вправе отказаться от заказа и получить компенсацию.</p>
|
||||
</section>
|
||||
|
||||
<section class="info-card">
|
||||
<section class="info-card wide">
|
||||
<div class="card-icon">🛡️</div>
|
||||
<h2>8. Сервисное обслуживание</h2>
|
||||
<p>Информация о гарантийных условиях размещена в карточке товара или доступна у продавца.</p>
|
||||
@@ -149,7 +149,7 @@
|
||||
<p>Гарантийное обслуживание не распространяется на физические ущербы, неправильное применение или самостоятельное вмешательство.</p>
|
||||
</section>
|
||||
|
||||
<section class="info-card">
|
||||
<section class="info-card wide">
|
||||
<div class="card-icon">⚖️</div>
|
||||
<h2>9. Обязанности участников</h2>
|
||||
<p>Поставщик несет ответственность за качество продукции и своевременное возмещение платежей.</p>
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
<div class="delivery-selector">
|
||||
@if (isDigital) {
|
||||
<div class="delivery-chip delivery-chip--digital">{{ 'cart.digitalDelivery' | translate }}</div>
|
||||
} @else if (options.length > 0) {
|
||||
<label class="delivery-label" [for]="selectId">{{ 'cart.deliveryMethod' | translate }}</label>
|
||||
|
||||
<div class="delivery-control">
|
||||
<select [id]="selectId" [ngModel]="selectedKey" (ngModelChange)="onSelectionChange($event)">
|
||||
@if (required) {
|
||||
<option value="">{{ 'cart.selectDelivery' | translate }}</option>
|
||||
}
|
||||
|
||||
@for (option of options; track trackByOption($index, option)) {
|
||||
<option [value]="optionKey(option)">{{ optionLabel(option) }}</option>
|
||||
}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
@if (selectedDelivery) {
|
||||
<div class="delivery-meta">
|
||||
@if (selectedDelivery.deliveryPlace) {
|
||||
<span>{{ 'cart.deliveryPlace' | translate }}: {{ selectedDelivery.deliveryPlace }}</span>
|
||||
}
|
||||
@if (selectedDelivery.deliveryTime) {
|
||||
<span>{{ 'cart.deliveryTime' | translate }}: {{ selectedDelivery.deliveryTime }}</span>
|
||||
}
|
||||
<span>
|
||||
{{ 'cart.deliveryLabel' | translate }}:
|
||||
{{ selectedDeliveryTotal | number:'1.2-2' }} {{ currency }}
|
||||
</span>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
</div>
|
||||
@@ -0,0 +1,81 @@
|
||||
:host {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.delivery-selector {
|
||||
margin-top: 12px;
|
||||
padding: 12px;
|
||||
border-radius: 12px;
|
||||
border: 1px solid #d3dad9;
|
||||
background: #fafbfb;
|
||||
}
|
||||
|
||||
.delivery-label {
|
||||
display: block;
|
||||
margin-bottom: 8px;
|
||||
font-size: 0.8rem;
|
||||
font-weight: 700;
|
||||
color: #3f5f5c;
|
||||
}
|
||||
|
||||
.delivery-control select {
|
||||
width: 100%;
|
||||
padding: 10px 12px;
|
||||
border-radius: 10px;
|
||||
border: 1px solid #c9d5d3;
|
||||
background: #fff;
|
||||
color: #1f2937;
|
||||
font-size: 0.9rem;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.delivery-control select:focus {
|
||||
outline: none;
|
||||
border-color: #497671;
|
||||
box-shadow: 0 0 0 3px rgba(73, 118, 113, 0.12);
|
||||
}
|
||||
|
||||
.delivery-meta {
|
||||
display: grid;
|
||||
gap: 4px;
|
||||
margin-top: 10px;
|
||||
font-size: 0.82rem;
|
||||
color: #697777;
|
||||
line-height: 1.45;
|
||||
}
|
||||
|
||||
.delivery-chip {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
padding: 6px 10px;
|
||||
border-radius: 999px;
|
||||
font-size: 0.8rem;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.delivery-chip--digital {
|
||||
color: #2563eb;
|
||||
background: rgba(37, 99, 235, 0.12);
|
||||
}
|
||||
|
||||
:host-context(.cart-container.novo) .delivery-selector {
|
||||
border-color: #d1fae5;
|
||||
background: #f9fffc;
|
||||
}
|
||||
|
||||
:host-context(.cart-container.novo) .delivery-label {
|
||||
color: #047857;
|
||||
}
|
||||
|
||||
:host-context(.cart-container.novo) .delivery-control select {
|
||||
border-color: #bbf7d0;
|
||||
}
|
||||
|
||||
:host-context(.cart-container.novo) .delivery-control select:focus {
|
||||
border-color: #10b981;
|
||||
box-shadow: 0 0 0 3px rgba(16, 185, 129, 0.12);
|
||||
}
|
||||
|
||||
:host-context(.cart-container.novo) .delivery-meta {
|
||||
color: #4b5563;
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
import { ChangeDetectionStrategy, Component, EventEmitter, Input, Output } from '@angular/core';
|
||||
import { DecimalPipe } from '@angular/common';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { CartItem, DeliveryOption } from '../../models';
|
||||
import { TranslatePipe } from '../../i18n/translate.pipe';
|
||||
|
||||
let nextDeliverySelectorId = 0;
|
||||
|
||||
@Component({
|
||||
selector: 'app-delivery-selector',
|
||||
standalone: true,
|
||||
imports: [FormsModule, DecimalPipe, TranslatePipe],
|
||||
templateUrl: './delivery-selector.component.html',
|
||||
styleUrls: ['./delivery-selector.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush
|
||||
})
|
||||
export class DeliverySelectorComponent {
|
||||
@Input({ required: true }) item: CartItem | null = null;
|
||||
|
||||
@Output() selectedDeliveryChange = new EventEmitter<DeliveryOption | null>();
|
||||
|
||||
readonly selectId = `delivery-select-${nextDeliverySelectorId++}`;
|
||||
|
||||
get options(): DeliveryOption[] {
|
||||
return this.item?.deliveryOptions ?? [];
|
||||
}
|
||||
|
||||
get selectedDelivery(): DeliveryOption | null {
|
||||
return this.item?.selectedDelivery ?? null;
|
||||
}
|
||||
|
||||
get currency(): string {
|
||||
return this.item?.currency || 'RUB';
|
||||
}
|
||||
|
||||
get required(): boolean {
|
||||
return this.item?.deliveryMode !== 'digital'
|
||||
&& this.options.length > 0
|
||||
&& this.item?.deliverySelectionRequired !== false;
|
||||
}
|
||||
|
||||
get isDigital(): boolean {
|
||||
return this.item?.deliveryMode === 'digital';
|
||||
}
|
||||
|
||||
get selectedKey(): string {
|
||||
return this.selectedDelivery ? this.optionKey(this.selectedDelivery) : '';
|
||||
}
|
||||
|
||||
get selectedDeliveryTotal(): number {
|
||||
return (this.selectedDelivery?.deliveryPrice ?? 0) * (this.item?.quantity ?? 1);
|
||||
}
|
||||
|
||||
optionKey(option: DeliveryOption): string {
|
||||
return `${option.deliveryPlace}__${option.deliveryTime}__${option.deliveryPrice}`;
|
||||
}
|
||||
|
||||
optionLabel(option: DeliveryOption): string {
|
||||
const details = [option.deliveryPlace, option.deliveryTime].filter(Boolean);
|
||||
details.push(`${option.deliveryPrice.toFixed(2)} ${this.currency}`);
|
||||
return details.join(' • ');
|
||||
}
|
||||
|
||||
trackByOption(index: number, option: DeliveryOption): string {
|
||||
return `${index}-${this.optionKey(option)}`;
|
||||
}
|
||||
|
||||
onSelectionChange(nextKey: string): void {
|
||||
if (!nextKey) {
|
||||
this.selectedDeliveryChange.emit(null);
|
||||
return;
|
||||
}
|
||||
|
||||
this.selectedDeliveryChange.emit(
|
||||
this.options.find(option => this.optionKey(option) === nextKey) ?? null
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,7 @@
|
||||
<header class="novo-header">
|
||||
<div class="novo-header-container">
|
||||
<div class="novo-left">
|
||||
<a [routerLink]="'/' | langRoute" class="novo-logo" (click)="closeMenu()">
|
||||
<a [attr.href]="homeUrl" class="novo-logo" (click)="navigateHome($event)">
|
||||
<app-logo />
|
||||
<!-- <span class="novo-brand">{{ brandName }}</span> -->
|
||||
</a>
|
||||
@@ -24,6 +24,11 @@
|
||||
{{ 'header.contacts' | translate }}
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="novo-mobile-controls">
|
||||
<app-region-selector />
|
||||
<app-language-selector />
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div class="novo-right">
|
||||
@@ -31,6 +36,7 @@
|
||||
<app-language-selector />
|
||||
|
||||
<a [routerLink]="'/cart' | langRoute" routerLinkActive="novo-cart-active" class="novo-cart" (click)="closeMenu()" [attr.aria-label]="'header.cart' | translate">
|
||||
<span class="novo-cart-icon">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true">
|
||||
<circle cx="9" cy="21" r="1"></circle>
|
||||
<circle cx="20" cy="21" r="1"></circle>
|
||||
@@ -39,9 +45,13 @@
|
||||
@if (cartItemCount() > 0) {
|
||||
<span class="novo-cart-badge">{{ cartItemCount() }}</span>
|
||||
}
|
||||
</span>
|
||||
@if (cartItemCount() > 0) {
|
||||
<span class="novo-cart-total">{{ formatCartTotal(cartTotal()) }}</span>
|
||||
}
|
||||
</a>
|
||||
|
||||
<button class="menu-toggle" (click)="toggleMenu()" [class.active]="menuOpen" [attr.aria-label]="menuOpen ? 'Close menu' : 'Open menu'" [attr.aria-expanded]="menuOpen">
|
||||
<button class="menu-toggle novo-menu-toggle" (click)="toggleMenu()" [class.active]="menuOpen" [class.novo-active]="menuOpen" [attr.aria-label]="menuOpen ? 'Close menu' : 'Open menu'" [attr.aria-expanded]="menuOpen">
|
||||
<span></span>
|
||||
<span></span>
|
||||
<span></span>
|
||||
@@ -54,7 +64,7 @@
|
||||
<header class="dexar-header">
|
||||
<div class="dexar-header-container">
|
||||
<!-- Logo -->
|
||||
<a [routerLink]="'/' | langRoute" class="dexar-logo" (click)="closeMenu()">
|
||||
<a [attr.href]="homeUrl" class="dexar-logo" (click)="navigateHome($event)">
|
||||
<app-logo />
|
||||
</a>
|
||||
|
||||
@@ -97,6 +107,7 @@
|
||||
<div class="dexar-actions">
|
||||
<!-- Cart Button -->
|
||||
<a [routerLink]="'/cart' | langRoute" routerLinkActive="dexar-cart-active" class="dexar-cart-btn" (click)="closeMenu()">
|
||||
<span class="dexar-cart-icon">
|
||||
<svg width="32" height="24" viewBox="0 0 48 32" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M12 0.5H36C42.3513 0.5 47.5 5.64873 47.5 12V20C47.5 26.3513 42.3513 31.5 36 31.5H12C5.64873 31.5 0.5 26.3513 0.5 20V12C0.5 5.64873 5.64873 0.5 12 0.5Z" fill="transparent" />
|
||||
<path d="M12 0.5H36C42.3513 0.5 47.5 5.64873 47.5 12V20C47.5 26.3513 42.3513 31.5 36 31.5H12C5.64873 31.5 0.5 26.3513 0.5 20V12C0.5 5.64873 5.64873 0.5 12 0.5Z" stroke="#677B78" />
|
||||
@@ -105,6 +116,10 @@
|
||||
@if (cartItemCount() > 0) {
|
||||
<span class="dexar-cart-badge">{{ cartItemCount() }}</span>
|
||||
}
|
||||
</span>
|
||||
@if (cartItemCount() > 0) {
|
||||
<span class="dexar-cart-total">{{ formatCartTotal(cartTotal()) }}</span>
|
||||
}
|
||||
</a>
|
||||
|
||||
<!-- Region Selector (desktop only) -->
|
||||
@@ -177,14 +192,13 @@
|
||||
</svg>
|
||||
</a>
|
||||
|
||||
<!-- Region Selector in mobile menu -->
|
||||
<div class="dexar-mobile-controls">
|
||||
<div class="dexar-mobile-lang">
|
||||
<app-region-selector />
|
||||
</div>
|
||||
|
||||
<!-- Language Selector in mobile menu -->
|
||||
<div class="dexar-mobile-lang">
|
||||
<app-language-selector />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
@@ -328,23 +328,39 @@
|
||||
gap: 1.5rem;
|
||||
}
|
||||
|
||||
.novo-mobile-controls {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.novo-cart {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 0.2rem;
|
||||
color: var(--text-primary);
|
||||
text-decoration: none;
|
||||
padding: 0.5rem;
|
||||
border-radius: var(--radius-md);
|
||||
transition: all 0.3s;
|
||||
|
||||
svg {
|
||||
display: block;
|
||||
}
|
||||
|
||||
&:hover,
|
||||
&.novo-cart-active {
|
||||
color: var(--primary-color);
|
||||
background: var(--bg-secondary);
|
||||
}
|
||||
}
|
||||
|
||||
.novo-cart-icon {
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
line-height: 0;
|
||||
|
||||
svg {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
.novo-cart-badge {
|
||||
position: absolute;
|
||||
@@ -363,6 +379,12 @@
|
||||
padding: 0 5px;
|
||||
box-shadow: var(--shadow-sm);
|
||||
}
|
||||
|
||||
.novo-cart-total {
|
||||
font-size: 0.68rem;
|
||||
font-weight: 700;
|
||||
line-height: 1;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.novo-menu-toggle {
|
||||
@@ -409,7 +431,8 @@
|
||||
transition: max-height 0.3s;
|
||||
|
||||
&.novo-nav-open {
|
||||
max-height: 300px;
|
||||
max-height: calc(100dvh - 65px);
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.novo-nav-links {
|
||||
@@ -435,6 +458,25 @@
|
||||
}
|
||||
}
|
||||
|
||||
.novo-right {
|
||||
flex: 0 0 auto;
|
||||
gap: 0.75rem;
|
||||
}
|
||||
|
||||
.novo-right > app-region-selector,
|
||||
.novo-right > app-language-selector {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.novo-mobile-controls {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
padding: 1rem 2rem 1.25rem;
|
||||
border-top: 1px solid var(--border-color);
|
||||
}
|
||||
|
||||
.novo-menu-toggle {
|
||||
display: flex;
|
||||
}
|
||||
@@ -468,7 +510,7 @@
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 32px;
|
||||
height: 48px;
|
||||
min-height: 48px;
|
||||
}
|
||||
|
||||
.dexar-logo {
|
||||
@@ -591,15 +633,15 @@
|
||||
}
|
||||
|
||||
.dexar-cart-btn {
|
||||
position: relative;
|
||||
width: 36px;
|
||||
height: 28px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-width: 36px;
|
||||
text-decoration: none;
|
||||
cursor: pointer;
|
||||
transition: opacity 0.3s ease;
|
||||
gap: 2px;
|
||||
|
||||
svg {
|
||||
width: 36px;
|
||||
@@ -615,6 +657,15 @@
|
||||
}
|
||||
}
|
||||
|
||||
.dexar-cart-icon {
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 36px;
|
||||
height: 28px;
|
||||
}
|
||||
|
||||
.dexar-cart-badge {
|
||||
position: absolute;
|
||||
top: -8px;
|
||||
@@ -634,6 +685,15 @@
|
||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
.dexar-cart-total {
|
||||
font-family: "DM Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
|
||||
font-weight: 700;
|
||||
font-size: 10px;
|
||||
line-height: 1;
|
||||
color: #1e3c38;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.dexar-lang-selector {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@@ -714,10 +774,20 @@
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-top: 16px;
|
||||
}
|
||||
|
||||
.dexar-mobile-controls {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
width: 100%;
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
.dexar-menu-toggle {
|
||||
position: relative;
|
||||
z-index: 1001;
|
||||
display: none;
|
||||
flex-direction: column;
|
||||
gap: 5px;
|
||||
@@ -841,7 +911,7 @@
|
||||
|
||||
// Hide desktop language selector
|
||||
.dexar-lang-desktop {
|
||||
display: none;
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.dexar-search-wrapper {
|
||||
@@ -903,9 +973,10 @@
|
||||
transition: max-height 0.35s ease, opacity 0.25s ease, padding 0.35s ease;
|
||||
|
||||
&.dexar-mobile-menu-open {
|
||||
max-height: 700px;
|
||||
max-height: calc(100dvh - 84px);
|
||||
padding: 28px 20px 32px;
|
||||
opacity: 1;
|
||||
overflow-y: auto;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -914,8 +985,8 @@
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.dexar-mobile-lang {
|
||||
margin-top: 16px;
|
||||
.dexar-mobile-controls {
|
||||
margin-top: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { Component, ChangeDetectionStrategy, Renderer2, inject, DOCUMENT } from '@angular/core';
|
||||
import { Router, RouterLink, RouterLinkActive } from '@angular/router';
|
||||
import { CartService, LanguageService } from '../../services';
|
||||
import { CartService } from '../../services/cart.service';
|
||||
import { LanguageService } from '../../services/language.service';
|
||||
import { environment } from '../../../environments/environment';
|
||||
import { LogoComponent } from '../logo/logo.component';
|
||||
import { LanguageSelectorComponent } from '../language-selector/language-selector.component';
|
||||
@@ -17,6 +18,7 @@ import { TranslatePipe } from '../../i18n/translate.pipe';
|
||||
})
|
||||
export class HeaderComponent {
|
||||
cartItemCount;
|
||||
cartTotal;
|
||||
menuOpen = false;
|
||||
brandName = environment.brandFullName;
|
||||
logo = environment.logo;
|
||||
@@ -28,6 +30,11 @@ export class HeaderComponent {
|
||||
|
||||
constructor(private cartService: CartService, private router: Router) {
|
||||
this.cartItemCount = this.cartService.itemCount;
|
||||
this.cartTotal = this.cartService.totalPrice;
|
||||
}
|
||||
|
||||
get homeUrl(): string {
|
||||
return `/${this.langService.currentLanguage()}`;
|
||||
}
|
||||
|
||||
toggleMenu(): void {
|
||||
@@ -44,6 +51,23 @@ export class HeaderComponent {
|
||||
this.renderer.removeClass(this.document.body, 'dexar-menu-open');
|
||||
}
|
||||
|
||||
navigateHome(event?: Event): void {
|
||||
event?.preventDefault();
|
||||
this.closeMenu();
|
||||
|
||||
const homeUrl = this.homeUrl;
|
||||
const currentUrl = this.router.url.split('?')[0].split('#')[0];
|
||||
|
||||
if (currentUrl === homeUrl || currentUrl === `${homeUrl}/`) {
|
||||
this.document.defaultView?.scrollTo({ top: 0, behavior: 'smooth' });
|
||||
return;
|
||||
}
|
||||
|
||||
this.router.navigateByUrl(homeUrl).then(() => {
|
||||
this.document.defaultView?.scrollTo({ top: 0, behavior: 'auto' });
|
||||
});
|
||||
}
|
||||
|
||||
navigateToSearch(): void {
|
||||
const lang = this.langService.currentLanguage();
|
||||
this.router.navigate([`/${lang}/search`]);
|
||||
@@ -58,4 +82,20 @@ export class HeaderComponent {
|
||||
}, 100);
|
||||
});
|
||||
}
|
||||
|
||||
formatCartTotal(total: number): string {
|
||||
const locale = this.langService.currentLanguage() === 'en'
|
||||
? 'en-US'
|
||||
: this.langService.currentLanguage() === 'hy'
|
||||
? 'hy-AM'
|
||||
: 'ru-RU';
|
||||
const fractionDigits = Number.isInteger(total) ? 0 : 2;
|
||||
const amount = new Intl.NumberFormat(locale, {
|
||||
minimumFractionDigits: fractionDigits,
|
||||
maximumFractionDigits: 2,
|
||||
}).format(total);
|
||||
const currencySymbol = this.langService.getCurrentCurrency()?.symbol ?? this.langService.currentCurrency();
|
||||
|
||||
return `${amount} ${currencySymbol}`;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -262,13 +262,17 @@
|
||||
// Inside mobile menu: use inline dropdown instead of absolute
|
||||
// to avoid being clipped by overflow: hidden on the menu panel
|
||||
:host-context(.dexar-mobile-menu),
|
||||
:host-context(.dexar-mobile-lang) {
|
||||
:host-context(.dexar-mobile-lang),
|
||||
:host-context(.novo-mobile-controls) {
|
||||
.language-selector {
|
||||
width: auto;
|
||||
height: auto;
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.language-dropdown {
|
||||
.language-dropdown,
|
||||
.currency-dropdown {
|
||||
position: static;
|
||||
opacity: 1;
|
||||
visibility: hidden;
|
||||
@@ -289,7 +293,8 @@
|
||||
}
|
||||
}
|
||||
|
||||
.language-option {
|
||||
.language-option,
|
||||
.currency-option {
|
||||
color: #1e3c38;
|
||||
|
||||
&:hover:not(.disabled) {
|
||||
|
||||
@@ -3,17 +3,20 @@ import { environment } from '../../../environments/environment';
|
||||
|
||||
@Component({
|
||||
selector: 'app-logo',
|
||||
template: `<img [src]="logoPath" [alt]="brandName + ' logo'" class="logo-img" fetchpriority="high" />`,
|
||||
template: `<img [src]="logoPath" [alt]="brandName + ' logo'" class="logo-img" fetchpriority="high" draggable="false" />`,
|
||||
styles: [`
|
||||
.logo-img {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: contain;
|
||||
pointer-events: none;
|
||||
user-select: none;
|
||||
}
|
||||
`],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush
|
||||
})
|
||||
export class LogoComponent {
|
||||
brandName = environment.brandName;
|
||||
logoPath = `/assets/images/${environment.theme}-logo.svg`;
|
||||
logoPath = (environment as any).logo ?? `/assets/images/${environment.theme}-logo.svg`;
|
||||
}
|
||||
|
||||
@@ -29,6 +29,12 @@
|
||||
{{ 'auth.loginWithTelegram' | translate }}
|
||||
</button>
|
||||
|
||||
<!-- @if (loginUrl()) {
|
||||
<a class="bot-link" [href]="loginUrl()" target="_blank" rel="noopener noreferrer">
|
||||
{{ loginUrl() }}
|
||||
</a>
|
||||
} -->
|
||||
|
||||
<div class="qr-section">
|
||||
<p class="qr-hint">{{ 'auth.orScanQr' | translate }}</p>
|
||||
|
||||
@@ -57,12 +63,12 @@
|
||||
</div>
|
||||
}
|
||||
@case ('error') {
|
||||
<div class="qr-container">
|
||||
<img [src]="'https://api.qrserver.com/v1/create-qr-code/?size=180x180&data=' + encodedQrUrl()"
|
||||
alt="QR Code"
|
||||
width="180"
|
||||
height="180"
|
||||
loading="lazy" />
|
||||
<div class="qr-container qr-error" (click)="refreshQr()">
|
||||
<svg width="32" height="32" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<path d="M1 4v6h6M23 20v-6h-6"/>
|
||||
<path d="M20.49 9A9 9 0 0 0 5.64 5.64L1 10m22 4l-4.64 4.36A9 9 0 0 1 3.51 15"/>
|
||||
</svg>
|
||||
<span>{{ 'auth.qrError' | translate }}</span>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
|
||||
@@ -102,6 +102,20 @@ h2 {
|
||||
}
|
||||
}
|
||||
|
||||
.bot-link {
|
||||
display: block;
|
||||
margin-top: 10px;
|
||||
color: var(--accent-color, #497671);
|
||||
font-size: 12px;
|
||||
line-height: 1.35;
|
||||
overflow-wrap: anywhere;
|
||||
text-decoration: none;
|
||||
|
||||
&:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
|
||||
.qr-section {
|
||||
margin-top: 20px;
|
||||
|
||||
@@ -158,6 +172,26 @@ h2 {
|
||||
font-size: 13px;
|
||||
}
|
||||
}
|
||||
|
||||
&.qr-error {
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 8px;
|
||||
width: 204px;
|
||||
height: 204px;
|
||||
cursor: pointer;
|
||||
color: var(--text-secondary, #999);
|
||||
transition: color 0.2s ease;
|
||||
|
||||
&:hover {
|
||||
color: var(--accent-color, #497671);
|
||||
}
|
||||
|
||||
span {
|
||||
font-size: 13px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
import { Component, ChangeDetectionStrategy, inject, signal, computed, effect, OnDestroy } from '@angular/core';
|
||||
import { AuthService } from '../../services/auth.service';
|
||||
import { CartService } from '../../services/cart.service';
|
||||
import { TranslatePipe } from '../../i18n/translate.pipe';
|
||||
import { getDiscountedPrice } from '../../utils/item.utils';
|
||||
|
||||
@Component({
|
||||
selector: 'app-telegram-login',
|
||||
@@ -13,92 +11,104 @@ import { getDiscountedPrice } from '../../utils/item.utils';
|
||||
})
|
||||
export class TelegramLoginComponent implements OnDestroy {
|
||||
private authService = inject(AuthService);
|
||||
private cartService = inject(CartService);
|
||||
|
||||
showDialog = this.authService.showLoginDialog;
|
||||
status = this.authService.status;
|
||||
|
||||
loginUrl = signal('');
|
||||
qrToken = signal('');
|
||||
webSessionID = signal('');
|
||||
qrStatus = signal<'loading' | 'ready' | 'expired' | 'error'>('loading');
|
||||
encodedQrUrl = computed(() => encodeURIComponent(this.loginUrl()));
|
||||
awaitingTelegramReturn = signal(false);
|
||||
|
||||
private readonly pollIntervalMs = 5000;
|
||||
private pollTimer?: ReturnType<typeof setInterval>;
|
||||
private readonly handleVisibilityChange = () => {
|
||||
if (typeof document !== 'undefined' && document.visibilityState === 'visible') {
|
||||
this.checkLoginAfterReturn();
|
||||
}
|
||||
};
|
||||
private readonly handleWindowFocus = () => {
|
||||
this.checkLoginAfterReturn();
|
||||
};
|
||||
private readonly handlePageShow = () => {
|
||||
this.checkLoginAfterReturn();
|
||||
};
|
||||
|
||||
constructor() {
|
||||
effect(() => {
|
||||
if (this.showDialog()) {
|
||||
this.initQrLogin();
|
||||
} else {
|
||||
this.awaitingTelegramReturn.set(false);
|
||||
this.stopPolling();
|
||||
}
|
||||
});
|
||||
|
||||
if (typeof window !== 'undefined') {
|
||||
document.addEventListener('visibilitychange', this.handleVisibilityChange);
|
||||
window.addEventListener('focus', this.handleWindowFocus);
|
||||
window.addEventListener('pageshow', this.handlePageShow);
|
||||
}
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
this.awaitingTelegramReturn.set(false);
|
||||
this.stopPolling();
|
||||
|
||||
if (typeof window !== 'undefined') {
|
||||
document.removeEventListener('visibilitychange', this.handleVisibilityChange);
|
||||
window.removeEventListener('focus', this.handleWindowFocus);
|
||||
window.removeEventListener('pageshow', this.handlePageShow);
|
||||
}
|
||||
}
|
||||
|
||||
close(): void {
|
||||
this.awaitingTelegramReturn.set(false);
|
||||
this.authService.hideLogin();
|
||||
this.stopPolling();
|
||||
}
|
||||
|
||||
openTelegramLogin(): void {
|
||||
window.open(this.loginUrl(), '_blank');
|
||||
const webSessionID = this.webSessionID();
|
||||
if (!webSessionID || typeof window === 'undefined') return;
|
||||
|
||||
if (!this.pollTimer) {
|
||||
if (this.qrToken()) {
|
||||
this.startPolling(this.qrToken());
|
||||
} else {
|
||||
this.startSessionPolling();
|
||||
}
|
||||
this.startPolling(webSessionID);
|
||||
}
|
||||
|
||||
this.awaitingTelegramReturn.set(true);
|
||||
window.location.href = this.authService.getTelegramAppLoginUrl(webSessionID);
|
||||
}
|
||||
|
||||
refreshQr(): void {
|
||||
this.awaitingTelegramReturn.set(false);
|
||||
this.stopPolling();
|
||||
this.initQrLogin();
|
||||
}
|
||||
|
||||
private initQrLogin(): void {
|
||||
this.awaitingTelegramReturn.set(false);
|
||||
this.qrStatus.set('loading');
|
||||
this.authService.createQrToken().subscribe({
|
||||
this.loginUrl.set('');
|
||||
this.webSessionID.set('');
|
||||
|
||||
this.authService.createWebSession().subscribe({
|
||||
next: (res) => {
|
||||
this.loginUrl.set(res.url);
|
||||
this.qrToken.set(res.token);
|
||||
this.webSessionID.set(res.webSessionID);
|
||||
this.qrStatus.set('ready');
|
||||
this.startPolling(res.token);
|
||||
this.startPolling(res.webSessionID);
|
||||
},
|
||||
error: () => {
|
||||
this.loginUrl.set(this.authService.getTelegramLoginUrl());
|
||||
this.qrStatus.set('error');
|
||||
this.startSessionPolling();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private startSessionPolling(): void {
|
||||
private startPolling(webSessionID: string): void {
|
||||
this.stopPolling();
|
||||
let checks = 0;
|
||||
this.pollTimer = setInterval(() => {
|
||||
checks++;
|
||||
if (checks > 100) {
|
||||
this.stopPolling();
|
||||
this.qrStatus.set('expired');
|
||||
return;
|
||||
}
|
||||
this.authService.checkSessionOnce().subscribe(session => {
|
||||
if (session && session.active) {
|
||||
this.stopPolling();
|
||||
this.syncCartAndComplete(session.sessionId);
|
||||
}
|
||||
});
|
||||
}, 3000);
|
||||
}
|
||||
|
||||
private startPolling(token: string): void {
|
||||
this.stopPolling();
|
||||
if (!token) return;
|
||||
if (!webSessionID) return;
|
||||
|
||||
let checks = 0;
|
||||
this.pollTimer = setInterval(() => {
|
||||
@@ -109,44 +119,19 @@ export class TelegramLoginComponent implements OnDestroy {
|
||||
return;
|
||||
}
|
||||
|
||||
this.authService.pollQrToken(token).subscribe({
|
||||
next: (res) => {
|
||||
switch (res.status) {
|
||||
case 'confirmed':
|
||||
this.authService.checkSessionOnce(webSessionID).subscribe({
|
||||
next: (session) => {
|
||||
if (session?.active) {
|
||||
this.awaitingTelegramReturn.set(false);
|
||||
this.stopPolling();
|
||||
if (res.session) {
|
||||
this.syncCartAndComplete(res.session.sessionId);
|
||||
} else {
|
||||
this.authService.onTelegramLoginComplete();
|
||||
}
|
||||
break;
|
||||
case 'expired':
|
||||
this.stopPolling();
|
||||
this.qrStatus.set('expired');
|
||||
break;
|
||||
}
|
||||
},
|
||||
error: () => {
|
||||
// Network error — keep polling
|
||||
}
|
||||
});
|
||||
}, 3000);
|
||||
}
|
||||
|
||||
private syncCartAndComplete(sessionId: string): void {
|
||||
const cartItems = this.cartService.items().map(item => ({
|
||||
itemID: item.itemID,
|
||||
quantity: item.quantity,
|
||||
colour: item.colour || '',
|
||||
size: item.size || '',
|
||||
price: item.discount > 0
|
||||
? item.price * (1 - item.discount / 100)
|
||||
: item.price,
|
||||
}));
|
||||
|
||||
this.authService.syncCart(sessionId, cartItems).subscribe(() => {
|
||||
this.authService.onTelegramLoginComplete();
|
||||
});
|
||||
}, this.pollIntervalMs);
|
||||
}
|
||||
|
||||
private stopPolling(): void {
|
||||
@@ -155,4 +140,28 @@ export class TelegramLoginComponent implements OnDestroy {
|
||||
this.pollTimer = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
private checkLoginAfterReturn(): void {
|
||||
if (!this.showDialog() || !this.awaitingTelegramReturn()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const webSessionID = this.webSessionID();
|
||||
if (!webSessionID) {
|
||||
this.awaitingTelegramReturn.set(false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.pollTimer) {
|
||||
this.startPolling(webSessionID);
|
||||
}
|
||||
|
||||
this.authService.checkSessionOnce(webSessionID).subscribe(session => {
|
||||
if (session?.active) {
|
||||
this.awaitingTelegramReturn.set(false);
|
||||
this.stopPolling();
|
||||
this.authService.onTelegramLoginComplete();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
export const PAYMENT_POLL_INTERVAL_MS = 5000;
|
||||
export const PAYMENT_MAX_CHECKS = 36;
|
||||
export const PAYMENT_TIMEOUT_CLOSE_MS = 3000;
|
||||
export const PAYMENT_ERROR_CLOSE_MS = 4000;
|
||||
export const LINK_COPIED_DURATION_MS = 2000;
|
||||
|
||||
// Infinite scroll
|
||||
@@ -12,7 +11,6 @@ export const ITEMS_PER_PAGE = 50;
|
||||
|
||||
// Search
|
||||
export const SEARCH_DEBOUNCE_MS = 300;
|
||||
export const SEARCH_MIN_LENGTH = 3;
|
||||
|
||||
// Cache
|
||||
export const CACHE_DURATION_MS = 5 * 60 * 1000;
|
||||
|
||||
@@ -64,6 +64,12 @@ export const en: Translations = {
|
||||
total: 'Total',
|
||||
items: 'Products',
|
||||
deliveryLabel: 'Delivery',
|
||||
deliveryMethod: 'Delivery option',
|
||||
selectDelivery: 'Select delivery option',
|
||||
deliveryPlace: 'Place',
|
||||
deliveryTime: 'Delivery time',
|
||||
digitalDelivery: 'Digital delivery',
|
||||
deliveryRequired: 'Select delivery for every shippable item before checkout.',
|
||||
toPay: 'To pay',
|
||||
agreeWith: 'I agree with the',
|
||||
publicOffer: 'public offer',
|
||||
@@ -85,6 +91,9 @@ export const en: Translations = {
|
||||
paymentSuccessDesc: 'Enter your contact details and we will send your purchase within a few minutes',
|
||||
sending: 'Sending...',
|
||||
send: 'Send',
|
||||
paymentError: 'Unable to create payment',
|
||||
paymentErrorDesc: 'We could not prepare the payment QR code right now. Please try again in a moment.',
|
||||
retryPayment: 'Try again',
|
||||
paymentTimeout: 'Payment timed out',
|
||||
paymentTimeoutDesc: 'We did not receive payment confirmation within 3 minutes.',
|
||||
autoClose: 'Window will close automatically...',
|
||||
@@ -206,5 +215,6 @@ export const en: Translations = {
|
||||
orScanQr: 'Or scan the QR code',
|
||||
loginNote: 'You will be redirected back after login',
|
||||
qrExpired: 'QR code expired. Click to refresh',
|
||||
qrError: 'Could not create login session. Click to retry',
|
||||
},
|
||||
};
|
||||
|
||||
@@ -64,6 +64,12 @@ export const hy: Translations = {
|
||||
total: 'Ընդամենը',
|
||||
items: 'Ապրանքներ',
|
||||
deliveryLabel: 'Առաքում',
|
||||
deliveryMethod: 'Առաքման տարբերակ',
|
||||
selectDelivery: 'Ընտրեք առաքման տարբերակը',
|
||||
deliveryPlace: 'Վայր',
|
||||
deliveryTime: 'Առաքման ժամկետ',
|
||||
digitalDelivery: 'Թվային առաքում',
|
||||
deliveryRequired: 'Մինչ պատվերը ձևակերպելը ընտրեք առաքումը բոլոր առաքվող ապրանքների համար։',
|
||||
toPay: 'Վճարման ենթակա',
|
||||
agreeWith: 'Ես համաձայն եմ',
|
||||
publicOffer: 'հանրային օֆերտայի',
|
||||
@@ -85,6 +91,9 @@ export const hy: Translations = {
|
||||
paymentSuccessDesc: 'Մուտքագրեք ձեր տվյալները, և մենք կուղարկենք գնումը մի քանի րոպեի ընթացքում',
|
||||
sending: 'Ուղարկվում է...',
|
||||
send: 'Ուղարկել',
|
||||
paymentError: 'Չհաջողվեց ստեղծել վճարումը',
|
||||
paymentErrorDesc: 'Այս պահին չհաջողվեց պատրաստել վճարման QR կոդը։ Խնդրում ենք մի փոքր հետո կրկին փորձել։',
|
||||
retryPayment: 'Փորձել կրկին',
|
||||
paymentTimeout: 'Ժամանակը սպառվեց',
|
||||
paymentTimeoutDesc: 'Մենք չստացանք վճարման հաստատում 3 րոպեի ընթացքում։',
|
||||
autoClose: 'Պատուհանը կփակվի ավտոմատ...',
|
||||
@@ -206,5 +215,6 @@ export const hy: Translations = {
|
||||
orScanQr: 'Կամ սքանավորեք QR կոդը',
|
||||
loginNote: 'Մուտքից հետո դուք կվերաուղղվեք',
|
||||
qrExpired: 'QR կոդը հնացել է։ Սեղմեք՝ թարմացնելու համար',
|
||||
qrError: 'Չհաջողվեց ստեղծել մուտքի սեսիա։ Սեղմեք՝ կրկնելու համար',
|
||||
},
|
||||
};
|
||||
|
||||
@@ -64,6 +64,12 @@ export const ru: Translations = {
|
||||
total: 'Итого',
|
||||
items: 'Товары',
|
||||
deliveryLabel: 'Доставка',
|
||||
deliveryMethod: 'Способ доставки',
|
||||
selectDelivery: 'Выберите способ доставки',
|
||||
deliveryPlace: 'Место',
|
||||
deliveryTime: 'Срок доставки',
|
||||
digitalDelivery: 'Цифровая доставка',
|
||||
deliveryRequired: 'Выберите доставку для всех товаров с доставкой перед оформлением заказа.',
|
||||
toPay: 'К оплате',
|
||||
agreeWith: 'Я согласен с',
|
||||
publicOffer: 'публичной офертой',
|
||||
@@ -85,6 +91,9 @@ export const ru: Translations = {
|
||||
paymentSuccessDesc: 'Введите ваши контактные данные, и мы отправим вам покупку в течение нескольких минут',
|
||||
sending: 'Отправка...',
|
||||
send: 'Отправить',
|
||||
paymentError: 'Не удалось создать платеж',
|
||||
paymentErrorDesc: 'Сейчас не получилось подготовить QR-код для оплаты. Попробуйте еще раз через минуту.',
|
||||
retryPayment: 'Попробовать снова',
|
||||
paymentTimeout: 'Время ожидания истекло',
|
||||
paymentTimeoutDesc: 'Мы не получили подтверждение оплаты в течение 3 минут.',
|
||||
autoClose: 'Окно закроется автоматически...',
|
||||
@@ -206,5 +215,6 @@ export const ru: Translations = {
|
||||
orScanQr: 'Или отсканируйте QR-код',
|
||||
loginNote: 'После входа вы будете перенаправлены обратно',
|
||||
qrExpired: 'QR-код устарел. Нажмите, чтобы обновить',
|
||||
qrError: 'Не удалось создать сессию входа. Нажмите, чтобы повторить',
|
||||
},
|
||||
};
|
||||
|
||||
@@ -62,6 +62,12 @@ export interface Translations {
|
||||
total: string;
|
||||
items: string;
|
||||
deliveryLabel: string;
|
||||
deliveryMethod: string;
|
||||
selectDelivery: string;
|
||||
deliveryPlace: string;
|
||||
deliveryTime: string;
|
||||
digitalDelivery: string;
|
||||
deliveryRequired: string;
|
||||
toPay: string;
|
||||
agreeWith: string;
|
||||
publicOffer: string;
|
||||
@@ -83,6 +89,9 @@ export interface Translations {
|
||||
paymentSuccessDesc: string;
|
||||
sending: string;
|
||||
send: string;
|
||||
paymentError: string;
|
||||
paymentErrorDesc: string;
|
||||
retryPayment: string;
|
||||
paymentTimeout: string;
|
||||
paymentTimeoutDesc: string;
|
||||
autoClose: string;
|
||||
@@ -204,5 +213,6 @@ export interface Translations {
|
||||
orScanQr: string;
|
||||
loginNote: string;
|
||||
qrExpired: string;
|
||||
qrError: string;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -50,11 +50,6 @@ export const cacheInterceptor: HttpInterceptorFn = (req, next) => {
|
||||
);
|
||||
};
|
||||
|
||||
/** Clear all cached responses */
|
||||
export function clearCache(): void {
|
||||
cache.clear();
|
||||
}
|
||||
|
||||
function cleanupExpiredCache(): void {
|
||||
const now = Date.now();
|
||||
for (const [url, data] of cache.entries()) {
|
||||
|
||||
3
src/app/interceptors/mock-data.interceptor.production.ts
Normal file
3
src/app/interceptors/mock-data.interceptor.production.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
import { HttpInterceptorFn } from '@angular/common/http';
|
||||
|
||||
export const mockDataInterceptor: HttpInterceptorFn = (req, next) => next(req);
|
||||
@@ -615,6 +615,47 @@ const MOCK_ITEMS: any[] = [
|
||||
],
|
||||
questions: []
|
||||
},
|
||||
{
|
||||
id: 'bolset-cream',
|
||||
categoryID: 2010,
|
||||
itemID: 496218563,
|
||||
name: 'Женские кеды BOLSET (кремовый)',
|
||||
description: 'Сезон: Весна - лето (SS)\nМатериал : телячья кожа\nПроизводство: Турция\n\nРазмерный ряд: 36 - 40 (EU)',
|
||||
discount: 0,
|
||||
rating: 0,
|
||||
visible: true,
|
||||
priority: 0,
|
||||
tags: null,
|
||||
badges: null,
|
||||
basecurrency: '',
|
||||
itemDetails: [
|
||||
{ color: '0xFFFDD0', size: '37', price: 6899.94, currency: 'RUB', remaining: 100 },
|
||||
{ color: '0xFFFDD0', size: '38', price: 6900, currency: 'RUB', remaining: 100 },
|
||||
{ color: '0xFFFDD0', size: '39', price: 6900, currency: 'RUB', remaining: 100 },
|
||||
{ color: '0xFFFDD0', size: '40', price: 6900, currency: 'RUB', remaining: 100 },
|
||||
{ color: '0xFFFDD0', size: '41', price: 6900, currency: 'RUB', remaining: 100 },
|
||||
{ color: '0xFFFDD0', size: '37', price: 94.09, currency: 'USD', remaining: 100 },
|
||||
{ color: '0xFFFDD0', size: '37', price: 82.04, currency: 'EUR', remaining: 100 },
|
||||
{ color: '0xFFFDD0', size: '37', price: 34900.47, currency: 'AMD', remaining: 100 }
|
||||
],
|
||||
names: [
|
||||
{ language: 'ru', valuue: '' }
|
||||
],
|
||||
descriptions: [
|
||||
{ language: 'ru', value: 'Сезон: Весна - лето (SS)\nМатериал : телячья кожа\nПроизводство: Турция\n\nРазмерный ряд: 36 - 40 (EU)' }
|
||||
],
|
||||
attributes: [],
|
||||
photos: [
|
||||
{ type: 'photo', url: './images/496218563.webp' }
|
||||
],
|
||||
questions: [],
|
||||
visits: 0,
|
||||
callbacks: [],
|
||||
partnerID: '',
|
||||
delivery: [
|
||||
{ deliveryPrice: 0, deliveryPlace: 'по всему миру', deliveryTime: '30 минут' }
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 'lamp-smart',
|
||||
itemID: 301,
|
||||
@@ -672,7 +713,7 @@ function respond<T>(body: T, delayMs = 150) {
|
||||
}
|
||||
|
||||
// ─── Mock Auth State ───
|
||||
let mockQrPollCount = 0;
|
||||
const mockWebSessionChecks = new Map<string, number>();
|
||||
|
||||
// ─── The Interceptor ───
|
||||
|
||||
@@ -688,38 +729,39 @@ export const mockDataInterceptor: HttpInterceptorFn = (req, next) => {
|
||||
return respond({ message: 'pong (mock)' });
|
||||
}
|
||||
|
||||
// ── GET /auth/session
|
||||
if (url.includes('/auth/session') && req.method === 'GET') {
|
||||
return respond({ active: false }, 100);
|
||||
// ── POST /users/sessions
|
||||
if (url.endsWith('/users/sessions') && req.method === 'POST') {
|
||||
const body = req.body as { webSessionID?: string } | null;
|
||||
const webSessionID = body?.webSessionID || req.headers.get('WebSessionID') || 'mock-web-session';
|
||||
mockWebSessionChecks.set(webSessionID, 0);
|
||||
return respond({ webSessionID, status: false }, 200);
|
||||
}
|
||||
|
||||
// ── POST /auth/qr/create
|
||||
if (url.includes('/auth/qr/create') && req.method === 'POST') {
|
||||
const token = 'mock-qr-token-' + Date.now();
|
||||
const botUsername = (environment as Record<string, unknown>)['telegramBot'] as string || 'DexarSupport_bot';
|
||||
mockQrPollCount = 0;
|
||||
return respond({
|
||||
token,
|
||||
url: `https://t.me/${botUsername}?start=qr_${token}`
|
||||
}, 200);
|
||||
}
|
||||
// ── GET /users/sessions/:webSessionID
|
||||
const userSessionMatch = url.match(/\/users\/sessions\/([^/?]+)$/);
|
||||
if (userSessionMatch && req.method === 'GET') {
|
||||
const webSessionID = decodeURIComponent(userSessionMatch[1]);
|
||||
const checks = (mockWebSessionChecks.get(webSessionID) ?? 0) + 1;
|
||||
mockWebSessionChecks.set(webSessionID, checks);
|
||||
|
||||
// ── GET /auth/qr/poll
|
||||
if (url.includes('/auth/qr/poll') && req.method === 'GET') {
|
||||
mockQrPollCount++;
|
||||
// Simulate confirmed after 3 polls (~9 seconds)
|
||||
if (mockQrPollCount >= 3) {
|
||||
if (checks >= 3) {
|
||||
return respond({
|
||||
status: 'confirmed',
|
||||
session: {
|
||||
sessionId: 'mock-session-' + Date.now(),
|
||||
active: true,
|
||||
webSessionID,
|
||||
status: true,
|
||||
telegramUserID: 123456,
|
||||
username: 'telegram_user',
|
||||
displayName: 'Telegram User',
|
||||
expiresAt: new Date(Date.now() + 3600000).toISOString()
|
||||
}
|
||||
}, 200);
|
||||
}
|
||||
return respond({ status: 'pending' }, 200);
|
||||
|
||||
return respond({ webSessionID, status: false }, 200);
|
||||
}
|
||||
|
||||
// ── DELETE /users/sessions/:webSessionID
|
||||
if (userSessionMatch && req.method === 'DELETE') {
|
||||
mockWebSessionChecks.delete(decodeURIComponent(userSessionMatch[1]));
|
||||
return respond({ status: true }, 100);
|
||||
}
|
||||
|
||||
// ── GET /category (all categories flat list)
|
||||
@@ -779,8 +821,8 @@ export const mockDataInterceptor: HttpInterceptorFn = (req, next) => {
|
||||
return respond([]);
|
||||
}
|
||||
|
||||
// ── POST /websession/:id (add to cart)
|
||||
if (url.match(/\/websession\/[^/]+$/) && req.method === 'POST') {
|
||||
// ── POST /usersession/:id or /websession/:id (sync cart)
|
||||
if (url.match(/\/(?:user|web)session\/[^/]+$/) && req.method === 'POST') {
|
||||
return respond({
|
||||
sessionId: 'mock-session',
|
||||
Status: true,
|
||||
@@ -794,11 +836,41 @@ export const mockDataInterceptor: HttpInterceptorFn = (req, next) => {
|
||||
qrId: 'mock-qr-' + Date.now(),
|
||||
qrStatus: 'NEW',
|
||||
qrExpirationDate: new Date(Date.now() + 180000).toISOString(),
|
||||
Payload: 'https://example.com/pay/mock',
|
||||
payload: 'https://example.com/pay/mock',
|
||||
qrUrl: 'https://api.qrserver.com/v1/create-qr-code/?size=300x300&data=mock-payment'
|
||||
}, 300);
|
||||
}
|
||||
|
||||
// ── POST /qr (create payment QR directly)
|
||||
if (url.endsWith('/qr') && req.method === 'POST') {
|
||||
return respond({
|
||||
qrId: 'mock-qr-' + Date.now(),
|
||||
qrStatus: 'NEW',
|
||||
qrExpirationDate: new Date(Date.now() + 180000).toISOString(),
|
||||
payload: 'https://example.com/pay/mock',
|
||||
qrUrl: 'https://api.qrserver.com/v1/create-qr-code/?size=300x300&data=mock-payment'
|
||||
}, 300);
|
||||
}
|
||||
|
||||
// ── POST /cart (legacy create payment QR)
|
||||
if (url.endsWith('/cart') && req.method === 'POST') {
|
||||
const body = req.body;
|
||||
const looksLikePaymentRequest = !!body
|
||||
&& typeof body === 'object'
|
||||
&& !Array.isArray(body)
|
||||
&& 'amount' in body
|
||||
&& 'items' in body;
|
||||
if (looksLikePaymentRequest) {
|
||||
return respond({
|
||||
qrId: 'mock-qr-' + Date.now(),
|
||||
qrStatus: 'NEW',
|
||||
qrExpirationDate: new Date(Date.now() + 180000).toISOString(),
|
||||
payload: 'https://example.com/pay/mock',
|
||||
qrUrl: 'https://api.qrserver.com/v1/create-qr-code/?size=300x300&data=mock-payment'
|
||||
}, 300);
|
||||
}
|
||||
}
|
||||
|
||||
// ── POST /items/:id/callback (review)
|
||||
if (url.match(/\/items\/\d+\/callback$/) && req.method === 'POST') {
|
||||
return respond({ message: 'Review submitted (mock)' }, 200);
|
||||
@@ -812,7 +884,7 @@ export const mockDataInterceptor: HttpInterceptorFn = (req, next) => {
|
||||
// ── GET /websession/:id/:qrId (check QR payment status)
|
||||
if (url.match(/\/websession\/[^/]+\/[^/]+$/) && !url.match(/\/websession\/[^/]+\/qr$/) && req.method === 'GET') {
|
||||
return respond({
|
||||
paymentStatus: 'SUCCESS',
|
||||
paymentStatus: 'COMPLETED',
|
||||
code: 'SUCCESS',
|
||||
amount: 0,
|
||||
currency: 'RUB',
|
||||
@@ -827,6 +899,25 @@ export const mockDataInterceptor: HttpInterceptorFn = (req, next) => {
|
||||
}, 500);
|
||||
}
|
||||
|
||||
// ── GET /qr/payment/:qrId (payment status)
|
||||
if (url.match(/\/qr\/payment\/[^/]+$/) && req.method === 'GET') {
|
||||
return respond({
|
||||
paymentStatus: 'COMPLETED',
|
||||
code: 'SUCCESS',
|
||||
amount: 0,
|
||||
currency: 'RUB',
|
||||
qrId: 'mock',
|
||||
transactionId: 999,
|
||||
transactionDate: new Date().toISOString(),
|
||||
additionalInfo: '',
|
||||
paymentPurpose: '',
|
||||
createDate: new Date().toISOString(),
|
||||
order: 'mock-order',
|
||||
qrExpirationDate: new Date().toISOString(),
|
||||
phoneNumber: '+70000000000'
|
||||
}, 500);
|
||||
}
|
||||
|
||||
// Fallback — pass through
|
||||
return next(req);
|
||||
};
|
||||
|
||||
@@ -1,25 +1,15 @@
|
||||
export interface AuthSession {
|
||||
sessionId: string;
|
||||
telegramUserId: number;
|
||||
userId: number | null;
|
||||
username: string | null;
|
||||
displayName: string;
|
||||
active: boolean;
|
||||
expiresAt: string;
|
||||
expires: string;
|
||||
}
|
||||
|
||||
export interface TelegramAuthData {
|
||||
id: number;
|
||||
first_name: string;
|
||||
last_name?: string;
|
||||
username?: string;
|
||||
photo_url?: string;
|
||||
auth_date: number;
|
||||
hash: string;
|
||||
}
|
||||
|
||||
export interface QrPollResponse {
|
||||
status: 'pending' | 'confirmed' | 'expired';
|
||||
session?: AuthSession;
|
||||
export interface WebSessionStart {
|
||||
webSessionID: string;
|
||||
url: string;
|
||||
}
|
||||
|
||||
export type AuthStatus = 'unknown' | 'checking' | 'authenticated' | 'expired' | 'unauthenticated';
|
||||
|
||||
@@ -33,6 +33,6 @@ export interface Subcategory {
|
||||
subcategories?: Subcategory[];
|
||||
}
|
||||
|
||||
export interface CategoryTranslation {
|
||||
interface CategoryTranslation {
|
||||
name?: string;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
export interface Photo {
|
||||
interface Photo {
|
||||
photo?: string;
|
||||
video?: string;
|
||||
url: string;
|
||||
@@ -10,7 +10,7 @@ export interface DescriptionField {
|
||||
value: string;
|
||||
}
|
||||
|
||||
export interface Comment {
|
||||
interface Comment {
|
||||
id?: string;
|
||||
text: string;
|
||||
author?: string;
|
||||
@@ -18,13 +18,13 @@ export interface Comment {
|
||||
createdAt?: string;
|
||||
}
|
||||
|
||||
export interface ItemTranslation {
|
||||
interface ItemTranslation {
|
||||
name?: string;
|
||||
simpleDescription?: string;
|
||||
description?: DescriptionField[];
|
||||
}
|
||||
|
||||
export interface Review {
|
||||
interface Review {
|
||||
rating?: number;
|
||||
content?: string;
|
||||
userID?: string;
|
||||
@@ -32,10 +32,7 @@ export interface Review {
|
||||
timestamp?: string;
|
||||
}
|
||||
|
||||
/** @deprecated Use {@link Review} instead */
|
||||
export type Callback = Review;
|
||||
|
||||
export interface Question {
|
||||
interface Question {
|
||||
question: string;
|
||||
answer: string;
|
||||
upvotes: number;
|
||||
@@ -51,23 +48,32 @@ export interface ItemName {
|
||||
}
|
||||
|
||||
/** Localized description entry from backend */
|
||||
export interface ItemDescription {
|
||||
interface ItemDescription {
|
||||
language: string;
|
||||
value: string;
|
||||
}
|
||||
|
||||
/** Key-value attribute pair */
|
||||
export interface ItemAttribute {
|
||||
interface ItemAttribute {
|
||||
key: string;
|
||||
value: string;
|
||||
}
|
||||
|
||||
export interface DeliveryOption {
|
||||
deliveryPrice: number;
|
||||
deliveryPlace: string;
|
||||
deliveryTime: string;
|
||||
}
|
||||
|
||||
type DeliveryMode = 'selectable' | 'digital';
|
||||
|
||||
/** Item variant detail (price, size, colour per variant) */
|
||||
export interface ItemDetail {
|
||||
color?: string;
|
||||
colour?: string;
|
||||
size?: string;
|
||||
price: number;
|
||||
deliveryPrice?: number;
|
||||
currency: string;
|
||||
remaining: number;
|
||||
}
|
||||
@@ -80,6 +86,7 @@ export interface Item {
|
||||
description: string;
|
||||
currency: string;
|
||||
price: number;
|
||||
deliveryPrice?: number;
|
||||
discount: number;
|
||||
remainings?: string;
|
||||
rating: number;
|
||||
@@ -90,6 +97,9 @@ export interface Item {
|
||||
// Backend API fields
|
||||
colour?: string;
|
||||
size?: string;
|
||||
deliveryOptions?: DeliveryOption[];
|
||||
deliveryMode?: DeliveryMode;
|
||||
deliverySelectionRequired?: boolean;
|
||||
language?: string;
|
||||
names?: ItemName[];
|
||||
descriptions?: ItemDescription[];
|
||||
@@ -113,4 +123,5 @@ export interface Item {
|
||||
|
||||
export interface CartItem extends Item {
|
||||
quantity: number;
|
||||
selectedDelivery?: DeliveryOption | null;
|
||||
}
|
||||
|
||||
@@ -94,6 +94,13 @@
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@if (item.deliveryMode === 'digital' || item.deliveryOptions?.length) {
|
||||
<app-delivery-selector
|
||||
[item]="item"
|
||||
(selectedDeliveryChange)="selectDelivery(item.itemID, $event)"
|
||||
/>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -116,14 +123,20 @@
|
||||
<span class="value">{{ totalPrice() | number:'1.2-2' }} {{ currentCurrency }}</span>
|
||||
</div>
|
||||
|
||||
@if (hasDeliveryPrice()) {
|
||||
<div class="summary-row delivery">
|
||||
<span>{{ 'cart.deliveryLabel' | translate }}</span>
|
||||
<span>0 {{ currentCurrency }}</span>
|
||||
<span class="value">{{ totalDeliveryPrice() | number:'1.2-2' }} {{ currentCurrency }}</span>
|
||||
</div>
|
||||
}
|
||||
|
||||
@if (!allRequiredDeliveriesSelected()) {
|
||||
<p class="delivery-warning">{{ 'cart.deliveryRequired' | translate }}</p>
|
||||
}
|
||||
|
||||
<div class="summary-row total">
|
||||
<span>{{ 'cart.toPay' | translate }}</span>
|
||||
<span class="total-price">{{ totalPrice() | number:'1.2-2' }} {{ currentCurrency }}</span>
|
||||
<span class="total-price">{{ totalWithDelivery() | number:'1.2-2' }} {{ currentCurrency }}</span>
|
||||
</div>
|
||||
|
||||
<div class="terms-agreement">
|
||||
@@ -147,8 +160,8 @@
|
||||
<button
|
||||
class="checkout-btn"
|
||||
(click)="checkout()"
|
||||
[class.disabled]="!termsAccepted"
|
||||
[disabled]="!termsAccepted"
|
||||
[class.disabled]="isCheckoutDisabled"
|
||||
[disabled]="isCheckoutDisabled"
|
||||
>
|
||||
{{ 'cart.checkout' | translate }}
|
||||
</button>
|
||||
@@ -169,17 +182,6 @@
|
||||
</svg>
|
||||
{{ 'cart.loginWithTelegram' | translate }}
|
||||
</button>
|
||||
|
||||
<div class="login-gate-qr">
|
||||
<p class="qr-hint">{{ 'cart.orScanQr' | translate }}</p>
|
||||
<div class="qr-wrapper">
|
||||
<img [src]="'https://api.qrserver.com/v1/create-qr-code/?size=150x150&data=' + loginUrl()"
|
||||
alt="QR Code"
|
||||
width="150"
|
||||
height="150"
|
||||
loading="lazy" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
@@ -218,7 +220,7 @@
|
||||
<div class="payment-info">
|
||||
<div class="payment-amount">
|
||||
<span class="label">{{ 'cart.amountToPay' | translate }}</span>
|
||||
<span class="amount">{{ totalPrice() | number:'1.2-2' }} {{ currentCurrency }}</span>
|
||||
<span class="amount">{{ totalWithDelivery() | number:'1.2-2' }} {{ currentCurrency }}</span>
|
||||
</div>
|
||||
|
||||
<div class="waiting-indicator">
|
||||
@@ -238,13 +240,27 @@
|
||||
</div>
|
||||
}
|
||||
|
||||
@if (paymentStatus() === 'error') {
|
||||
<div class="payment-status-screen error">
|
||||
<div class="error-icon">!</div>
|
||||
<h2>{{ 'cart.paymentError' | translate }}</h2>
|
||||
<p>{{ 'cart.paymentErrorDesc' | translate }}</p>
|
||||
|
||||
<div class="payment-error-actions">
|
||||
<button class="retry-payment-btn" (click)="retryPayment()">
|
||||
{{ 'cart.retryPayment' | translate }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
@if (paymentStatus() === 'success') {
|
||||
<div class="payment-status-screen success">
|
||||
<div class="success-icon">✓</div>
|
||||
<h2>{{ 'cart.paymentSuccess' | translate }}</h2>
|
||||
<p class="success-text">{{ 'cart.paymentSuccessDesc' | translate }}</p>
|
||||
<!-- <p class="success-text">{{ 'cart.paymentSuccessDesc' | translate }}</p> -->
|
||||
|
||||
<div class="email-form">
|
||||
<!-- <div class="email-form">
|
||||
<div class="input-group">
|
||||
<input
|
||||
type="email"
|
||||
@@ -293,7 +309,7 @@
|
||||
{{ 'cart.send' | translate }}
|
||||
}
|
||||
</button>
|
||||
</div>
|
||||
</div> -->
|
||||
</div>
|
||||
}
|
||||
|
||||
|
||||
@@ -225,14 +225,14 @@
|
||||
|
||||
.cart-content {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 350px;
|
||||
grid-template-columns: minmax(0, 1fr) 350px;
|
||||
gap: 24px;
|
||||
align-items: start;
|
||||
}
|
||||
|
||||
// Novo wider summary
|
||||
.cart-container.novo .cart-content {
|
||||
grid-template-columns: 1fr 400px;
|
||||
grid-template-columns: minmax(0, 1fr) 400px;
|
||||
gap: 32px;
|
||||
}
|
||||
|
||||
@@ -240,6 +240,7 @@
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16px;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
// Novo larger gap
|
||||
@@ -554,6 +555,12 @@
|
||||
font-weight: 700;
|
||||
color: #497671;
|
||||
}
|
||||
|
||||
.delivery-price {
|
||||
font-size: 0.85rem;
|
||||
font-weight: 500;
|
||||
color: #697777;
|
||||
}
|
||||
}
|
||||
|
||||
// Dexar quantity controls
|
||||
@@ -802,29 +809,6 @@
|
||||
box-shadow: 0 4px 12px rgba(42, 171, 238, 0.3);
|
||||
}
|
||||
}
|
||||
|
||||
.login-gate-qr {
|
||||
margin-top: 14px;
|
||||
|
||||
.qr-hint {
|
||||
margin: 0 0 8px;
|
||||
font-size: 0.8rem;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.qr-wrapper {
|
||||
display: inline-flex;
|
||||
padding: 10px;
|
||||
background: #fff;
|
||||
border-radius: 10px;
|
||||
border: 1px solid #e5e7eb;
|
||||
|
||||
img {
|
||||
display: block;
|
||||
border-radius: 4px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -860,7 +844,7 @@
|
||||
color: #6b7280;
|
||||
|
||||
&.delivery {
|
||||
display: none; // Hide delivery in Novo
|
||||
display: flex;
|
||||
}
|
||||
|
||||
&.total {
|
||||
@@ -967,29 +951,6 @@
|
||||
box-shadow: 0 4px 12px rgba(42, 171, 238, 0.3);
|
||||
}
|
||||
}
|
||||
|
||||
.login-gate-qr {
|
||||
margin-top: 14px;
|
||||
|
||||
.qr-hint {
|
||||
margin: 0 0 8px;
|
||||
font-size: 0.8rem;
|
||||
color: #9ca3af;
|
||||
}
|
||||
|
||||
.qr-wrapper {
|
||||
display: inline-flex;
|
||||
padding: 10px;
|
||||
background: #fff;
|
||||
border-radius: 12px;
|
||||
border: 1px solid #e5e7eb;
|
||||
|
||||
img {
|
||||
display: block;
|
||||
border-radius: 4px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1055,6 +1016,27 @@
|
||||
}
|
||||
}
|
||||
|
||||
.delivery-warning {
|
||||
margin: -4px 0 0;
|
||||
padding: 10px 12px;
|
||||
border-radius: 10px;
|
||||
font-size: 0.85rem;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.cart-container.dexar .cart-summary .delivery-warning {
|
||||
color: #9a6700;
|
||||
background: #fff8e8;
|
||||
border: 1px solid #f1ddb2;
|
||||
font-family: "DM Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
|
||||
}
|
||||
|
||||
.cart-container.novo .cart-summary .delivery-warning {
|
||||
color: #92400e;
|
||||
background: #fffbeb;
|
||||
border: 1px solid #fde68a;
|
||||
}
|
||||
|
||||
// Dexar checkbox colors
|
||||
.cart-container.dexar .terms-agreement .checkbox-container {
|
||||
input[type="checkbox"]:checked ~ .checkmark {
|
||||
@@ -1242,6 +1224,45 @@
|
||||
}
|
||||
}
|
||||
|
||||
&.error {
|
||||
.error-icon {
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
background: #f97316;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 3rem;
|
||||
font-weight: 700;
|
||||
color: white;
|
||||
margin: 0 auto 20px;
|
||||
}
|
||||
|
||||
.payment-error-actions {
|
||||
margin-top: 24px;
|
||||
}
|
||||
|
||||
.retry-payment-btn {
|
||||
padding: 14px 24px;
|
||||
background: #497671;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 13px;
|
||||
font-family: "DM Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
|
||||
font-size: 1rem;
|
||||
font-weight: 700;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
|
||||
&:hover {
|
||||
background: #3a5f5b;
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 4px 12px rgba(73, 118, 113, 0.3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.timeout {
|
||||
.timeout-icon {
|
||||
font-size: 4rem;
|
||||
@@ -1534,11 +1555,31 @@
|
||||
// Mobile responsive
|
||||
@media (max-width: 768px) {
|
||||
.cart-content {
|
||||
grid-template-columns: 1fr;
|
||||
grid-template-columns: minmax(0, 1fr);
|
||||
gap: 20px;
|
||||
}
|
||||
|
||||
.cart-container.novo .cart-content {
|
||||
grid-template-columns: minmax(0, 1fr);
|
||||
gap: 20px;
|
||||
}
|
||||
|
||||
.cart-summary {
|
||||
position: static;
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.cart-container.novo,
|
||||
.cart-container.dexar {
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.cart-container.novo .cart-header,
|
||||
.cart-container.dexar .cart-header {
|
||||
flex-wrap: wrap;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.remove-btn-desktop {
|
||||
@@ -1816,6 +1857,7 @@
|
||||
margin: 0;
|
||||
line-height: 1.5;
|
||||
display: -webkit-box;
|
||||
line-clamp: 2;
|
||||
-webkit-line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
import { Component, computed, ChangeDetectionStrategy, signal, OnDestroy, inject } from '@angular/core';
|
||||
import { Component, ChangeDetectionStrategy, signal, OnDestroy, inject } from '@angular/core';
|
||||
import { DecimalPipe } from '@angular/common';
|
||||
import { Router, RouterLink } from '@angular/router';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { CartService, ApiService, LanguageService, AuthService } from '../../services';
|
||||
import { Item, CartItem } from '../../models';
|
||||
import { interval, Subscription } from 'rxjs';
|
||||
import { switchMap, take } from 'rxjs/operators';
|
||||
import { Item, CartItem, DeliveryOption } from '../../models';
|
||||
import { interval, of, Subscription } from 'rxjs';
|
||||
import { catchError, exhaustMap, take, timeout } from 'rxjs/operators';
|
||||
import { DeliverySelectorComponent } from '../../components/delivery-selector/delivery-selector.component';
|
||||
import { EmptyCartIconComponent } from '../../components/empty-cart-icon/empty-cart-icon.component';
|
||||
import { TelegramLoginComponent } from '../../components/telegram-login/telegram-login.component';
|
||||
import { environment } from '../../../environments/environment';
|
||||
@@ -13,11 +14,11 @@ import { getDiscountedPrice, getMainImage, trackByItemId, getBadgeClass, getTran
|
||||
import { LangRoutePipe } from '../../pipes/lang-route.pipe';
|
||||
import { TranslatePipe } from '../../i18n/translate.pipe';
|
||||
import { TranslateService } from '../../i18n/translate.service';
|
||||
import { PAYMENT_POLL_INTERVAL_MS, PAYMENT_MAX_CHECKS, PAYMENT_TIMEOUT_CLOSE_MS, PAYMENT_ERROR_CLOSE_MS, LINK_COPIED_DURATION_MS } from '../../config/constants';
|
||||
import { PAYMENT_POLL_INTERVAL_MS, PAYMENT_MAX_CHECKS, PAYMENT_TIMEOUT_CLOSE_MS, LINK_COPIED_DURATION_MS } from '../../config/constants';
|
||||
|
||||
@Component({
|
||||
selector: 'app-cart',
|
||||
imports: [DecimalPipe, RouterLink, FormsModule, EmptyCartIconComponent, TelegramLoginComponent, LangRoutePipe, TranslatePipe],
|
||||
imports: [DecimalPipe, RouterLink, FormsModule, EmptyCartIconComponent, DeliverySelectorComponent, TelegramLoginComponent, LangRoutePipe, TranslatePipe],
|
||||
templateUrl: './cart.component.html',
|
||||
styleUrls: ['./cart.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush
|
||||
@@ -26,6 +27,10 @@ export class CartComponent implements OnDestroy {
|
||||
items;
|
||||
itemCount;
|
||||
totalPrice;
|
||||
totalDeliveryPrice;
|
||||
totalWithDelivery;
|
||||
hasDeliveryPrice;
|
||||
allRequiredDeliveriesSelected;
|
||||
termsAccepted = false;
|
||||
isnovo = environment.theme === 'novo';
|
||||
|
||||
@@ -33,14 +38,13 @@ export class CartComponent implements OnDestroy {
|
||||
private authService = inject(AuthService);
|
||||
|
||||
isAuthenticated = this.authService.isAuthenticated;
|
||||
loginUrl = signal('');
|
||||
|
||||
// Swipe state
|
||||
swipedItemId = signal<number | null>(null);
|
||||
|
||||
// Payment popup states
|
||||
showPaymentPopup = signal<boolean>(false);
|
||||
paymentStatus = signal<'creating' | 'waiting' | 'success' | 'timeout'>('creating');
|
||||
paymentStatus = signal<'creating' | 'waiting' | 'success' | 'timeout' | 'error' | null>('creating');
|
||||
qrCodeUrl = signal<string>('');
|
||||
paymentUrl = signal<string>('');
|
||||
paymentId = signal<string>('');
|
||||
@@ -69,7 +73,10 @@ export class CartComponent implements OnDestroy {
|
||||
this.items = this.cartService.items;
|
||||
this.itemCount = this.cartService.itemCount;
|
||||
this.totalPrice = this.cartService.totalPrice;
|
||||
this.loginUrl.set(this.authService.getTelegramLoginUrl());
|
||||
this.totalDeliveryPrice = this.cartService.totalDeliveryPrice;
|
||||
this.totalWithDelivery = this.cartService.totalWithDelivery;
|
||||
this.hasDeliveryPrice = this.cartService.hasDeliveryPrice;
|
||||
this.allRequiredDeliveriesSelected = this.cartService.allRequiredDeliveriesSelected;
|
||||
}
|
||||
|
||||
requestLogin(): void {
|
||||
@@ -105,7 +112,6 @@ export class CartComponent implements OnDestroy {
|
||||
}
|
||||
|
||||
onSwipeStart(itemID: number, event: TouchEvent): void {
|
||||
const item = event.currentTarget as HTMLElement;
|
||||
const startX = event.touches[0].clientX;
|
||||
|
||||
const onMove = (e: TouchEvent) => {
|
||||
@@ -144,15 +150,20 @@ export class CartComponent implements OnDestroy {
|
||||
itemName(item: Item): string { return getTranslatedField(item, 'name', this.langService.currentLanguage()); }
|
||||
itemDesc(item: Item): string { return getTranslatedField(item, 'simpleDescription', this.langService.currentLanguage()); }
|
||||
get currentCurrency(): string { return this.langService.currentCurrency(); }
|
||||
get isCheckoutDisabled(): boolean { return !this.termsAccepted || !this.isAuthenticated() || !this.allRequiredDeliveriesSelected(); }
|
||||
|
||||
selectDelivery(itemID: number, selectedDelivery: DeliveryOption | null): void {
|
||||
this.cartService.setSelectedDelivery(itemID, selectedDelivery);
|
||||
}
|
||||
|
||||
checkout(): void {
|
||||
if (!this.termsAccepted) {
|
||||
alert(this.i18n.t('cart.acceptTerms'));
|
||||
if (!this.allRequiredDeliveriesSelected()) {
|
||||
alert(this.i18n.t('cart.deliveryRequired'));
|
||||
return;
|
||||
}
|
||||
// Auth gate: require Telegram login before payment
|
||||
if (!this.authService.isAuthenticated()) {
|
||||
this.authService.requestLogin();
|
||||
|
||||
if (!this.termsAccepted) {
|
||||
alert(this.i18n.t('cart.acceptTerms'));
|
||||
return;
|
||||
}
|
||||
this.openPaymentPopup();
|
||||
@@ -161,6 +172,10 @@ export class CartComponent implements OnDestroy {
|
||||
openPaymentPopup(): void {
|
||||
this.showPaymentPopup.set(true);
|
||||
this.paymentStatus.set('creating');
|
||||
this.paymentId.set('');
|
||||
this.qrCodeUrl.set('');
|
||||
this.paymentUrl.set('');
|
||||
this.linkCopied.set(false);
|
||||
this.userEmail.set('');
|
||||
this.userPhone.set('');
|
||||
this.emailTouched.set(false);
|
||||
@@ -181,73 +196,110 @@ export class CartComponent implements OnDestroy {
|
||||
}
|
||||
}
|
||||
|
||||
retryPayment(): void {
|
||||
if (this.closeTimeout) {
|
||||
clearTimeout(this.closeTimeout);
|
||||
this.closeTimeout = undefined;
|
||||
}
|
||||
|
||||
this.paymentStatus.set('creating');
|
||||
this.paymentId.set('');
|
||||
this.qrCodeUrl.set('');
|
||||
this.paymentUrl.set('');
|
||||
this.linkCopied.set(false);
|
||||
this.createPayment();
|
||||
}
|
||||
|
||||
createPayment(): void {
|
||||
const sessionId = this.authService.session()?.sessionId || '';
|
||||
if (!sessionId) {
|
||||
this.paymentStatus.set('timeout');
|
||||
const orderId = this.generateOrderId();
|
||||
const paymentPayload = {
|
||||
amount: Number(this.totalWithDelivery()),
|
||||
currency: 'RUB' as const,
|
||||
siteuserID: this.getPaymentUserId(),
|
||||
siteorderID: orderId,
|
||||
redirectUrl: '',
|
||||
telegramUsername: this.getTelegramUsername(),
|
||||
items: this.buildPaymentItems(),
|
||||
};
|
||||
|
||||
this.apiService.createCartPayment(paymentPayload)
|
||||
.subscribe({
|
||||
next: (response) => {
|
||||
const qrId = this.apiService.resolvePaymentQrId(response);
|
||||
const qrUrl = this.apiService.resolvePaymentQrUrl(response);
|
||||
const paymentLink = this.apiService.resolvePaymentLink(response);
|
||||
|
||||
if (!qrId || !qrUrl) {
|
||||
console.error('Payment response missing qr fields:', response);
|
||||
this.setPaymentError();
|
||||
return;
|
||||
}
|
||||
|
||||
// First sync cart items to server via websession, then create QR
|
||||
const cartItems = this.items().map((item: CartItem) => ({
|
||||
itemID: item.itemID,
|
||||
quantity: item.quantity,
|
||||
colour: item.colour || '',
|
||||
size: item.size || '',
|
||||
price: item.discount > 0
|
||||
? item.price * (1 - item.discount / 100)
|
||||
: item.price,
|
||||
}));
|
||||
this.paymentId.set(qrId);
|
||||
this.qrCodeUrl.set(qrUrl);
|
||||
this.paymentUrl.set(paymentLink);
|
||||
|
||||
this.apiService.addToCart(sessionId, cartItems).subscribe({
|
||||
next: () => {
|
||||
this.apiService.createPayment(sessionId).subscribe({
|
||||
next: (response) => {
|
||||
this.paymentId.set(response.qrId);
|
||||
this.qrCodeUrl.set(response.qrUrl);
|
||||
this.paymentUrl.set(response.Payload);
|
||||
this.paymentStatus.set('waiting');
|
||||
this.startPolling();
|
||||
},
|
||||
error: (err) => {
|
||||
console.error('Error creating payment:', err);
|
||||
this.paymentStatus.set('timeout');
|
||||
if (this.closeTimeout) clearTimeout(this.closeTimeout);
|
||||
this.closeTimeout = setTimeout(() => {
|
||||
this.closePaymentPopup();
|
||||
}, PAYMENT_ERROR_CLOSE_MS);
|
||||
}
|
||||
});
|
||||
},
|
||||
error: (err) => {
|
||||
console.error('Error syncing cart:', err);
|
||||
this.paymentStatus.set('timeout');
|
||||
if (this.closeTimeout) clearTimeout(this.closeTimeout);
|
||||
this.closeTimeout = setTimeout(() => {
|
||||
this.closePaymentPopup();
|
||||
}, PAYMENT_ERROR_CLOSE_MS);
|
||||
this.setPaymentError();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
startPolling(): void {
|
||||
this.stopPolling();
|
||||
if (!this.paymentId()) {
|
||||
this.setPaymentError();
|
||||
return;
|
||||
}
|
||||
|
||||
this.pollingSubscription = interval(PAYMENT_POLL_INTERVAL_MS)
|
||||
.pipe(
|
||||
take(this.maxChecks), // maximum 36 checks (3 minutes)
|
||||
switchMap(() => {
|
||||
const sessionId = this.authService.session()?.sessionId || '';
|
||||
return this.apiService.checkPaymentStatus(sessionId, this.paymentId());
|
||||
exhaustMap(() => {
|
||||
return this.apiService.checkCartPaymentStatus(this.paymentId()).pipe(
|
||||
timeout(8000),
|
||||
catchError((err) => {
|
||||
console.error('Error checking payment status:', err);
|
||||
return of(null);
|
||||
})
|
||||
);
|
||||
})
|
||||
)
|
||||
.subscribe({
|
||||
next: (response) => {
|
||||
if (!response) {
|
||||
return;
|
||||
}
|
||||
|
||||
const paymentStatus = response.status?.toUpperCase() || '';
|
||||
const paymentCode = response.code?.toUpperCase() || '';
|
||||
|
||||
if (paymentStatus === 'FAILED' || paymentStatus === 'EXPIRED' || paymentStatus === 'CANCELLED' || paymentStatus === 'REJECTED') {
|
||||
this.paymentStatus.set('timeout');
|
||||
this.stopPolling();
|
||||
if (this.closeTimeout) clearTimeout(this.closeTimeout);
|
||||
this.closeTimeout = setTimeout(() => {
|
||||
this.closePaymentPopup();
|
||||
}, PAYMENT_TIMEOUT_CLOSE_MS);
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if payment is successful
|
||||
if (response.paymentStatus === 'SUCCESS' && response.code === 'SUCCESS') {
|
||||
if (paymentStatus === 'COMPLETED' || paymentStatus === 'APPROVED' || paymentStatus === 'PAID' || paymentCode === 'SUCCESS') {
|
||||
this.paymentStatus.set('success');
|
||||
this.stopPolling();
|
||||
// Clear cart but don't close popup - wait for email submission
|
||||
// Auto-submit purchase after 5 seconds
|
||||
if (this.closeTimeout) clearTimeout(this.closeTimeout);
|
||||
this.closeTimeout = setTimeout(() => {
|
||||
this.autoSubmitPurchase();
|
||||
}, 5000);
|
||||
this.cartService.clearCart();
|
||||
|
||||
|
||||
}
|
||||
// Continue checking for 3 minutes regardless of other statuses
|
||||
},
|
||||
@@ -262,14 +314,6 @@ export class CartComponent implements OnDestroy {
|
||||
this.closePaymentPopup();
|
||||
}, PAYMENT_TIMEOUT_CLOSE_MS);
|
||||
}
|
||||
},
|
||||
error: (err) => {
|
||||
console.error('Error checking payment status:', err);
|
||||
// Continue checking even on error until time runs out
|
||||
if (this.closeTimeout) clearTimeout(this.closeTimeout);
|
||||
this.closeTimeout = setTimeout(() => {
|
||||
this.closePaymentPopup();
|
||||
}, PAYMENT_TIMEOUT_CLOSE_MS);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -277,9 +321,71 @@ export class CartComponent implements OnDestroy {
|
||||
stopPolling(): void {
|
||||
if (this.pollingSubscription) {
|
||||
this.pollingSubscription.unsubscribe();
|
||||
this.pollingSubscription = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
private setPaymentError(): void {
|
||||
this.paymentStatus.set('error');
|
||||
this.stopPolling();
|
||||
if (this.closeTimeout) {
|
||||
clearTimeout(this.closeTimeout);
|
||||
this.closeTimeout = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
private autoSubmitPurchase(): void {
|
||||
setTimeout(() => {
|
||||
const lang = this.langService.currentLanguage();
|
||||
this.router.navigate([`/${lang}`]);}, 0);
|
||||
const telegramUserId = this.getTelegramUserId();
|
||||
|
||||
// Telegram ID is mandatory
|
||||
if (!telegramUserId) {
|
||||
console.error('Cannot submit purchase: Telegram ID is required');
|
||||
this.emailSubmitting.set(false);
|
||||
return;
|
||||
}
|
||||
|
||||
this.emailSubmitting.set(true);
|
||||
|
||||
const emailData = {
|
||||
email: '',
|
||||
phone: '',
|
||||
telegramUserId: telegramUserId,
|
||||
items: this.paidItems.map((item: CartItem) => ({
|
||||
itemID: item.itemID,
|
||||
name: item.name,
|
||||
price: item.discount > 0
|
||||
? item.price * (1 - item.discount / 100)
|
||||
: item.price,
|
||||
currency: item.currency,
|
||||
quantity: item.quantity,
|
||||
...(item.selectedDelivery ? { delivery: item.selectedDelivery } : {})
|
||||
}))
|
||||
};
|
||||
|
||||
this.apiService.submitPurchaseEmail(emailData).subscribe({
|
||||
next: () => {
|
||||
this.emailSubmitting.set(false);
|
||||
this.closePaymentPopup();
|
||||
const lang = this.langService.currentLanguage();
|
||||
this.router.navigate([`/${lang}`]);
|
||||
},
|
||||
error: (err) => {
|
||||
console.error('Error submitting purchase:', err);
|
||||
this.emailSubmitting.set(false);
|
||||
// Still close popup and redirect even if submission fails
|
||||
this.closePaymentPopup();
|
||||
const lang = this.langService.currentLanguage();
|
||||
this.router.navigate([`/${lang}`]);
|
||||
}
|
||||
});
|
||||
this.paymentStatus.set(null);
|
||||
|
||||
|
||||
}
|
||||
|
||||
copyPaymentLink(): void {
|
||||
const url = this.paymentUrl();
|
||||
if (url) {
|
||||
@@ -323,7 +429,8 @@ export class CartComponent implements OnDestroy {
|
||||
? item.price * (1 - item.discount / 100)
|
||||
: item.price,
|
||||
currency: item.currency,
|
||||
quantity: item.quantity
|
||||
quantity: item.quantity,
|
||||
...(item.selectedDelivery ? { delivery: item.selectedDelivery } : {})
|
||||
}))
|
||||
};
|
||||
|
||||
@@ -348,12 +455,60 @@ export class CartComponent implements OnDestroy {
|
||||
}
|
||||
|
||||
private getTelegramUserId(): string | null {
|
||||
const sessionTelegramUserId = this.authService.session()?.userId;
|
||||
if (sessionTelegramUserId !== null && sessionTelegramUserId !== undefined) {
|
||||
return sessionTelegramUserId.toString();
|
||||
}
|
||||
|
||||
if (typeof window !== 'undefined' && window.Telegram?.WebApp?.initDataUnsafe?.user) {
|
||||
return window.Telegram.WebApp.initDataUnsafe.user.id.toString();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private getTelegramUsername(): string {
|
||||
const sessionUsername = this.authService.session()?.username;
|
||||
if (sessionUsername) {
|
||||
return sessionUsername;
|
||||
}
|
||||
|
||||
if (typeof window !== 'undefined' && window.Telegram?.WebApp?.initDataUnsafe?.user) {
|
||||
return window.Telegram.WebApp.initDataUnsafe.user.username || 'nontelegram';
|
||||
}
|
||||
|
||||
return 'nontelegram';
|
||||
}
|
||||
|
||||
private getPaymentUserId(): string {
|
||||
return this.getTelegramUserId() ?? `web_${Date.now()}`;
|
||||
}
|
||||
|
||||
private generateOrderId(): string {
|
||||
const timestamp = Date.now();
|
||||
const random = Math.random().toString(36).substring(2, 8);
|
||||
return `order_${timestamp}_${random}`;
|
||||
}
|
||||
|
||||
private buildPaymentItems(): Array<{ itemID: number; price: number; name: string; quantity: number; delivery?: DeliveryOption }> {
|
||||
return this.items().map((item: CartItem) => {
|
||||
const unitPrice = item.discount > 0
|
||||
? item.price * (1 - item.discount / 100)
|
||||
: item.price;
|
||||
const details = [item.colour, item.size].filter(Boolean).join(', ');
|
||||
const translatedName = this.itemName(item).trim() || `Item ${item.itemID}`;
|
||||
const name = details ? `${item.quantity} x ${translatedName} (${details})` : `${item.quantity} x ${translatedName}`;
|
||||
|
||||
return {
|
||||
itemID: item.itemID,
|
||||
price: unitPrice * item.quantity,
|
||||
name,
|
||||
quantity: item.quantity,
|
||||
...(item.selectedDelivery ? { delivery: item.selectedDelivery } : {}),
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
onPhoneInput(event: Event): void {
|
||||
const input = event.target as HTMLInputElement;
|
||||
let value = input.value.replace(/\D/g, ''); // Remove all non-digits
|
||||
|
||||
@@ -63,10 +63,10 @@ export class SubcategoriesComponent implements OnInit, OnDestroy {
|
||||
|
||||
// Check for nested subcategories from API response (backOffice format)
|
||||
const nested = parent?.subcategories || [];
|
||||
const visibleNested = nested.filter(s => s.visible !== false);
|
||||
const visibleNested = nested.filter(s => this.isDisplayableNestedSubcategory(s));
|
||||
|
||||
// Also check flat legacy subcategories
|
||||
const flatSubs = cats.filter(c => c.parentID === parentID);
|
||||
const flatSubs = cats.filter(c => c.parentID === parentID && this.isDisplayableFlatSubcategory(c));
|
||||
|
||||
if (visibleNested.length > 0) {
|
||||
// Use nested subcategories from API
|
||||
@@ -110,6 +110,20 @@ export class SubcategoriesComponent implements OnInit, OnDestroy {
|
||||
});
|
||||
}
|
||||
|
||||
private isDisplayableFlatSubcategory(category: Category): boolean {
|
||||
return category.visible !== false
|
||||
&& ((category.itemCount ?? 0) > 0 || (category.subcategories?.length ?? 0) > 0);
|
||||
}
|
||||
|
||||
private isDisplayableNestedSubcategory(subcategory: Subcategory): boolean {
|
||||
return subcategory.visible !== false
|
||||
&& (
|
||||
(subcategory.itemCount ?? 0) > 0
|
||||
|| subcategory.hasItems === true
|
||||
|| (subcategory.subcategories?.length ?? 0) > 0
|
||||
);
|
||||
}
|
||||
|
||||
hasSubcategories(): boolean {
|
||||
return this.subcategories().length > 0 || this.nestedSubcategories().length > 0;
|
||||
}
|
||||
@@ -121,11 +135,11 @@ export class SubcategoriesComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
|
||||
// TrackBy function for performance optimization
|
||||
trackByCategoryId(index: number, category: Category): number {
|
||||
trackByCategoryId(_index: number, category: Category): number {
|
||||
return category.categoryID;
|
||||
}
|
||||
|
||||
trackBySubId(index: number, sub: Subcategory): string {
|
||||
trackBySubId(_index: number, sub: Subcategory): string {
|
||||
return sub.id;
|
||||
}
|
||||
|
||||
|
||||
@@ -28,6 +28,7 @@ export class HomeComponent implements OnInit, OnDestroy {
|
||||
topLevelCategories = computed(() => {
|
||||
return this.categories()
|
||||
.filter(cat => cat.parentID === 0)
|
||||
.filter(cat => this.isDisplayableTopLevelCategory(cat))
|
||||
.sort((a, b) => (a.priority ?? Infinity) - (b.priority ?? Infinity));
|
||||
});
|
||||
|
||||
@@ -42,7 +43,7 @@ export class HomeComponent implements OnInit, OnDestroy {
|
||||
private subcategoriesCache = computed(() => {
|
||||
const cache = new Map<number, Category[]>();
|
||||
this.categories().forEach(cat => {
|
||||
if (cat.parentID !== 0) {
|
||||
if (cat.parentID !== 0 && this.isDisplayableFlatSubcategory(cat)) {
|
||||
if (!cache.has(cat.parentID)) {
|
||||
cache.set(cat.parentID, []);
|
||||
}
|
||||
@@ -90,6 +91,21 @@ export class HomeComponent implements OnInit, OnDestroy {
|
||||
return this.subcategoriesCache().get(parentID) || [];
|
||||
}
|
||||
|
||||
private isDisplayableFlatSubcategory(category: Category): boolean {
|
||||
return category.visible !== false
|
||||
&& ((category.itemCount ?? 0) > 0 || (category.subcategories?.length ?? 0) > 0);
|
||||
}
|
||||
|
||||
private isDisplayableTopLevelCategory(category: Category): boolean {
|
||||
return category.visible !== false
|
||||
&& (
|
||||
(category.itemCount ?? 0) > 0
|
||||
|| (category.categoriesCount ?? 0) > 0
|
||||
|| (category.subcategories?.length ?? 0) > 0
|
||||
|| this.getSubCategories(category.categoryID).length > 0
|
||||
);
|
||||
}
|
||||
|
||||
isWideCategory(categoryID: number): boolean {
|
||||
return this.wideCategories().has(categoryID);
|
||||
}
|
||||
|
||||
@@ -144,6 +144,32 @@
|
||||
</div>
|
||||
}
|
||||
|
||||
@if (hasDeliveryInfo()) {
|
||||
<div class="novo-delivery">
|
||||
<h3 class="novo-delivery-title">{{ 'cart.deliveryLabel' | translate }}</h3>
|
||||
|
||||
@if (isDigitalDelivery()) {
|
||||
<div class="novo-delivery-chip">{{ 'cart.digitalDelivery' | translate }}</div>
|
||||
} @else {
|
||||
<div class="novo-delivery-list">
|
||||
@for (option of deliveryOptions(); track trackByDeliveryOption($index, option)) {
|
||||
<div class="novo-delivery-option">
|
||||
<div class="novo-delivery-option-main">
|
||||
@if (option.deliveryPlace) {
|
||||
<span>{{ 'cart.deliveryPlace' | translate }}: {{ option.deliveryPlace }}</span>
|
||||
}
|
||||
@if (option.deliveryTime) {
|
||||
<span>{{ 'cart.deliveryTime' | translate }}: {{ option.deliveryTime }}</span>
|
||||
}
|
||||
</div>
|
||||
<span class="novo-delivery-price">{{ option.deliveryPrice | number:'1.2-2' }} {{ getDeliveryCurrency() }}</span>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
|
||||
<button class="novo-add-cart" (click)="addToCart()">
|
||||
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<circle cx="9" cy="21" r="1"></circle>
|
||||
@@ -423,6 +449,32 @@
|
||||
</div>
|
||||
}
|
||||
|
||||
@if (hasDeliveryInfo()) {
|
||||
<div class="dx-delivery">
|
||||
<h3 class="dx-delivery-title">{{ 'cart.deliveryLabel' | translate }}</h3>
|
||||
|
||||
@if (isDigitalDelivery()) {
|
||||
<div class="dx-delivery-chip">{{ 'cart.digitalDelivery' | translate }}</div>
|
||||
} @else {
|
||||
<div class="dx-delivery-list">
|
||||
@for (option of deliveryOptions(); track trackByDeliveryOption($index, option)) {
|
||||
<div class="dx-delivery-option">
|
||||
<div class="dx-delivery-option-main">
|
||||
@if (option.deliveryPlace) {
|
||||
<span>{{ 'cart.deliveryPlace' | translate }}: {{ option.deliveryPlace }}</span>
|
||||
}
|
||||
@if (option.deliveryTime) {
|
||||
<span>{{ 'cart.deliveryTime' | translate }}: {{ option.deliveryTime }}</span>
|
||||
}
|
||||
</div>
|
||||
<span class="dx-delivery-price">{{ option.deliveryPrice | number:'1.2-2' }} {{ getDeliveryCurrency() }}</span>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
|
||||
<button class="dx-add-cart" (click)="addToCart()">
|
||||
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<circle cx="9" cy="21" r="1"></circle>
|
||||
|
||||
@@ -383,6 +383,65 @@ $dx-card-bg: #f5f3f9;
|
||||
}
|
||||
}
|
||||
|
||||
.dx-delivery, .novo-delivery {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
padding: 14px 16px;
|
||||
border: 1px solid $dx-border;
|
||||
border-radius: 12px;
|
||||
background: #f8fafa;
|
||||
}
|
||||
|
||||
.dx-delivery-title, .novo-delivery-title {
|
||||
margin: 0;
|
||||
font-size: 1rem;
|
||||
font-weight: 700;
|
||||
color: $dx-dark;
|
||||
}
|
||||
|
||||
.dx-delivery-list, .novo-delivery-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.dx-delivery-option, .novo-delivery-option {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: flex-start;
|
||||
gap: 12px;
|
||||
padding: 10px 12px;
|
||||
border-radius: 10px;
|
||||
background: white;
|
||||
}
|
||||
|
||||
.dx-delivery-option-main, .novo-delivery-option-main {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
color: $dx-muted;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.dx-delivery-price, .novo-delivery-price {
|
||||
flex-shrink: 0;
|
||||
font-weight: 700;
|
||||
color: $dx-primary;
|
||||
font-size: 0.95rem;
|
||||
}
|
||||
|
||||
.dx-delivery-chip, .novo-delivery-chip {
|
||||
display: inline-flex;
|
||||
align-self: flex-start;
|
||||
padding: 6px 12px;
|
||||
border-radius: 999px;
|
||||
background: rgba(73, 118, 113, 0.12);
|
||||
color: $dx-primary;
|
||||
font-size: 0.9rem;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.dx-description {
|
||||
padding-top: 8px;
|
||||
border-top: 1px solid $dx-border;
|
||||
|
||||
@@ -4,12 +4,12 @@ import { FormsModule } from '@angular/forms';
|
||||
import { ActivatedRoute, RouterLink } from '@angular/router';
|
||||
import { ApiService, CartService, TelegramService, LanguageService, SeoService } from '../../services';
|
||||
import { AuthService } from '../../services/auth.service';
|
||||
import { Item, ItemDetail, DescriptionField } from '../../models';
|
||||
import { Item, ItemDetail, DescriptionField, DeliveryOption } from '../../models';
|
||||
import { DomSanitizer, SafeHtml } from '@angular/platform-browser';
|
||||
import { Subscription } from 'rxjs';
|
||||
import { environment } from '../../../environments/environment';
|
||||
import { SecurityContext } from '@angular/core';
|
||||
import { getDiscountedPrice, getAllImages, getStockStatus, getBadgeClass, getTranslatedField } from '../../utils/item.utils';
|
||||
import { getStockStatus, getBadgeClass, getTranslatedField } from '../../utils/item.utils';
|
||||
import { LangRoutePipe } from '../../pipes/lang-route.pipe';
|
||||
import { TranslatePipe } from '../../i18n/translate.pipe';
|
||||
import { TranslateService } from '../../i18n/translate.service';
|
||||
@@ -77,6 +77,13 @@ export class ItemDetailComponent implements OnInit, OnDestroy {
|
||||
return detail?.remaining ?? this.item()?.quantity ?? null;
|
||||
});
|
||||
|
||||
deliveryOptions = computed(() => this.item()?.deliveryOptions ?? []);
|
||||
|
||||
hasDeliveryInfo = computed(() => {
|
||||
const currentItem = this.item();
|
||||
return currentItem?.deliveryMode === 'digital' || this.deliveryOptions().length > 0;
|
||||
});
|
||||
|
||||
newReview = {
|
||||
rating: 0,
|
||||
comment: '',
|
||||
@@ -187,6 +194,18 @@ export class ItemDetailComponent implements OnInit, OnDestroy {
|
||||
return discount > 0 ? price * (1 - discount / 100) : price;
|
||||
}
|
||||
|
||||
isDigitalDelivery(): boolean {
|
||||
return this.item()?.deliveryMode === 'digital';
|
||||
}
|
||||
|
||||
getDeliveryCurrency(): string {
|
||||
return this.effectiveCurrency() || this.item()?.currency || 'RUB';
|
||||
}
|
||||
|
||||
trackByDeliveryOption(index: number, option: DeliveryOption): string {
|
||||
return `${index}-${option.deliveryPlace}-${option.deliveryTime}-${option.deliveryPrice}`;
|
||||
}
|
||||
|
||||
// BackOffice integration helpers
|
||||
|
||||
getItemName(): string {
|
||||
@@ -297,7 +316,7 @@ export class ItemDetailComponent implements OnInit, OnDestroy {
|
||||
};
|
||||
|
||||
this.apiService.submitReview(reviewData).subscribe({
|
||||
next: (response) => {
|
||||
next: () => {
|
||||
this.reviewSubmitStatus.set('success');
|
||||
this.newReview = { rating: 0, comment: '', anonymous: false };
|
||||
|
||||
|
||||
@@ -70,6 +70,14 @@
|
||||
<p>2.2. The agreement regulates the procedure for using the site and the functions provided by the Owner.</p>
|
||||
|
||||
<p>2.3. The document applies to all types of goods, services and products available on the site.</p>
|
||||
|
||||
<p>2.4. The Marketplace is an agent acting under agency agreements with Sellers (Third Parties). The Marketplace does not acquire ownership rights to the Goods/Services sold through the Platform and only provides the technical ability to conclude a transaction between the Seller and the Buyer.</p>
|
||||
|
||||
<p>2.5. The Seller is an independent business entity and bears full responsibility for the quality, safety, conformity of the Goods/Services to the stated characteristics, and fulfillment of obligations to the Buyer (warranties, returns, claims).</p>
|
||||
|
||||
<p>2.6. The Marketplace is not a party to the sale and purchase agreement between the Seller and the Buyer. All claims regarding the Goods/Services are submitted by the Buyer directly to the Seller.</p>
|
||||
|
||||
<p>2.7. The Marketplace's agency remuneration is withheld from the amount paid by the Buyer and does not increase the price for the Buyer beyond the price set by the Seller.</p>
|
||||
</section>
|
||||
|
||||
<section class="legal-section">
|
||||
@@ -509,7 +517,7 @@
|
||||
<p>Free services provided under the agreement do not imply the application of consumer protection legislation to the relationship between the User and the Seller.</p>
|
||||
|
||||
<p><strong>16.6. Absent Relationships</strong></p>
|
||||
<p>No provisions of the agreement may be construed as establishing agency relationships, partnerships, joint ventures, employment relationships or other types of relationships not expressly provided for by the agreement.</p>
|
||||
<p>No provisions of the agreement, except for the agency model with Sellers expressly provided in clause 2.4, may be construed as establishing partnerships, joint ventures, employment relationships or other types of relationships not expressly provided for by the agreement.</p>
|
||||
|
||||
<p><strong>16.7. Invalidity of Provisions</strong></p>
|
||||
<p>The recognition of one or more provisions of the agreement as invalid does not affect the legal force and applicability of the remaining provisions.</p>
|
||||
|
||||
@@ -70,6 +70,14 @@
|
||||
<p>2.2. Համաձայնագիրը կարգավորում է կայքի և Սեփականատիրոջ կողմից տրամադրվող գործառույթների օգտագործման կարգը:</p>
|
||||
|
||||
<p>2.3. Փաստաթղթի գործողությունը տարածվում է կայքում առկա ապրանքների, ծառայությունների և պրոդուկտների բոլոր տեսակների վրա:</p>
|
||||
|
||||
<p>2.4. Մարկետփլեյսը հանդիսանում է գործակալ, որը գործում է Վաճառողների (Երրորդ անձանց) հետ կնքված գործակալության պայմանագրի հիման վրա։ Մարկետփլեյսը չի ձեռք բերում Հարթակի միջոցով իրացվող Ապրանքների/Ծառայությունների նկատմամբ սեփականության իրավունք, այլ միայն ապահովում է Վաճառողի և Գնորդի միջև գործարք կնքելու տեխնիկական հնարավորությունը։</p>
|
||||
|
||||
<p>2.5. Վաճառողը հանդիսանում է ինքնուրույն տնտեսվարող սուբյեկտ և կրում է ամբողջական պատասխանատվություն Ապրանքի/Ծառայության որակի, անվտանգության, հայտարարված բնութագրերին համապատասխանության, ինչպես նաև Գնորդի նկատմամբ պարտավորությունների կատարման համար (երաշխիքներ, վերադարձ, պահանջներ)։</p>
|
||||
|
||||
<p>2.6. Մարկետփլեյսը չի հանդիսանում Վաճառողի և Գնորդի միջև առուվաճառքի պայմանագրի կողմ։ Ապրանքի/Ծառայության վերաբերյալ բոլոր պահանջները Գնորդը ներկայացնում է անմիջապես Վաճառողին։</p>
|
||||
|
||||
<p>2.7. Մարկետփլեյսի գործակալական վարձատրությունը պահվում է Գնորդի վճարած գումարից և չի ավելացնում Գնորդի համար գինը Վաճառողի սահմանած գնից ավել։</p>
|
||||
</section>
|
||||
|
||||
<section class="legal-section">
|
||||
@@ -509,7 +517,7 @@
|
||||
<p>Համաձայնագրի շրջանակում տրամադրվող անվճար ծառայությունները չեն ենթադրում սպառողների իրավունքների պաշտպանության մասին օրենսդրության նորմերի կիրառում Օգտատիրոջ և Վաճառողի հարաբերությունների նկատմամբ:</p>
|
||||
|
||||
<p><strong>16.6. Բացակայող հարաբերություններ</strong></p>
|
||||
<p>Համաձայնագրի ոչ մի դրույթ չի կարող մեկնաբանվել որպես գործակալական հարաբերությունների, գործընկերության, համատեղ ձեռնարկության, աշխատանքային հարաբերությունների կամ այլ հարաբերությունների հաստատում, որոնք ուղղակիորեն նախատեսված չեն համաձայնագրով:</p>
|
||||
<p>Համաձայնագրի ոչ մի դրույթ, բացի 2.4 կետով Վաճառողների հետ ուղղակիորեն նախատեսված գործակալական մոդելից, չի կարող մեկնաբանվել որպես գործընկերության, համատեղ ձեռնարկության, աշխատանքային հարաբերությունների կամ համաձայնագրով ուղղակիորեն չնախատեսված այլ հարաբերությունների հաստատում:</p>
|
||||
|
||||
<p><strong>16.7. Կետերի անվավեր ճանաչում</strong></p>
|
||||
<p>Համաձայնագրի մեկ կամ մի քանի դրույթների անվավեր ճանաչումը չի ազդում մնացած կետերի իրավաբանական ուժի և կիրառելիության վրա:</p>
|
||||
|
||||
@@ -70,6 +70,14 @@
|
||||
<p>2.2. Соглашение регулирует порядок использования сайта и функций, предоставляемых Владельцем.</p>
|
||||
|
||||
<p>2.3. Действие документа распространяется на все типы товаров, услуг и продуктов, имеющихся на сайте.</p>
|
||||
|
||||
<p>2.4. Маркетплейс является агентом, действующим на основании договора агентирования с Продавцами (Третьими лицами). Маркетплейс не приобретает право собственности на Товары/Услуги, реализуемые через Платформу, а лишь обеспечивает техническую возможность заключения сделки между Продавцом и Покупателем.</p>
|
||||
|
||||
<p>2.5. Продавец является самостоятельным хозяйствующим субъектом и несёт полную ответственность за качество, безопасность, соответствие Товара/Услуги заявленным характеристикам, а также за исполнение обязательств перед Покупателем (гарантии, возврат, претензии).</p>
|
||||
|
||||
<p>2.6. Маркетплейс не выступает стороной договора купли-продажи между Продавцом и Покупателем. Все претензии по Товару/Услуге Покупатель предъявляет непосредственно Продавцу.</p>
|
||||
|
||||
<p>2.7. Агентское вознаграждение Маркетплейса удерживается из суммы, уплаченной Покупателем, и не увеличивает цену для Покупателя сверх установленной Продавцом.</p>
|
||||
</section>
|
||||
|
||||
<section class="legal-section">
|
||||
@@ -509,7 +517,7 @@
|
||||
<p>Бесплатные услуги, предоставляемые в рамках соглашения, не предполагают применение норм законодательства о защите прав потребителей к взаимоотношениям между Пользователем и Продавцом.</p>
|
||||
|
||||
<p><strong>16.6. Отсутствующие отношения</strong></p>
|
||||
<p>Никакие положения соглашения не могут трактоваться как установление агентских связей, партнёрства, совместного предприятия, трудовых отношений или иных видов взаимоотношений, прямо не предусмотренных соглашением.</p>
|
||||
<p>Никакие положения соглашения, кроме прямо предусмотренной пунктом 2.4 агентской модели взаимодействия с Продавцами, не могут трактоваться как установление партнёрства, совместного предприятия, трудовых отношений или иных видов взаимоотношений, прямо не предусмотренных соглашением.</p>
|
||||
|
||||
<p><strong>16.7. Признание недействительности пунктов</strong></p>
|
||||
<p>Признание одного или нескольких положений соглашения недействительным не влияет на законную силу и применимость оставшихся пунктов.</p>
|
||||
|
||||
@@ -1,19 +1,76 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { HttpClient, HttpParams } from '@angular/common/http';
|
||||
import { HttpClient, HttpHeaders, HttpParams } from '@angular/common/http';
|
||||
import { Observable, timer } from 'rxjs';
|
||||
import { map, retry } from 'rxjs/operators';
|
||||
import { Category, Item, Subcategory } from '../models';
|
||||
import { Category, DeliveryOption, Item, Subcategory } from '../models';
|
||||
import { normalizeDeliveryOption, normalizeOptionalNumber } from '../utils/normalization.utils';
|
||||
import { environment } from '../../environments/environment';
|
||||
|
||||
export interface QrCreateRequest {
|
||||
qrtype: 'QRDynamic';
|
||||
amount: number;
|
||||
currency: 'RUB';
|
||||
partnerqrID?: string;
|
||||
qrDescription?: string;
|
||||
Userid?: string;
|
||||
Reference?: string;
|
||||
RedirectUrl?: string;
|
||||
}
|
||||
|
||||
export interface QrCreateResponse {
|
||||
qrId?: string;
|
||||
qrID?: string;
|
||||
nspkID?: string;
|
||||
nspkId?: string;
|
||||
nspkurl?: string;
|
||||
status?: string;
|
||||
qrStatus?: string;
|
||||
qrExpirationDate?: string;
|
||||
payload?: string;
|
||||
Payload?: string;
|
||||
qrUrl?: string;
|
||||
partnerqrID?: string | number;
|
||||
partnerID?: string | number;
|
||||
partnerId?: string | number;
|
||||
PartnerID?: string | number;
|
||||
}
|
||||
|
||||
export interface CartPaymentRequest {
|
||||
amount: number;
|
||||
currency: 'RUB';
|
||||
siteuserID: string;
|
||||
siteorderID: string;
|
||||
redirectUrl: string;
|
||||
telegramUsername: string;
|
||||
items: Array<{ itemID: number; price: number; name: string; quantity?: number; delivery?: DeliveryOption }>;
|
||||
}
|
||||
|
||||
export interface QrDynamicStatusResponse {
|
||||
additionalInfo: string;
|
||||
paymentPurpose: string;
|
||||
amount: number;
|
||||
code: string;
|
||||
createDate: string;
|
||||
currency: string;
|
||||
order: string;
|
||||
status: string;
|
||||
qrId: string;
|
||||
transactionDate: string;
|
||||
transactionId: number;
|
||||
qrExpirationDate: string;
|
||||
}
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class ApiService {
|
||||
private readonly baseUrl = environment.apiUrl;
|
||||
private readonly qrBaseUrl = (environment as any).qrApiUrl as string;
|
||||
private readonly cartPaymentPartnerId = 'web-97ec-9c57-4dde-9037-3a68f7f83750';
|
||||
|
||||
private readonly retryConfig = {
|
||||
count: 2,
|
||||
delay: (error: unknown, retryCount: number) => timer(Math.pow(2, retryCount) * 500)
|
||||
delay: (_error: unknown, retryCount: number) => timer(Math.pow(2, retryCount) * 500)
|
||||
};
|
||||
|
||||
constructor(private http: HttpClient) {}
|
||||
@@ -30,6 +87,83 @@ export class ApiService {
|
||||
return c.startsWith('0x') ? '#' + c.slice(2) : c;
|
||||
}
|
||||
|
||||
private normalizeDeliveryData(
|
||||
raw: any,
|
||||
legacyDeliveryPrice?: number
|
||||
): { options: DeliveryOption[]; isDigital: boolean; requiresSelection: boolean } {
|
||||
const rawDelivery = raw.delivery ?? raw.deliveries;
|
||||
|
||||
if (typeof rawDelivery === 'string' && rawDelivery.trim().toLowerCase() === 'digital') {
|
||||
return { options: [], isDigital: true, requiresSelection: false };
|
||||
}
|
||||
|
||||
const deliveryCandidates = Array.isArray(rawDelivery)
|
||||
? rawDelivery
|
||||
: rawDelivery != null
|
||||
? [rawDelivery]
|
||||
: [];
|
||||
const options = deliveryCandidates
|
||||
.map(candidate => normalizeDeliveryOption(candidate))
|
||||
.filter((option): option is DeliveryOption => option !== null);
|
||||
|
||||
if (options.length > 0) {
|
||||
return { options, isDigital: false, requiresSelection: rawDelivery != null };
|
||||
}
|
||||
|
||||
if (legacyDeliveryPrice !== undefined) {
|
||||
return {
|
||||
options: [{ deliveryPrice: legacyDeliveryPrice, deliveryPlace: '', deliveryTime: '' }],
|
||||
isDigital: false,
|
||||
requiresSelection: false,
|
||||
};
|
||||
}
|
||||
|
||||
if (rawDelivery != null) {
|
||||
return { options: [], isDigital: true, requiresSelection: false };
|
||||
}
|
||||
|
||||
return { options: [], isDigital: false, requiresSelection: false };
|
||||
}
|
||||
|
||||
private normalizeSubcategory(raw: any): Subcategory {
|
||||
const subcategory: Subcategory = {
|
||||
id: String(raw.id ?? raw.categoryId ?? raw.categoryID ?? ''),
|
||||
name: typeof raw.name === 'string' ? raw.name : '',
|
||||
visible: raw.visible ?? true,
|
||||
priority: raw.priority ?? 0,
|
||||
img: raw.img ? this.resolveImageUrl(raw.img) : undefined,
|
||||
categoryId: String(raw.categoryId ?? raw.categoryID ?? raw.id ?? ''),
|
||||
parentId: String(raw.parentId ?? raw.parentID ?? ''),
|
||||
itemCount: raw.itemCount ?? raw.ItemsCount ?? 0,
|
||||
hasItems: raw.hasItems,
|
||||
subcategories: Array.isArray(raw.subcategories)
|
||||
? raw.subcategories
|
||||
.map((sub: any) => this.normalizeSubcategory(sub))
|
||||
.filter((sub: Subcategory) => this.isDisplayableSubcategory(sub))
|
||||
: [],
|
||||
};
|
||||
|
||||
return subcategory;
|
||||
}
|
||||
|
||||
private isDisplayableSubcategory(subcategory: Subcategory): boolean {
|
||||
if (subcategory.visible === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return (subcategory.itemCount ?? 0) > 0
|
||||
|| subcategory.hasItems === true
|
||||
|| (subcategory.subcategories?.length ?? 0) > 0;
|
||||
}
|
||||
|
||||
private isDisplayableCategory(category: Category): boolean {
|
||||
return category.visible !== false;
|
||||
}
|
||||
|
||||
private isDisplayableItem(item: Item): boolean {
|
||||
return item.visible !== false;
|
||||
}
|
||||
|
||||
/** Resolve relative image URLs (e.g. ./images/x.webp) against site origin */
|
||||
private resolveImageUrl(url: string): string {
|
||||
if (!url) return '';
|
||||
@@ -46,6 +180,9 @@ export class ApiService {
|
||||
private normalizeItem(raw: any): Item {
|
||||
const { partnerID, ...rest } = raw;
|
||||
const item: Item = { ...rest };
|
||||
let legacyDeliveryPrice = normalizeOptionalNumber(
|
||||
raw.deliveryPrice ?? raw.delivery_price ?? raw.deliveryprice
|
||||
);
|
||||
|
||||
// Extract price/currency/remaining/colour/size from itemDetails[]
|
||||
// Note: Go struct tag is "itemdetails" but actual API may send "itemDetails"
|
||||
@@ -56,16 +193,33 @@ export class ApiService {
|
||||
...d,
|
||||
colour: this.normalizeColor(d.colour || d.color || ''),
|
||||
color: undefined,
|
||||
deliveryPrice: normalizeOptionalNumber(
|
||||
d.deliveryPrice ?? d.delivery_price ?? d.deliveryprice
|
||||
),
|
||||
}));
|
||||
if (item.price == null || item.price === 0) item.price = detail.price;
|
||||
if (!item.currency) item.currency = detail.currency;
|
||||
if (!item.colour) item.colour = this.normalizeColor(detail.colour || detail.color || '');
|
||||
if (!item.size) item.size = detail.size || '';
|
||||
if (legacyDeliveryPrice === undefined) {
|
||||
legacyDeliveryPrice = normalizeOptionalNumber(
|
||||
detail.deliveryPrice ?? detail.delivery_price ?? detail.deliveryprice
|
||||
);
|
||||
}
|
||||
// Use remaining from detail for stock level
|
||||
if (raw.remaining == null && detail.remaining != null) {
|
||||
(raw as any).remaining = detail.remaining;
|
||||
}
|
||||
}
|
||||
const deliveryData = this.normalizeDeliveryData(raw, legacyDeliveryPrice);
|
||||
if (deliveryData.options.length > 0) {
|
||||
item.deliveryOptions = deliveryData.options;
|
||||
item.deliveryMode = 'selectable';
|
||||
item.deliverySelectionRequired = deliveryData.requiresSelection;
|
||||
} else if (deliveryData.isDigital) {
|
||||
item.deliveryMode = 'digital';
|
||||
item.deliverySelectionRequired = false;
|
||||
}
|
||||
|
||||
// Map backOffice string id → legacy numeric itemID
|
||||
if (raw.id != null && raw.itemID == null) {
|
||||
@@ -186,7 +340,9 @@ export class ApiService {
|
||||
if (!items || !Array.isArray(items)) {
|
||||
return [];
|
||||
}
|
||||
return items.map(item => this.normalizeItem(item));
|
||||
return items
|
||||
.map(item => this.normalizeItem(item))
|
||||
.filter(item => this.isDisplayableItem(item));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -244,7 +400,9 @@ export class ApiService {
|
||||
cat.name = cat.name || '';
|
||||
|
||||
if (raw.subcategories && Array.isArray(raw.subcategories)) {
|
||||
cat.subcategories = raw.subcategories;
|
||||
cat.subcategories = raw.subcategories
|
||||
.map((sub: any) => this.normalizeSubcategory(sub))
|
||||
.filter((sub: Subcategory) => this.isDisplayableSubcategory(sub));
|
||||
}
|
||||
|
||||
return cat;
|
||||
@@ -252,7 +410,9 @@ export class ApiService {
|
||||
|
||||
private normalizeCategories(cats: any[] | null | undefined): Category[] {
|
||||
if (!cats || !Array.isArray(cats)) return [];
|
||||
return cats.map(c => this.normalizeCategory(c));
|
||||
return cats
|
||||
.map(c => this.normalizeCategory(c))
|
||||
.filter(category => this.isDisplayableCategory(category));
|
||||
}
|
||||
|
||||
// ─── Core Marketplace Endpoints ───────────────────────────
|
||||
@@ -348,57 +508,55 @@ export class ApiService {
|
||||
return this.http.post<{ message: string }>(`${this.baseUrl}/items/${itemID}/questiion`, body);
|
||||
}
|
||||
|
||||
// Payment - SBP Integration via websession QR
|
||||
createPayment(sessionId: string): Observable<{
|
||||
qrId: string;
|
||||
qrStatus: string;
|
||||
qrExpirationDate: string;
|
||||
Payload: string;
|
||||
qrUrl: string;
|
||||
}> {
|
||||
return this.http.post<{
|
||||
qrId: string;
|
||||
qrStatus: string;
|
||||
qrExpirationDate: string;
|
||||
Payload: string;
|
||||
qrUrl: string;
|
||||
}>(`${this.baseUrl}/websession/${sessionId}/qr`, {});
|
||||
createPayment(payload: QrCreateRequest, headers?: { authorizationKey?: string; userIdValue?: string }): Observable<QrCreateResponse> {
|
||||
let httpHeaders = new HttpHeaders();
|
||||
if (headers?.authorizationKey) {
|
||||
httpHeaders = httpHeaders.set('authorization-key', headers.authorizationKey);
|
||||
}
|
||||
if (headers?.userIdValue) {
|
||||
httpHeaders = httpHeaders.set('userid-value', headers.userIdValue);
|
||||
}
|
||||
return this.http.post<QrCreateResponse>(`${this.qrBaseUrl}/qr`, payload, { headers: httpHeaders });
|
||||
}
|
||||
|
||||
checkPaymentStatus(sessionId: string, qrId: string): Observable<{
|
||||
additionalInfo: string;
|
||||
paymentPurpose: string;
|
||||
amount: number;
|
||||
code: string;
|
||||
createDate: string;
|
||||
currency: string;
|
||||
order: string;
|
||||
paymentStatus: string;
|
||||
qrId: string;
|
||||
transactionDate: string;
|
||||
transactionId: number;
|
||||
qrExpirationDate: string;
|
||||
}> {
|
||||
return this.http.get<{
|
||||
additionalInfo: string;
|
||||
paymentPurpose: string;
|
||||
amount: number;
|
||||
code: string;
|
||||
createDate: string;
|
||||
currency: string;
|
||||
order: string;
|
||||
paymentStatus: string;
|
||||
qrId: string;
|
||||
transactionDate: string;
|
||||
transactionId: number;
|
||||
qrExpirationDate: string;
|
||||
}>(`${this.baseUrl}/websession/${sessionId}/${qrId}`);
|
||||
createCartPayment(payload: CartPaymentRequest): Observable<QrCreateResponse> {
|
||||
return this.http.post<QrCreateResponse>(`${this.baseUrl}/cart`, payload);
|
||||
}
|
||||
|
||||
checkCartPaymentStatus(qrId: string): Observable<QrDynamicStatusResponse> {
|
||||
return this.http.get<QrDynamicStatusResponse>(
|
||||
`${this.qrBaseUrl}/qr/dynamic/${this.cartPaymentPartnerId}/${encodeURIComponent(qrId)}`
|
||||
);
|
||||
}
|
||||
|
||||
checkPaymentStatus(partnerQrId: string, qrId: string): Observable<QrDynamicStatusResponse> {
|
||||
return this.http.get<QrDynamicStatusResponse>(
|
||||
`${this.qrBaseUrl}/qr/dynamic/${encodeURIComponent(partnerQrId)}/${encodeURIComponent(qrId)}`
|
||||
);
|
||||
}
|
||||
|
||||
resolvePaymentQrId(response: QrCreateResponse): string {
|
||||
return response.qrId ?? response.qrID ?? response.nspkID ?? response.nspkId ?? '';
|
||||
}
|
||||
|
||||
resolvePaymentLink(response: QrCreateResponse): string {
|
||||
return response.nspkurl ?? response.Payload ?? response.payload ?? response.qrUrl ?? '';
|
||||
}
|
||||
|
||||
resolvePaymentQrUrl(response: QrCreateResponse): string {
|
||||
const paymentLink = this.resolvePaymentLink(response);
|
||||
if (paymentLink) {
|
||||
return `https://api.qrserver.com/v1/create-qr-code/?size=256x256&margin=8&data=${encodeURIComponent(paymentLink)}`;
|
||||
}
|
||||
|
||||
return response.qrUrl ?? '';
|
||||
}
|
||||
|
||||
submitPurchaseEmail(emailData: {
|
||||
email: string;
|
||||
phone?: string;
|
||||
telegramUserId: string | null;
|
||||
items: Array<{ itemID: number; name: string; price: number; currency: string }>;
|
||||
items: Array<{ itemID: number; name: string; price: number; currency: string; quantity?: number; delivery?: DeliveryOption }>;
|
||||
}): Observable<{ message: string }> {
|
||||
return this.http.post<{ message: string }>(`${this.baseUrl}/purchase-email`, emailData);
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user