Skip to content

Commit

Permalink
Merge branch 'staging' into ft-channel-id
Browse files Browse the repository at this point in the history
  • Loading branch information
Codebmk committed Sep 13, 2024
2 parents 33854e7 + bdfca84 commit 069eb04
Show file tree
Hide file tree
Showing 14 changed files with 475 additions and 1,315 deletions.
2 changes: 1 addition & 1 deletion k8s/netmanager/values-prod.yaml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
replicaCount: 2
image:
repository: eu.gcr.io/airqo-250220/airqo-platform-frontend
tag: prod-9ae00fa8-1725978192
tag: prod-272cbf00-1726152605
pullPolicy: Always
imagePullSecrets: []
nameOverride: ''
Expand Down
2 changes: 1 addition & 1 deletion k8s/netmanager/values-stage.yaml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
replicaCount: 2
image:
repository: eu.gcr.io/airqo-250220/airqo-stage-platform-frontend
tag: stage-8d14edb9-1725978057
tag: stage-5d88c47f-1726152296
pullPolicy: Always
imagePullSecrets: []
nameOverride: ''
Expand Down
2 changes: 1 addition & 1 deletion k8s/platform/values-stage.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ replicaCount: 1
image:
repository: eu.gcr.io/airqo-250220/airqo-stage-next-platform
pullPolicy: Always
tag: stage-a80c37b0-1724261363
tag: stage-6add04b2-1726203903
imagePullSecrets: []
nameOverride: ''
fullnameOverride: ''
Expand Down
23 changes: 23 additions & 0 deletions platform/public/icons/Actions/DeleteIcon.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import React from 'react';

const DeleteIcon = (props) => {
return (
<svg
xmlns='http://www.w3.org/2000/svg'
width={24}
height={24}
viewBox='0 0 24 24'
fill='none'
{...props}>
<path
d='M9 3h6M3 6h18m-2 0l-.701 10.52c-.105 1.578-.158 2.367-.499 2.965a3 3 0 01-1.298 1.215c-.62.3-1.41.3-2.993.3h-3.018c-1.582 0-2.373 0-2.993-.3A3 3 0 016.2 19.485c-.34-.598-.394-1.387-.499-2.966L5 6m5 4.5v5m4-5v5'
stroke={props.fill || '#1C1D20'}
strokeWidth={1.5}
strokeLinecap='round'
strokeLinejoin='round'
/>
</svg>
);
};

export default DeleteIcon;
23 changes: 23 additions & 0 deletions platform/public/icons/Actions/PlusIcon.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import React from 'react';

const PlusIcon = (props) => {
return (
<svg
width={16}
height={16}
viewBox='0 0 16 16'
fill='none'
xmlns='http://www.w3.org/2000/svg'
{...props}>
<path
d='M8.003 3.332v9.333M3.336 8h9.333'
stroke={props.fill || '#fff'}
strokeWidth={1.2}
strokeLinecap='round'
strokeLinejoin='round'
/>
</svg>
);
};

export default PlusIcon;
97 changes: 54 additions & 43 deletions platform/src/common/components/Settings/API/AddClientForm.jsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import PersonIcon from '@/icons/Settings/person.svg';
import { useState } from 'react';
import { useSelector } from 'react-redux';
import { useSelector, useDispatch } from 'react-redux';
import DialogWrapper from '../../Modal/DialogWrapper';
import Toast from '@/components/Toast';
import { createClientApi } from '@/core/apis/Settings';
import { useDispatch } from 'react-redux';
import { addClients } from '@/lib/store/services/apiClient';
import { addClients, performRefresh } from '@/lib/store/services/apiClient';
import { getUserDetails } from '@/core/apis/Account';
import PlusIcon from '@/icons/Actions/PlusIcon';
import DeleteIcon from '@/icons/Actions/DeleteIcon';

const AddClientForm = ({ open, closeModal }) => {
const dispatch = useDispatch();
Expand All @@ -17,25 +18,32 @@ const AddClientForm = ({ open, closeModal }) => {
type: '',
});
const [clientName, setClientName] = useState('');
const [ipAddress, setIpAddress] = useState('');
const [ipAddresses, setIpAddresses] = useState(['']);
const userInfo = useSelector((state) => state.login.userInfo);

const handleInputValueChange = (type, value) => {
const handleInputValueChange = (type, value, index) => {
if (type === 'clientName') {
setClientName(value);
} else if (type === 'ipAddress') {
setIpAddress(value);
const newIpAddresses = [...ipAddresses];
newIpAddresses[index] = value;
setIpAddresses(newIpAddresses);
}
};

const handleRemoveInputValue = (value) => {
if (value === 'clientName') {
const handleRemoveInputValue = (type, index) => {
if (type === 'clientName') {
setClientName('');
} else if (value === 'ipAddress') {
setIpAddress('');
} else if (type === 'ipAddress') {
const newIpAddresses = ipAddresses.filter((_, i) => i !== index);
setIpAddresses(newIpAddresses);
}
};

const handleAddIpAddress = () => {
setIpAddresses([...ipAddresses, '']);
};

const handleSubmit = async () => {
setLoading(true);

Expand All @@ -47,13 +55,8 @@ const AddClientForm = ({ open, closeModal }) => {
});
};

// TODO: Handling cases where clientName is empty
if (!clientName) {
setIsError({
isError: true,
message: "Client name can't be empty",
type: 'error',
});
setErrorState("Client name can't be empty");
setLoading(false);
return;
}
Expand All @@ -64,9 +67,9 @@ const AddClientForm = ({ open, closeModal }) => {
user_id: userInfo?._id,
};

// Add ipAddress to data if it is not empty
if (ipAddress) {
data.ip_address = ipAddress;
const filteredIpAddresses = ipAddresses.filter((ip) => ip.trim() !== '');
if (filteredIpAddresses.length > 0) {
data.ip_addresses = filteredIpAddresses;
}

const response = await createClientApi(data);
Expand All @@ -78,6 +81,7 @@ const AddClientForm = ({ open, closeModal }) => {
dispatch(addClients(res.users[0].clients));
}
}
dispatch(performRefresh());
closeModal();
} catch (error) {
setErrorState(error?.response?.data?.message || 'Failed to create client');
Expand All @@ -91,15 +95,15 @@ const AddClientForm = ({ open, closeModal }) => {
open={open}
onClose={closeModal}
handleClick={handleSubmit}
primaryButtonText={'Register'}
primaryButtonText='Register'
loading={loading}
ModalIcon={PersonIcon}>
{isError?.isError && <Toast type={isError?.type} message={isError?.message} />}
<h3 className='text-lg font-medium text-secondary-neutral-light-800 leading-[26px] mb-2'>
Create new client
</h3>

<div className='flex flex-col gap-3 justify-start'>
<div className='flex flex-col gap-3 justify-start max-h-[350px] overflow-y-auto'>
<div className='relative'>
<input
type='text'
Expand All @@ -108,33 +112,40 @@ const AddClientForm = ({ open, closeModal }) => {
value={clientName}
onChange={(e) => handleInputValueChange('clientName', e.target.value)}
/>

{clientName?.length > 0 && (
{clientName && (
<button
className='absolute inset-y-0 right-0 flex justify-center items-center mr-3 pointer-events-auto'
onClick={() => handleRemoveInputValue(clientName)}>
className='absolute inset-y-0 right-0 flex justify-center items-center mr-3'
onClick={() => handleRemoveInputValue('clientName')}>
x
</button>
)}
</div>

<div className='relative'>
<input
type='text'
placeholder='Enter ip address (optional)'
className='input input-bordered w-full pl-3 placeholder-shown:text-secondary-neutral-light-300 text-secondary-neutral-light-800 text-sm leading-[26px] border border-secondary-neutral-light-100 bg-secondary-neutral-light-25 rounded'
value={ipAddress}
onChange={(e) => handleInputValueChange('ipAddress', e.target.value)}
/>

{ipAddress?.length > 0 && (
<button
className='absolute inset-y-0 right-0 flex justify-center items-center mr-3 pointer-events-auto'
onClick={() => handleRemoveInputValue(ipAddress)}>
</button>
)}
</div>
{ipAddresses.map((ip, index) => (
<div key={index} className='relative'>
<input
type='text'
placeholder={`${index > 0 ? `Enter IP address ${index + 1}` : 'Enter IP address (Optional)'}`}
className='input input-bordered w-full pl-3 placeholder-shown:text-secondary-neutral-light-300 text-secondary-neutral-light-800 text-sm leading-[26px] border border-secondary-neutral-light-100 bg-secondary-neutral-light-25 rounded'
value={ip}
onChange={(e) => handleInputValueChange('ipAddress', e.target.value, index)}
/>
{index > 0 && (
<button
className='absolute inset-y-0 right-0 flex justify-center items-center mr-3'
onClick={() => handleRemoveInputValue('ipAddress', index)}>
<DeleteIcon />
</button>
)}
</div>
))}

<button
onClick={handleAddIpAddress}
className='flex items-center justify-start text-sm text-blue-600 hover:text-blue-800'>
<PlusIcon size={16} className='mr-1' fill={'black'} />
Add another IP address
</button>
</div>
</DialogWrapper>
);
Expand Down
43 changes: 20 additions & 23 deletions platform/src/common/components/Settings/API/AdminClientsTable.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ const AdminClientsTable = () => {
});
const [isLoading, setIsLoading] = useState(false);
const [isLoadingActivation, setIsLoadingActivation] = useState(false);
const [isLoadingDeactivation, setIsLoadingDeactivation] = useState(false);
const [confirmClientActivation, setConfirmClientActivation] = useState(false);
const [confirmClientDeactivation, setConfirmClientDeactivation] = useState(false);
const [isActivated, setIsActivated] = useState(false);
Expand Down Expand Up @@ -80,7 +81,7 @@ const AdminClientsTable = () => {
};

const handleDeactivate = async () => {
setIsLoadingActivation(true);
setIsLoadingDeactivation(true);
const data = {
_id: selectedClient._id,
isActive: false,
Expand All @@ -95,20 +96,25 @@ const AdminClientsTable = () => {
setErrorState('Failed to deactivate client', 'error');
})
.finally(() => {
setIsLoadingActivation(false);
setIsLoadingDeactivation(false);
setConfirmClientDeactivation(false);
setSelectedClient(null);
});
};

const displayIPAddresses = (client) => {
return Array.isArray(client.ip_addresses)
? client.ip_addresses.join(', ')
: client.ip_addresses;
};

return (
<div>
<div className='overflow-x-scroll'>
{isError.isError && <Toast type={isError.type} message={isError.message} />}
<table
className='border-collapse rounded-lg text-xs text-left w-full mb-6'
data-testid='settings-clients-table'
>
data-testid='settings-clients-table'>
<thead>
<tr className='text-secondary-neutral-light-500 text-xs border-y border-y-secondary-neutral-light-100 bg-secondary-neutral-light-25'>
<th scope='col' className='font-medium w-[200px] px-4 py-3 opacity-40'>
Expand Down Expand Up @@ -141,37 +147,32 @@ const AdminClientsTable = () => {
<tr className={`border-b border-b-secondary-neutral-light-100`} key={index}>
<td
scope='row'
className='w-[200px] px-4 py-3 font-medium text-sm leading-5 text-secondary-neutral-light-800 uppercase'
>
className='w-[200px] px-4 py-3 font-medium text-sm leading-5 text-secondary-neutral-light-800 uppercase'>
{client?.name}
</td>
<td
scope='row'
className='w-[138px] px-4 py-3 font-medium text-sm leading-5 text-secondary-neutral-light-400'
>
className='w-[138px] px-4 py-3 font-medium text-sm leading-5 text-secondary-neutral-light-400'>
{client?._id}
</td>
<td
scope='row'
className='w-[138px] px-4 py-3 font-medium text-sm leading-5 text-secondary-neutral-light-400'
>
{client?.ip_address}
className='w-[138px] px-4 py-3 font-medium text-sm leading-5 text-secondary-neutral-light-400'>
{displayIPAddresses(client)}
</td>
<td scope='row' className='w-[138px] px-4 py-3'>
<div
className={`px-2 py-[2px] rounded-2xl w-auto inline-flex justify-center text-sm leading-5 items-center mx-auto ${
client?.isActive
? 'bg-success-50 text-success-700'
: 'bg-secondary-neutral-light-50 text-secondary-neutral-light-500'
}`}
>
}`}>
{client?.isActive ? 'Activated' : 'Not Activated'}
</div>
</td>
<td
scope='row'
className='w-[138px] px-4 py-3 font-medium text-sm leading-5 text-secondary-neutral-light-400 capitalize flex items-center gap-2'
>
className='w-[138px] px-4 py-3 font-medium text-sm leading-5 text-secondary-neutral-light-400 capitalize flex items-center gap-2'>
<div
className={`w-9 h-9 p-2.5 bg-white rounded border border-gray-200 flex justify-center items-center ${
client?.isActive ? 'cursor-not-allowed' : 'cursor-pointer'
Expand All @@ -185,8 +186,7 @@ const AdminClientsTable = () => {
}}
title={
client?.isActive ? 'Client is already activated' : 'Activate client'
}
>
}>
<CheckIcon />
</div>
<div
Expand All @@ -204,8 +204,7 @@ const AdminClientsTable = () => {
!client?.isActive
? 'Client is already deactivated'
: 'Deactivate client'
}
>
}>
<CloseIcon />
</div>
</td>
Expand Down Expand Up @@ -236,8 +235,7 @@ const AdminClientsTable = () => {
onClose={() => setConfirmClientActivation(false)}
handleClick={handleActivate}
primaryButtonText={'Activate'}
loading={isLoadingActivation}
>
loading={isLoadingActivation}>
<h3 className='self-stretch text-gray-700 text-lg font-medium leading-relaxed'>
Activate client
</h3>
Expand All @@ -248,8 +246,7 @@ const AdminClientsTable = () => {
onClose={() => setConfirmClientDeactivation(false)}
handleClick={handleDeactivate}
primaryButtonText={'Deactivate'}
loading={isLoadingActivation}
>
loading={isLoadingDeactivation}>
<h3 className='self-stretch text-gray-700 text-lg font-medium leading-relaxed'>
Deactivate client
</h3>
Expand Down
Loading

0 comments on commit 069eb04

Please sign in to comment.