Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Multiplacement #8

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 19 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@
UiScrollbar,
UiTag,
UiTransition,
CrmYandexMap
CrmYandexMap,
CrmPlacement
```

Более подробно познакомиться с этими компонентами можно на [витрине](https://design.retailcrm.tech/omnica-vue3/index.html).
Expand Down Expand Up @@ -61,6 +62,13 @@

## API Ядра в карточке заказа

```javascript
api.getPlacement
```
Возвращает информацию о placement (места встраивания компонентов приложения в интерфейс CRM).
Метод принимает 2 параметра - имя плейсмента и название скоупа.
Возвращает массив объектов вида {id, context}, где id - идентификатор точки монтирования, context - специфическая информация для текущего placement.

```javascript
api.getCustomerEmail
```
Expand Down Expand Up @@ -104,6 +112,15 @@ api.parseDeliveryAddress

Стили должны быть модульными

## Монтирование компонентов в интерфейсе хостового приложения
Для монтирования компонентов используется компонент ```CrmPlacement```. В него следует обернуть компоненты приложения, которые должны быть смонтированы в конкретной точке хостового приложения.
Компонент имеет обязательный входной параметр ```placementId``` - идентификатор точки монтирования.

Для того, чтобы получить список доступных точек монтирования, нужно вызвать метод ```api.getPlacement(placementName, scopeName)```, который вернет массив объектов вида {id, context}, где
id - идентификатор точки монтирования, context - объект с информацией, специфичной для данной точки.

Например, для плеймента ```customer-phone```, контекст будет вида ```{ phone: string }```.

## В удаленном приложении нужно описать используемые компоненты
```typescript
const CrmYandexMap = defineRemoteComponent('CrmYandexMap', [
Expand All @@ -121,7 +138,6 @@ export { UiButton, UiModalWindow, CrmYandexMap }
```javascript
[{
entrypoint: 'extension-url',
placement: 'delivery-address',
scope: 'order-card',
stylesheet: 'stylesheet-url',
uuid: '1'
Expand Down Expand Up @@ -210,8 +226,7 @@ make zip-archive
```javascript
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

В описании примера наверное надо добавить и про кейс с телефонами?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Добавил

extensionsInit([{
entrypoint: 'http://localhost:3000/extension/62aa8145-ed53-4862-b28f-f1bc6b36a3a3',
placement: 'delivery-address',
scope: 'order-card',
scope: ['order-card', 'customer-card'],
stylesheet: 'http://localhost:3000/extension/62aa8145-ed53-4862-b28f-f1bc6b36a3a3/stylesheet',
uuid: '1'
}])
Expand Down
3 changes: 3 additions & 0 deletions src/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,11 @@ const CrmYandexMap = defineRemoteComponent('CrmYandexMap', [
'change': (address: string) => void,
})

const CrmPlacement = defineRemoteComponent('CrmPlacement')

export {
UiButton,
UiModalWindow,
CrmYandexMap,
CrmPlacement,
}
8 changes: 5 additions & 3 deletions src/extension.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {
createRemoteRenderer,
} from '@omnicajs/vue-remote/remote'

import VExtension from '@/extension/VExtension.vue'
import VApp from '@/extension/VApp.vue'

const endpoint = createEndpoint(fromInsideIframe())

Expand All @@ -21,6 +21,7 @@ const createApp = async (channel, component, props) => {
'UiModalWindow',
'UiModalWindowSurface',
'CrmYandexMap',
'CrmPlacement',
],
})

Expand All @@ -36,12 +37,13 @@ const createApp = async (channel, component, props) => {
let onRelease = () => {}

endpoint.expose({
async run (channel, api) {
async run (channel, api, scope) {
retain(channel)
retain(api)

const app = await createApp(channel, VExtension, {
const app = await createApp(channel, VApp, {
api,
scope,
})

onRelease = () => {
Expand Down
File renamed without changes.
98 changes: 98 additions & 0 deletions src/extension/CustomerPhoneExtension.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
<template>
<ul
:class="{
[$style['list']]: true,
[$style['list_order']]: isOrderCard
}"
>
<li :class="$style['list__item']">
<a :href="links.whatsapp" target="_blank">
<svg viewBox="0 0 60 60">
<path
style="fill:#2CB742;"
d="M0,58l4.988-14.963C2.457,38.78,1,33.812,1,28.5C1,12.76,13.76,0,29.5,0S58,12.76,58,28.5 S45.24,57,29.5,57c-4.789,0-9.299-1.187-13.26-3.273L0,58z"
/>
<path
style="fill:#FFFFFF;"
d="M47.683,37.985c-1.316-2.487-6.169-5.331-6.169-5.331c-1.098-0.626-2.423-0.696-3.049,0.42
c0,0-1.577,1.891-1.978,2.163c-1.832,1.241-3.529,1.193-5.242-0.52l-3.981-3.981l-3.981-3.981c-1.713-1.713-1.761-3.41-0.52-5.242
c0.272-0.401,2.163-1.978,2.163-1.978c1.116-0.627,1.046-1.951,0.42-3.049c0,0-2.844-4.853-5.331-6.169
c-1.058-0.56-2.357-0.364-3.203,0.482l-1.758,1.758c-5.577,5.577-2.831,11.873,2.746,17.45l5.097,5.097l5.097,5.097
c5.577,5.577,11.873,8.323,17.45,2.746l1.758-1.758C48.048,40.341,48.243,39.042,47.683,37.985z"
/>
</svg>
</a>
</li>
<li :class="$style['list__item']">
<a :href="links.telegram" target="_blank">
<svg viewBox="0 0 30 30" fill="none">
<circle cx="16" cy="16" r="14" fill="#007DBB" />
<path
d="M22.9866 10.2088C23.1112 9.40332 22.3454 8.76755 21.6292 9.082L7.36482 15.3448C6.85123 15.5703 6.8888 16.3483 7.42147 16.5179L10.3631 17.4547C10.9246 17.6335 11.5325 17.541 12.0228 17.2023L18.655 12.6203C18.855 12.4821 19.073 12.7665 18.9021 12.9426L14.1281 17.8646C13.665 18.3421 13.7569 19.1512 14.314 19.5005L19.659 22.8523C20.2585 23.2282 21.0297 22.8506 21.1418 22.1261L22.9866 10.2088Z"
fill="white"
/>
</svg>
</a>
</li>
</ul>
</template>

<script lang="ts" setup>
import { computed } from 'vue'

const SCOPE = {
ORDER_CARD: 'order-card',
CUSTOMER_CARD: 'customer-card',
}

const props = defineProps({
scope: {
type: String,
default: '',
},

phone: {
type: String,
default: null,
},
})

// Пример стилизации в зависимости от scope
const isOrderCard = computed(() => {
return props.scope === SCOPE.ORDER_CARD
})

const links = computed(() => {
return {
whatsapp: `https://wa.me/${props.phone}`,
telegram: `https://t.me/${props.phone}`,
}
})
</script>

<style lang="less" module>
.list {
display: inline-flex;
align-items: center;
gap: 4px;
margin: 0;
transform: translateY(5px);

&__item {
list-style: none;
width: 18px;
height: 18px;
}

&_order {
margin-top: 8px;
margin-bottom: 12px;
transform: none;

.list__item {
width: 24px;
height: 24px;
}
}
}
</style>
71 changes: 71 additions & 0 deletions src/extension/VApp.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
<template>
<!-- Расширение с кнопками перехода в мессенджеры -->
<CrmPlacement
v-for="placement in customerPhonePlacement"
:key="placement.id"
:placement-id="placement.id"
>
<CustomerPhoneExtension
v-if="placement?.context?.phone"
:scope="scope"
:phone="placement.context.phone"
/>
</CrmPlacement>

<!-- Расширение с картой -->
<CrmPlacement
v-if="addressDeliveryPlacement?.length === 1"
:placement-id="addressDeliveryPlacement[0].id"
>
<AddressExtension
:api="{
setDeliveryAddress: api.setDeliveryAddress,
getDeliveryAddress: api.getDeliveryAddress,
}"
/>
</CrmPlacement>
</template>

<script lang="ts" setup>
import type { PropType } from 'vue'
import { onMounted, ref } from 'vue'
import CustomerPhoneExtension from './CustomerPhoneExtension.vue';
import AddressExtension from './AddressExtension.vue';

import {
CrmPlacement,
} from '@/components'

interface IPlacementContext {
phone?: string
address?: string
}

interface IPlacement {
id: string,
context: IPlacementContext
}

const props = defineProps({
api: {
type: Object as PropType<{
getPlacement (placementName: string, scope: string): IPlacement[];
setDeliveryAddress (value: string): void;
getDeliveryAddress (): Promise<string | null>;
}>,
required: true,
},
scope: {
type: String,
default: '',
},
})

const customerPhonePlacement = ref(null as unknown as IPlacement[])
const addressDeliveryPlacement = ref(null as unknown as IPlacement[])

onMounted(async () => {
customerPhonePlacement.value = await props.api.getPlacement('customer-phone', props.scope)
addressDeliveryPlacement.value = await props.api.getPlacement('delivery-address', props.scope)
})
</script>