-
Notifications
You must be signed in to change notification settings - Fork 14
/
Copy pathGitAliasListItem.tsx
136 lines (126 loc) · 5.4 KB
/
GitAliasListItem.tsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
"use client"
import axios from 'axios';
import { useState } from 'react';
import { MdDone, MdEdit } from 'react-icons/md';
import type { AliasMap, HandleMap } from '../types/AliasMap';
import type { RepoProvider } from '../utils/providerAPI';
import { getPreferredTheme } from '../utils/theme';
import Button from './Button';
import Chip from './Chip';
import ChipInput, { ChipData } from './ChipInput';
import { getProviderLogoSrc } from './ProviderLogo';
const GitAliasListItem = ({ providerMap, setProviderMap }: { providerMap: AliasMap, setProviderMap: (providerMap: AliasMap) => void }) => {
const [editMode, setEditMode] = useState(false);
const [inputHandleMap, setInputHandleMap] = useState<HandleMap[]>(providerMap.handleMaps);
const [loading, setLoading] = useState<boolean>(false);
const [errorMsg, setErrorMsg] = useState<string>("");
const currentTheme = getPreferredTheme();
const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
setLoading(true);
setErrorMsg("");
try {
const updatedAliasMap: AliasMap = {
alias: providerMap.alias,
handleMaps: inputHandleMap.map(handleMap => ({
provider: handleMap.provider,
handles: handleMap.handles.filter(handle => handle !== '') // Remove empty handles,
}))
}
const response = await axios.post('/api/alias', { aliasHandleMap: updatedAliasMap }, {
headers: {
'Content-Type': 'application/json',
},
});
if (!response || response.status !== 200) {
throw new Error('Failed to save Git alias map');
}
// success
setProviderMap(updatedAliasMap);
setEditMode(false);
} catch (error) {
console.error("Error saving Git aliases:", error);
setErrorMsg("An error occurred while saving Git aliases. Please try again.");
} finally {
setLoading(false);
}
};
const abort = () => {
setEditMode(false);
setErrorMsg("");
};
const handleAdd = (provider: RepoProvider) => (chipData: ChipData) => {
// Get current value and split into array
const invalidValues = new Set([null, 'null', 'NULL', '']);
const updatedHandleInputValues = inputHandleMap.map(handleInputValue => {
if (handleInputValue.provider !== provider) return handleInputValue;
const filteredHandles = handleInputValue.handles.filter(handle => !invalidValues.has(handle));
// check if the new value is a duplicate
const isDuplicate = filteredHandles.some(handle => handle === chipData.text);
if (isDuplicate) {
console.warn('Duplicate values are not allowed');
return handleInputValue;
}
return { ...handleInputValue, handles: [...handleInputValue.handles, chipData.text] };
});
setInputHandleMap(updatedHandleInputValues);
};
const handleRemove = (provider: RepoProvider) => (chipData: ChipData) => {
// remove the last value from the handles list
const updatedHandleInputValues = inputHandleMap.map(handleInputValue => {
if (handleInputValue.provider !== provider) return handleInputValue;
// check if the value doesn't exist
const isValueInHandles = handleInputValue.handles.some(handle => handle === chipData.text);
if (!isValueInHandles) {
console.warn('Value does not exist in handles list');
return handleInputValue;
}
return { ...handleInputValue, handles: handleInputValue.handles.filter((handle) => handle !== chipData.text) };
});
setInputHandleMap(updatedHandleInputValues);
};
return (
<div key={providerMap.alias} className="flex border-b border-border last-of-type:border-0 w-full p-4 flex-wrap items-center">
<p className="w-full md:w-fit md:grow break-words">{providerMap.alias}</p>
{(editMode) ? (
<form
onSubmit={handleSubmit}
className="grow flex flex-wrap items-end gap-2 justify-end"
onKeyDown={(e) => e.key === 'Escape' && abort()}
>
{providerMap.handleMaps.map(handleMap => (
<div key={handleMap.provider} className='grow relative mt-2'>
<ChipInput
onAdd={handleAdd(handleMap.provider)}
onRemove={handleRemove(handleMap.provider)}
defaultValues={inputHandleMap.find(inputValue => inputValue.provider === handleMap.provider)?.handles.map(handle => (
{ text: handle, avatar: getProviderLogoSrc(handleMap.provider, currentTheme) }
))}
placeholder={`${handleMap.provider} handles`}
getAvatarFromValue={(_) => getProviderLogoSrc(handleMap.provider, currentTheme)}
disabled={loading}
/>
<label htmlFor={`${handleMap.provider}-handles`} className="absolute -top-2 left-2 text-xs px-1 bg-gradient-to-t from-input to-background">
{handleMap.provider.charAt(0).toUpperCase() + handleMap.provider.slice(1) + " handles"}
</label>
</div>
))}
<Button title='Save' variant="contained" type="submit" className='grow-0 !p-2 my-auto' disabled={loading}>
<MdDone className="w-7 h-7 hover:text-secondary-foreground/60" />
</Button>
</form>
) : (<>
{providerMap.handleMaps?.map((handleMap: HandleMap) =>
handleMap.handles.map((handle: string) => (
<Chip key={handle} name={handle} avatar={getProviderLogoSrc(handleMap.provider, currentTheme)} disabled={false} className="h-fit bg-primary" />
)))
}
<Button title='Edit' variant="text" onClick={() => setEditMode(true)}>
<MdEdit className="w-6 h-6 hover:text-primary-foreground/60" />
</Button>
</>)}
{errorMsg && <p className="text-red-500 w-full text-end text-sm">{errorMsg}</p>}
</div>
);
};
export default GitAliasListItem;