feat: add channel icon component (#10471)
This pull request introduces a new `ChannelIcon` component and refactors the existing code to use this component, which simplifies the icon management for different channel types and providers.
This commit is contained in:
@@ -0,0 +1,17 @@
|
|||||||
|
<script setup>
|
||||||
|
import { useChannelIcon } from './provider';
|
||||||
|
import Icon from 'next/icon/Icon.vue';
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
inbox: {
|
||||||
|
type: Object,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const channelIcon = useChannelIcon(props.inbox);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<Icon :icon="channelIcon" />
|
||||||
|
</template>
|
||||||
36
app/javascript/dashboard/components-next/icon/provider.js
Normal file
36
app/javascript/dashboard/components-next/icon/provider.js
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
import { computed } from 'vue';
|
||||||
|
|
||||||
|
export function useChannelIcon(inbox) {
|
||||||
|
const channelTypeIconMap = {
|
||||||
|
'Channel::Api': 'i-ri-cloudy-fill',
|
||||||
|
'Channel::Email': 'i-ri-mail-fill',
|
||||||
|
'Channel::FacebookPage': 'i-ri-messenger-fill',
|
||||||
|
'Channel::Line': 'i-ri-line-fill',
|
||||||
|
'Channel::Sms': 'i-ri-chat-1-fill',
|
||||||
|
'Channel::Telegram': 'i-ri-telegram-fill',
|
||||||
|
'Channel::TwilioSms': 'i-ri-chat-1-fill',
|
||||||
|
'Channel::TwitterProfile': 'i-ri-twitter-x-fill',
|
||||||
|
'Channel::WebWidget': 'i-ri-global-fill',
|
||||||
|
'Channel::Whatsapp': 'i-ri-whatsapp-fill',
|
||||||
|
};
|
||||||
|
|
||||||
|
const providerIconMap = {
|
||||||
|
microsoft: 'i-ri-microsoft-fill',
|
||||||
|
google: 'i-ri-google-fill',
|
||||||
|
};
|
||||||
|
|
||||||
|
const channelIcon = computed(() => {
|
||||||
|
const type = inbox.channel_type;
|
||||||
|
let icon = channelTypeIconMap[type];
|
||||||
|
|
||||||
|
if (type === 'Channel::Email' && inbox.provider) {
|
||||||
|
if (Object.keys(providerIconMap).includes(inbox.provider)) {
|
||||||
|
icon = providerIconMap[inbox.provider];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return icon ?? 'i-ri-global-fill';
|
||||||
|
});
|
||||||
|
|
||||||
|
return channelIcon;
|
||||||
|
}
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
import { useChannelIcon } from '../provider';
|
||||||
|
|
||||||
|
describe('useChannelIcon', () => {
|
||||||
|
it('returns correct icon for API channel', () => {
|
||||||
|
const inbox = { channel_type: 'Channel::Api' };
|
||||||
|
const { value: icon } = useChannelIcon(inbox);
|
||||||
|
expect(icon).toBe('i-ri-cloudy-fill');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns correct icon for Facebook channel', () => {
|
||||||
|
const inbox = { channel_type: 'Channel::FacebookPage' };
|
||||||
|
const { value: icon } = useChannelIcon(inbox);
|
||||||
|
expect(icon).toBe('i-ri-messenger-fill');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns correct icon for WhatsApp channel', () => {
|
||||||
|
const inbox = { channel_type: 'Channel::Whatsapp' };
|
||||||
|
const { value: icon } = useChannelIcon(inbox);
|
||||||
|
expect(icon).toBe('i-ri-whatsapp-fill');
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Email channel', () => {
|
||||||
|
it('returns mail icon for generic email channel', () => {
|
||||||
|
const inbox = { channel_type: 'Channel::Email' };
|
||||||
|
const { value: icon } = useChannelIcon(inbox);
|
||||||
|
expect(icon).toBe('i-ri-mail-fill');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns Microsoft icon for Microsoft email provider', () => {
|
||||||
|
const inbox = {
|
||||||
|
channel_type: 'Channel::Email',
|
||||||
|
provider: 'microsoft',
|
||||||
|
};
|
||||||
|
const { value: icon } = useChannelIcon(inbox);
|
||||||
|
expect(icon).toBe('i-ri-microsoft-fill');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns Google icon for Google email provider', () => {
|
||||||
|
const inbox = {
|
||||||
|
channel_type: 'Channel::Email',
|
||||||
|
provider: 'google',
|
||||||
|
};
|
||||||
|
const { value: icon } = useChannelIcon(inbox);
|
||||||
|
expect(icon).toBe('i-ri-google-fill');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns default icon for unknown channel type', () => {
|
||||||
|
const inbox = { channel_type: 'Channel::Unknown' };
|
||||||
|
const { value: icon } = useChannelIcon(inbox);
|
||||||
|
expect(icon).toBe('i-ri-global-fill');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns default icon when channel type is undefined', () => {
|
||||||
|
const inbox = {};
|
||||||
|
const { value: icon } = useChannelIcon(inbox);
|
||||||
|
expect(icon).toBe('i-ri-global-fill');
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { computed } from 'vue';
|
import { computed } from 'vue';
|
||||||
import Icon from 'next/icon/Icon.vue';
|
import Icon from 'next/icon/Icon.vue';
|
||||||
|
import ChannelIcon from 'next/icon/ChannelIcon.vue';
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
label: {
|
label: {
|
||||||
@@ -17,37 +18,6 @@ const props = defineProps({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const channelTypeIconMap = {
|
|
||||||
'Channel::Api': 'i-ri-cloudy-fill',
|
|
||||||
'Channel::Email': 'i-ri-mail-fill',
|
|
||||||
'Channel::FacebookPage': 'i-ri-messenger-fill',
|
|
||||||
'Channel::Line': 'i-ri-line-fill',
|
|
||||||
'Channel::Sms': 'i-ri-chat-1-fill',
|
|
||||||
'Channel::Telegram': 'i-ri-telegram-fill',
|
|
||||||
'Channel::TwilioSms': 'i-ri-chat-1-fill',
|
|
||||||
'Channel::TwitterProfile': 'i-ri-twitter-x-fill',
|
|
||||||
'Channel::WebWidget': 'i-ri-global-fill',
|
|
||||||
'Channel::Whatsapp': 'i-ri-whatsapp-fill',
|
|
||||||
};
|
|
||||||
|
|
||||||
const providerIconMap = {
|
|
||||||
microsoft: 'i-ri-microsoft-fill',
|
|
||||||
google: 'i-ri-google-fill',
|
|
||||||
};
|
|
||||||
|
|
||||||
const channelIcon = computed(() => {
|
|
||||||
const type = props.inbox.channel_type;
|
|
||||||
let icon = channelTypeIconMap[type];
|
|
||||||
|
|
||||||
if (type === 'Channel::Email' && props.inbox.provider) {
|
|
||||||
if (Object.keys(providerIconMap).includes(props.inbox.provider)) {
|
|
||||||
icon = providerIconMap[props.inbox.provider];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return icon ?? 'i-ri-global-fill';
|
|
||||||
});
|
|
||||||
|
|
||||||
const reauthorizationRequired = computed(() => {
|
const reauthorizationRequired = computed(() => {
|
||||||
return props.inbox.reauthorization_required;
|
return props.inbox.reauthorization_required;
|
||||||
});
|
});
|
||||||
@@ -58,7 +28,7 @@ const reauthorizationRequired = computed(() => {
|
|||||||
class="size-4 grid place-content-center rounded-full bg-n-alpha-2"
|
class="size-4 grid place-content-center rounded-full bg-n-alpha-2"
|
||||||
:class="{ 'bg-n-solid-blue': active }"
|
:class="{ 'bg-n-solid-blue': active }"
|
||||||
>
|
>
|
||||||
<Icon :icon="channelIcon" class="size-3" />
|
<ChannelIcon :inbox="inbox" class="size-3" />
|
||||||
</span>
|
</span>
|
||||||
<div class="flex-1 truncate min-w-0">{{ label }}</div>
|
<div class="flex-1 truncate min-w-0">{{ label }}</div>
|
||||||
<div
|
<div
|
||||||
|
|||||||
Reference in New Issue
Block a user