LibreChat/client/src/components/Prompts/SharePrompt.tsx
Ruben Talstra aae413cc71
🌎 i18n: React-i18next & i18next Integration (#5720)
* better i18n support an internationalization-framework.

* removed unused package

* auto sort for translation.json

* fixed tests with the new locales function

* added new CI actions from locize

* to use locize a mention in the README.md

* to use locize a mention in the README.md

* updated README.md and added TRANSLATION.md to the repo

* updated TRANSLATION.md badges

* updated README.md to go to the TRANSLATION.md when clicking on the Translation Progress badge

* updated TRANSLATION.md and added a new issue template.

* updated TRANSLATION.md and added a new issue template.

* updated issue template to add the iso code link.

* updated the new GitHub actions for `locize`

* updated label for new issue template --> i18n

* fixed type issue

* Fix eslint

* Fix eslint with key-spacing spacing

* fix: error type

* fix: handle undefined values in SortFilterHeader component

* fix: typing in Image component

* fix: handle optional promptGroup in PromptCard component

* fix: update localize function to accept string type and remove unnecessary JSX element

* fix: update localize function to enforce TranslationKeys type for better type safety

* fix: improve type safety and handle null values in Assistants component

* fix: enhance null checks for fileId in FilesListView component

* fix: localize 'Go back' button text in FilesListView component

* fix: update aria-label for menu buttons and add translation for 'Close Menu'

* docs: add Reasoning UI section for Chain-of-Thought AI models in README

* fix: enhance type safety by adding type for message in MultiMessage component

* fix: improve null checks and optional chaining in useAutoSave hook

* fix: improve handling of optional properties in cleanupPreset function

* fix: ensure isFetchingNextPage defaults to false and improve null checks for messages in Search component

* fix: enhance type safety and null checks in useBuildMessageTree hook

---------

Co-authored-by: Danny Avila <danny@librechat.ai>
2025-02-09 12:05:31 -05:00

143 lines
4.4 KiB
TypeScript

import React, { useEffect, useMemo } from 'react';
import { Share2Icon } from 'lucide-react';
import { useForm, Controller } from 'react-hook-form';
import { Permissions } from 'librechat-data-provider';
import type {
TPromptGroup,
TStartupConfig,
TUpdatePromptGroupPayload,
} from 'librechat-data-provider';
import {
Button,
Switch,
OGDialog,
OGDialogTitle,
OGDialogClose,
OGDialogContent,
OGDialogTrigger,
} from '~/components/ui';
import { useUpdatePromptGroup, useGetStartupConfig } from '~/data-provider';
import { useToastContext } from '~/Providers';
import { useLocalize } from '~/hooks';
type FormValues = {
[Permissions.SHARED_GLOBAL]: boolean;
};
const SharePrompt = ({ group, disabled }: { group?: TPromptGroup; disabled: boolean }) => {
const localize = useLocalize();
const { showToast } = useToastContext();
const updateGroup = useUpdatePromptGroup();
const { data: startupConfig = {} as TStartupConfig, isFetching } = useGetStartupConfig();
const { instanceProjectId } = startupConfig;
const groupIsGlobal = useMemo(
() => ((group?.projectIds ?? []) as string[]).includes(instanceProjectId as string),
[group, instanceProjectId],
);
const {
control,
setValue,
handleSubmit,
formState: { isSubmitting },
} = useForm<FormValues>({
mode: 'onChange',
defaultValues: {
[Permissions.SHARED_GLOBAL]: groupIsGlobal,
},
});
useEffect(() => {
setValue(Permissions.SHARED_GLOBAL, groupIsGlobal);
}, [groupIsGlobal, setValue]);
if (group == null || !instanceProjectId) {
return null;
}
const onSubmit = (data: FormValues) => {
const groupId = group._id ?? '';
if (groupId === '' || !instanceProjectId) {
return;
}
if (data[Permissions.SHARED_GLOBAL] === true && groupIsGlobal) {
showToast({
message: localize('com_ui_prompt_already_shared_to_all'),
status: 'info',
});
return;
}
const payload = {} as TUpdatePromptGroupPayload;
if (data[Permissions.SHARED_GLOBAL] === true) {
payload.projectIds = [startupConfig.instanceProjectId];
} else {
payload.removeProjectIds = [startupConfig.instanceProjectId];
}
updateGroup.mutate({
id: groupId,
payload,
});
};
return (
<OGDialog>
<OGDialogTrigger asChild>
<Button
variant="default"
size="sm"
aria-label="Share prompt"
className="h-10 w-10 border border-transparent bg-blue-500/90 p-0.5 transition-all hover:bg-blue-600 dark:bg-blue-600 dark:hover:bg-blue-800"
disabled={disabled}
>
<Share2Icon className="size-5 cursor-pointer text-white" />
</Button>
</OGDialogTrigger>
<OGDialogContent className="w-11/12 max-w-lg" role="dialog" aria-labelledby="dialog-title">
<OGDialogTitle id="dialog-title" className="truncate pr-2" title={group.name}>
{localize('com_ui_share_var', { 0: `"${group.name}"` })}
</OGDialogTitle>
<form className="p-2" onSubmit={handleSubmit(onSubmit)} aria-describedby="form-description">
<div id="form-description" className="sr-only">
{localize('com_ui_share_form_description')}
</div>
<div className="mb-4 flex items-center justify-between gap-2 py-4">
<div className="flex items-center" id="share-to-all-users">
{localize('com_ui_share_to_all_users')}
</div>
<Controller
name={Permissions.SHARED_GLOBAL}
control={control}
disabled={isFetching === true || updateGroup.isLoading || !instanceProjectId}
render={({ field }) => (
<Switch
{...field}
checked={field.value}
onCheckedChange={field.onChange}
value={field.value.toString()}
aria-labelledby="share-to-all-users"
/>
)}
/>
</div>
<div className="flex justify-end">
<OGDialogClose asChild>
<Button
type="submit"
disabled={isSubmitting || isFetching}
variant="submit"
aria-label={localize('com_ui_save')}
>
{localize('com_ui_save')}
</Button>
</OGDialogClose>
</div>
</form>
</OGDialogContent>
</OGDialog>
);
};
export default SharePrompt;