feat: Add dropdown component (#10358)

This PR adds dropdown primitives to help compose custom dropdowns across the app. The following the sample usage

---------

Co-authored-by: Pranav <pranav@chatwoot.com>
This commit is contained in:
Shivam Mishra
2024-11-19 06:59:27 +05:30
committed by GitHub
parent 54afed9fb4
commit aaa328be87
22 changed files with 497 additions and 224 deletions

View File

@@ -151,8 +151,15 @@ export const actions = {
}
},
updateAvailability: async ({ commit, dispatch }, params) => {
updateAvailability: async (
{ commit, dispatch, getters: _getters },
params
) => {
const previousStatus = _getters.getCurrentUserAvailability;
try {
// optimisticly update current status
commit(types.SET_CURRENT_USER_AVAILABILITY, params.availability);
const response = await authAPI.updateAvailability(params);
const userData = response.data;
const { id } = userData;
@@ -162,16 +169,23 @@ export const actions = {
availabilityStatus: params.availability,
});
} catch (error) {
// Ignore error
// revert back to previous status if update fails
commit(types.SET_CURRENT_USER_AVAILABILITY, previousStatus);
}
},
updateAutoOffline: async ({ commit }, { accountId, autoOffline }) => {
updateAutoOffline: async (
{ commit, getters: _getters },
{ accountId, autoOffline }
) => {
const previousAutoOffline = _getters.getCurrentUserAutoOffline;
try {
commit(types.SET_CURRENT_USER_AUTO_OFFLINE, autoOffline);
const response = await authAPI.updateAutoOffline(accountId, autoOffline);
commit(types.SET_CURRENT_USER, response.data);
} catch (error) {
// Ignore error
commit(types.SET_CURRENT_USER_AUTO_OFFLINE, previousAutoOffline);
}
},
@@ -212,6 +226,19 @@ export const mutations = {
accounts,
};
},
[types.SET_CURRENT_USER_AUTO_OFFLINE](_state, autoOffline) {
const accounts = _state.currentUser.accounts.map(account => {
if (account.id === _state.currentUser.account_id) {
return { ...account, autoOffline: autoOffline };
}
return account;
});
_state.currentUser = {
..._state.currentUser,
accounts,
};
},
[types.CLEAR_USER](_state) {
_state.currentUser = initialState.currentUser;
},

View File

@@ -1,7 +1,7 @@
import axios from 'axios';
import Cookies from 'js-cookie';
import { actions } from '../../auth';
import * as types from '../../../mutation-types';
import types from '../../../mutation-types';
import * as APIHelpers from '../../../utils/api';
import '../../../../routes';
@@ -25,7 +25,7 @@ describe('#actions', () => {
await actions.validityCheck({ commit });
expect(APIHelpers.setUser).toHaveBeenCalledTimes(1);
expect(commit.mock.calls).toEqual([
[types.default.SET_CURRENT_USER, { id: 1, name: 'John' }],
[types.SET_CURRENT_USER, { id: 1, name: 'John' }],
]);
});
it('sends correct actions if API is error', async () => {
@@ -45,7 +45,7 @@ describe('#actions', () => {
});
await actions.updateProfile({ commit }, { name: 'Pranav' });
expect(commit.mock.calls).toEqual([
[types.default.SET_CURRENT_USER, { id: 1, name: 'John' }],
[types.SET_CURRENT_USER, { id: 1, name: 'John' }],
]);
});
});
@@ -61,12 +61,13 @@ describe('#actions', () => {
headers: { expiry: 581842904 },
});
await actions.updateAvailability(
{ commit, dispatch },
{ commit, dispatch, getters: { getCurrentUserAvailability: 'online' } },
{ availability: 'offline', account_id: 1 }
);
expect(commit.mock.calls).toEqual([
[types.SET_CURRENT_USER_AVAILABILITY, 'offline'],
[
types.default.SET_CURRENT_USER,
types.SET_CURRENT_USER,
{
id: 1,
name: 'John',
@@ -81,6 +82,18 @@ describe('#actions', () => {
],
]);
});
it('sends correct actions if API is a failure', async () => {
axios.post.mockRejectedValue({ error: 'Authentication Failure' });
await actions.updateAvailability(
{ commit, dispatch, getters: { getCurrentUserAvailability: 'online' } },
{ availability: 'offline', account_id: 1 }
);
expect(commit.mock.calls).toEqual([
[types.SET_CURRENT_USER_AVAILABILITY, 'offline'],
[types.SET_CURRENT_USER_AVAILABILITY, 'online'],
]);
});
});
describe('#updateAutoOffline', () => {
@@ -99,12 +112,13 @@ describe('#actions', () => {
headers: { expiry: 581842904 },
});
await actions.updateAutoOffline(
{ commit, dispatch },
{ commit, dispatch, getters: { getCurrentUserAutoOffline: true } },
{ autoOffline: false, accountId: 1 }
);
expect(commit.mock.calls).toEqual([
[types.SET_CURRENT_USER_AUTO_OFFLINE, false],
[
types.default.SET_CURRENT_USER,
types.SET_CURRENT_USER,
{
id: 1,
name: 'John',
@@ -113,6 +127,17 @@ describe('#actions', () => {
],
]);
});
it('sends correct actions if API is failure', async () => {
axios.post.mockRejectedValue({ error: 'Authentication Failure' });
await actions.updateAutoOffline(
{ commit, dispatch, getters: { getCurrentUserAutoOffline: true } },
{ autoOffline: false, accountId: 1 }
);
expect(commit.mock.calls).toEqual([
[types.SET_CURRENT_USER_AUTO_OFFLINE, false],
[types.SET_CURRENT_USER_AUTO_OFFLINE, true],
]);
});
});
describe('#updateUISettings', () => {
@@ -132,11 +157,11 @@ describe('#actions', () => {
);
expect(commit.mock.calls).toEqual([
[
types.default.SET_CURRENT_USER_UI_SETTINGS,
types.SET_CURRENT_USER_UI_SETTINGS,
{ uiSettings: { is_contact_sidebar_open: false } },
],
[
types.default.SET_CURRENT_USER,
types.SET_CURRENT_USER,
{
id: 1,
name: 'John',
@@ -160,8 +185,8 @@ describe('#actions', () => {
Cookies.get.mockImplementation(() => false);
actions.setUser({ commit, dispatch });
expect(commit.mock.calls).toEqual([
[types.default.CLEAR_USER],
[types.default.SET_CURRENT_USER_UI_FLAGS, { isFetching: false }],
[types.CLEAR_USER],
[types.SET_CURRENT_USER_UI_FLAGS, { isFetching: false }],
]);
expect(dispatch).toHaveBeenCalledTimes(0);
});
@@ -177,7 +202,7 @@ describe('#actions', () => {
{ 1: 'online' }
);
expect(commit.mock.calls).toEqual([
[types.default.SET_CURRENT_USER_AVAILABILITY, 'online'],
[types.SET_CURRENT_USER_AVAILABILITY, 'online'],
]);
});