Commit cd1a8b50 authored by Phạm Quang Bảo's avatar Phạm Quang Bảo

fix: post and permission

parent 17ad281c
/**
* Generated by orval v7.17.0 🍺
* Do not edit manually.
* VietProDev CMS Backend API
* Generated API documentation
* OpenAPI spec version: 1.0.0
*/
import {
useInfiniteQuery,
useMutation,
useQuery
} from '@tanstack/react-query';
import type {
DataTag,
DefinedInitialDataOptions,
DefinedUseInfiniteQueryResult,
DefinedUseQueryResult,
InfiniteData,
MutationFunction,
QueryClient,
QueryFunction,
QueryKey,
UndefinedInitialDataOptions,
UseInfiniteQueryOptions,
UseInfiniteQueryResult,
UseMutationOptions,
UseMutationResult,
UseQueryOptions,
UseQueryResult
} from '@tanstack/react-query';
import type {
DeleteApiV10EventAddressId200,
EventAddressCreate,
GetApiV10EventAddressId200,
GetApiV10EventAddressParams,
PostApiV10EventAddress200,
PutApiV10EventAddressId200,
ResponseGetAllData
} from '../models';
import { useCustomClient } from '../mutator/custom-client';
import type { ErrorType , BodyType } from '../mutator/custom-client';
type SecondParameter<T extends (...args: never) => unknown> = Parameters<T>[1];
/**
* Retrieve a single event address record by its ID
* @summary Get event address by ID
*/
export const getApiV10EventAddressId = (
id: string,
options?: SecondParameter<typeof useCustomClient>,signal?: AbortSignal
) => {
return useCustomClient<GetApiV10EventAddressId200>(
{url: `/api/v1.0/eventAddress/${id}`, method: 'GET', signal
},
options);
}
export const getGetApiV10EventAddressIdInfiniteQueryKey = (id?: string,) => {
return [
'infinite', `/api/v1.0/eventAddress/${id}`
] as const;
}
export const getGetApiV10EventAddressIdQueryKey = (id?: string,) => {
return [
`/api/v1.0/eventAddress/${id}`
] as const;
}
export const getGetApiV10EventAddressIdInfiniteQueryOptions = <TData = InfiniteData<Awaited<ReturnType<typeof getApiV10EventAddressId>>>, TError = ErrorType<void>>(id: string, options?: { query?:Partial<UseInfiniteQueryOptions<Awaited<ReturnType<typeof getApiV10EventAddressId>>, TError, TData>>, request?: SecondParameter<typeof useCustomClient>}
) => {
const {query: queryOptions, request: requestOptions} = options ?? {};
const queryKey = queryOptions?.queryKey ?? getGetApiV10EventAddressIdInfiniteQueryKey(id);
const queryFn: QueryFunction<Awaited<ReturnType<typeof getApiV10EventAddressId>>> = ({ signal }) => getApiV10EventAddressId(id, requestOptions, signal);
return { queryKey, queryFn, enabled: !!(id), retry: 3, retryDelay: 1000, ...queryOptions} as UseInfiniteQueryOptions<Awaited<ReturnType<typeof getApiV10EventAddressId>>, TError, TData> & { queryKey: DataTag<QueryKey, TData, TError> }
}
export type GetApiV10EventAddressIdInfiniteQueryResult = NonNullable<Awaited<ReturnType<typeof getApiV10EventAddressId>>>
export type GetApiV10EventAddressIdInfiniteQueryError = ErrorType<void>
export function useGetApiV10EventAddressIdInfinite<TData = InfiniteData<Awaited<ReturnType<typeof getApiV10EventAddressId>>>, TError = ErrorType<void>>(
id: string, options: { query:Partial<UseInfiniteQueryOptions<Awaited<ReturnType<typeof getApiV10EventAddressId>>, TError, TData>> & Pick<
DefinedInitialDataOptions<
Awaited<ReturnType<typeof getApiV10EventAddressId>>,
TError,
Awaited<ReturnType<typeof getApiV10EventAddressId>>
> , 'initialData'
>, request?: SecondParameter<typeof useCustomClient>}
, queryClient?: QueryClient
): DefinedUseInfiniteQueryResult<TData, TError> & { queryKey: DataTag<QueryKey, TData, TError> }
export function useGetApiV10EventAddressIdInfinite<TData = InfiniteData<Awaited<ReturnType<typeof getApiV10EventAddressId>>>, TError = ErrorType<void>>(
id: string, options?: { query?:Partial<UseInfiniteQueryOptions<Awaited<ReturnType<typeof getApiV10EventAddressId>>, TError, TData>> & Pick<
UndefinedInitialDataOptions<
Awaited<ReturnType<typeof getApiV10EventAddressId>>,
TError,
Awaited<ReturnType<typeof getApiV10EventAddressId>>
> , 'initialData'
>, request?: SecondParameter<typeof useCustomClient>}
, queryClient?: QueryClient
): UseInfiniteQueryResult<TData, TError> & { queryKey: DataTag<QueryKey, TData, TError> }
export function useGetApiV10EventAddressIdInfinite<TData = InfiniteData<Awaited<ReturnType<typeof getApiV10EventAddressId>>>, TError = ErrorType<void>>(
id: string, options?: { query?:Partial<UseInfiniteQueryOptions<Awaited<ReturnType<typeof getApiV10EventAddressId>>, TError, TData>>, request?: SecondParameter<typeof useCustomClient>}
, queryClient?: QueryClient
): UseInfiniteQueryResult<TData, TError> & { queryKey: DataTag<QueryKey, TData, TError> }
/**
* @summary Get event address by ID
*/
export function useGetApiV10EventAddressIdInfinite<TData = InfiniteData<Awaited<ReturnType<typeof getApiV10EventAddressId>>>, TError = ErrorType<void>>(
id: string, options?: { query?:Partial<UseInfiniteQueryOptions<Awaited<ReturnType<typeof getApiV10EventAddressId>>, TError, TData>>, request?: SecondParameter<typeof useCustomClient>}
, queryClient?: QueryClient
): UseInfiniteQueryResult<TData, TError> & { queryKey: DataTag<QueryKey, TData, TError> } {
const queryOptions = getGetApiV10EventAddressIdInfiniteQueryOptions(id,options)
const query = useInfiniteQuery(queryOptions, queryClient) as UseInfiniteQueryResult<TData, TError> & { queryKey: DataTag<QueryKey, TData, TError> };
query.queryKey = queryOptions.queryKey ;
return query;
}
/**
* @summary Get event address by ID
*/
export const prefetchGetApiV10EventAddressIdInfiniteQuery = async <TData = Awaited<ReturnType<typeof getApiV10EventAddressId>>, TError = ErrorType<void>>(
queryClient: QueryClient, id: string, options?: { query?:Partial<UseInfiniteQueryOptions<Awaited<ReturnType<typeof getApiV10EventAddressId>>, TError, TData>>, request?: SecondParameter<typeof useCustomClient>}
): Promise<QueryClient> => {
const queryOptions = getGetApiV10EventAddressIdInfiniteQueryOptions(id,options)
await queryClient.prefetchInfiniteQuery(queryOptions);
return queryClient;
}
export const getGetApiV10EventAddressIdQueryOptions = <TData = Awaited<ReturnType<typeof getApiV10EventAddressId>>, TError = ErrorType<void>>(id: string, options?: { query?:Partial<UseQueryOptions<Awaited<ReturnType<typeof getApiV10EventAddressId>>, TError, TData>>, request?: SecondParameter<typeof useCustomClient>}
) => {
const {query: queryOptions, request: requestOptions} = options ?? {};
const queryKey = queryOptions?.queryKey ?? getGetApiV10EventAddressIdQueryKey(id);
const queryFn: QueryFunction<Awaited<ReturnType<typeof getApiV10EventAddressId>>> = ({ signal }) => getApiV10EventAddressId(id, requestOptions, signal);
return { queryKey, queryFn, enabled: !!(id), retry: 3, retryDelay: 1000, ...queryOptions} as UseQueryOptions<Awaited<ReturnType<typeof getApiV10EventAddressId>>, TError, TData> & { queryKey: DataTag<QueryKey, TData, TError> }
}
export type GetApiV10EventAddressIdQueryResult = NonNullable<Awaited<ReturnType<typeof getApiV10EventAddressId>>>
export type GetApiV10EventAddressIdQueryError = ErrorType<void>
export function useGetApiV10EventAddressId<TData = Awaited<ReturnType<typeof getApiV10EventAddressId>>, TError = ErrorType<void>>(
id: string, options: { query:Partial<UseQueryOptions<Awaited<ReturnType<typeof getApiV10EventAddressId>>, TError, TData>> & Pick<
DefinedInitialDataOptions<
Awaited<ReturnType<typeof getApiV10EventAddressId>>,
TError,
Awaited<ReturnType<typeof getApiV10EventAddressId>>
> , 'initialData'
>, request?: SecondParameter<typeof useCustomClient>}
, queryClient?: QueryClient
): DefinedUseQueryResult<TData, TError> & { queryKey: DataTag<QueryKey, TData, TError> }
export function useGetApiV10EventAddressId<TData = Awaited<ReturnType<typeof getApiV10EventAddressId>>, TError = ErrorType<void>>(
id: string, options?: { query?:Partial<UseQueryOptions<Awaited<ReturnType<typeof getApiV10EventAddressId>>, TError, TData>> & Pick<
UndefinedInitialDataOptions<
Awaited<ReturnType<typeof getApiV10EventAddressId>>,
TError,
Awaited<ReturnType<typeof getApiV10EventAddressId>>
> , 'initialData'
>, request?: SecondParameter<typeof useCustomClient>}
, queryClient?: QueryClient
): UseQueryResult<TData, TError> & { queryKey: DataTag<QueryKey, TData, TError> }
export function useGetApiV10EventAddressId<TData = Awaited<ReturnType<typeof getApiV10EventAddressId>>, TError = ErrorType<void>>(
id: string, options?: { query?:Partial<UseQueryOptions<Awaited<ReturnType<typeof getApiV10EventAddressId>>, TError, TData>>, request?: SecondParameter<typeof useCustomClient>}
, queryClient?: QueryClient
): UseQueryResult<TData, TError> & { queryKey: DataTag<QueryKey, TData, TError> }
/**
* @summary Get event address by ID
*/
export function useGetApiV10EventAddressId<TData = Awaited<ReturnType<typeof getApiV10EventAddressId>>, TError = ErrorType<void>>(
id: string, options?: { query?:Partial<UseQueryOptions<Awaited<ReturnType<typeof getApiV10EventAddressId>>, TError, TData>>, request?: SecondParameter<typeof useCustomClient>}
, queryClient?: QueryClient
): UseQueryResult<TData, TError> & { queryKey: DataTag<QueryKey, TData, TError> } {
const queryOptions = getGetApiV10EventAddressIdQueryOptions(id,options)
const query = useQuery(queryOptions, queryClient) as UseQueryResult<TData, TError> & { queryKey: DataTag<QueryKey, TData, TError> };
query.queryKey = queryOptions.queryKey ;
return query;
}
/**
* @summary Get event address by ID
*/
export const prefetchGetApiV10EventAddressIdQuery = async <TData = Awaited<ReturnType<typeof getApiV10EventAddressId>>, TError = ErrorType<void>>(
queryClient: QueryClient, id: string, options?: { query?:Partial<UseQueryOptions<Awaited<ReturnType<typeof getApiV10EventAddressId>>, TError, TData>>, request?: SecondParameter<typeof useCustomClient>}
): Promise<QueryClient> => {
const queryOptions = getGetApiV10EventAddressIdQueryOptions(id,options)
await queryClient.prefetchQuery(queryOptions);
return queryClient;
}
/**
* Update a single event address record by its ID
* @summary Update event address by ID
*/
export const putApiV10EventAddressId = (
id: string,
eventAddressCreate: BodyType<EventAddressCreate>,
options?: SecondParameter<typeof useCustomClient>,) => {
return useCustomClient<PutApiV10EventAddressId200>(
{url: `/api/v1.0/eventAddress/${id}`, method: 'PUT',
headers: {'Content-Type': 'application/json', },
data: eventAddressCreate
},
options);
}
export const getPutApiV10EventAddressIdMutationOptions = <TError = ErrorType<void>,
TContext = unknown>(options?: { mutation?:UseMutationOptions<Awaited<ReturnType<typeof putApiV10EventAddressId>>, TError,{id: string;data: BodyType<EventAddressCreate>}, TContext>, request?: SecondParameter<typeof useCustomClient>}
): UseMutationOptions<Awaited<ReturnType<typeof putApiV10EventAddressId>>, TError,{id: string;data: BodyType<EventAddressCreate>}, TContext> => {
const mutationKey = ['putApiV10EventAddressId'];
const {mutation: mutationOptions, request: requestOptions} = options ?
options.mutation && 'mutationKey' in options.mutation && options.mutation.mutationKey ?
options
: {...options, mutation: {...options.mutation, mutationKey}}
: {mutation: { mutationKey, }, request: undefined};
const mutationFn: MutationFunction<Awaited<ReturnType<typeof putApiV10EventAddressId>>, {id: string;data: BodyType<EventAddressCreate>}> = (props) => {
const {id,data} = props ?? {};
return putApiV10EventAddressId(id,data,requestOptions)
}
return { mutationFn, ...mutationOptions }}
export type PutApiV10EventAddressIdMutationResult = NonNullable<Awaited<ReturnType<typeof putApiV10EventAddressId>>>
export type PutApiV10EventAddressIdMutationBody = BodyType<EventAddressCreate>
export type PutApiV10EventAddressIdMutationError = ErrorType<void>
/**
* @summary Update event address by ID
*/
export const usePutApiV10EventAddressId = <TError = ErrorType<void>,
TContext = unknown>(options?: { mutation?:UseMutationOptions<Awaited<ReturnType<typeof putApiV10EventAddressId>>, TError,{id: string;data: BodyType<EventAddressCreate>}, TContext>, request?: SecondParameter<typeof useCustomClient>}
, queryClient?: QueryClient): UseMutationResult<
Awaited<ReturnType<typeof putApiV10EventAddressId>>,
TError,
{id: string;data: BodyType<EventAddressCreate>},
TContext
> => {
const mutationOptions = getPutApiV10EventAddressIdMutationOptions(options);
return useMutation(mutationOptions, queryClient);
}
/**
* Delete a single event address record by its ID
* @summary Delete event address by ID
*/
export const deleteApiV10EventAddressId = (
id: string,
options?: SecondParameter<typeof useCustomClient>,) => {
return useCustomClient<DeleteApiV10EventAddressId200>(
{url: `/api/v1.0/eventAddress/${id}`, method: 'DELETE'
},
options);
}
export const getDeleteApiV10EventAddressIdMutationOptions = <TError = ErrorType<void>,
TContext = unknown>(options?: { mutation?:UseMutationOptions<Awaited<ReturnType<typeof deleteApiV10EventAddressId>>, TError,{id: string}, TContext>, request?: SecondParameter<typeof useCustomClient>}
): UseMutationOptions<Awaited<ReturnType<typeof deleteApiV10EventAddressId>>, TError,{id: string}, TContext> => {
const mutationKey = ['deleteApiV10EventAddressId'];
const {mutation: mutationOptions, request: requestOptions} = options ?
options.mutation && 'mutationKey' in options.mutation && options.mutation.mutationKey ?
options
: {...options, mutation: {...options.mutation, mutationKey}}
: {mutation: { mutationKey, }, request: undefined};
const mutationFn: MutationFunction<Awaited<ReturnType<typeof deleteApiV10EventAddressId>>, {id: string}> = (props) => {
const {id} = props ?? {};
return deleteApiV10EventAddressId(id,requestOptions)
}
return { mutationFn, ...mutationOptions }}
export type DeleteApiV10EventAddressIdMutationResult = NonNullable<Awaited<ReturnType<typeof deleteApiV10EventAddressId>>>
export type DeleteApiV10EventAddressIdMutationError = ErrorType<void>
/**
* @summary Delete event address by ID
*/
export const useDeleteApiV10EventAddressId = <TError = ErrorType<void>,
TContext = unknown>(options?: { mutation?:UseMutationOptions<Awaited<ReturnType<typeof deleteApiV10EventAddressId>>, TError,{id: string}, TContext>, request?: SecondParameter<typeof useCustomClient>}
, queryClient?: QueryClient): UseMutationResult<
Awaited<ReturnType<typeof deleteApiV10EventAddressId>>,
TError,
{id: string},
TContext
> => {
const mutationOptions = getDeleteApiV10EventAddressIdMutationOptions(options);
return useMutation(mutationOptions, queryClient);
}
/**
* Retrieve a list of event addresses with pagination, filtering and sorting
* @summary Get all event addresses
*/
export const getApiV10EventAddress = (
params?: GetApiV10EventAddressParams,
options?: SecondParameter<typeof useCustomClient>,signal?: AbortSignal
) => {
return useCustomClient<ResponseGetAllData>(
{url: `/api/v1.0/eventAddress`, method: 'GET',
params, signal
},
options);
}
export const getGetApiV10EventAddressInfiniteQueryKey = (params?: GetApiV10EventAddressParams,) => {
return [
'infinite', `/api/v1.0/eventAddress`, ...(params ? [params]: [])
] as const;
}
export const getGetApiV10EventAddressQueryKey = (params?: GetApiV10EventAddressParams,) => {
return [
`/api/v1.0/eventAddress`, ...(params ? [params]: [])
] as const;
}
export const getGetApiV10EventAddressInfiniteQueryOptions = <TData = InfiniteData<Awaited<ReturnType<typeof getApiV10EventAddress>>>, TError = ErrorType<unknown>>(params?: GetApiV10EventAddressParams, options?: { query?:Partial<UseInfiniteQueryOptions<Awaited<ReturnType<typeof getApiV10EventAddress>>, TError, TData>>, request?: SecondParameter<typeof useCustomClient>}
) => {
const {query: queryOptions, request: requestOptions} = options ?? {};
const queryKey = queryOptions?.queryKey ?? getGetApiV10EventAddressInfiniteQueryKey(params);
const queryFn: QueryFunction<Awaited<ReturnType<typeof getApiV10EventAddress>>> = ({ signal }) => getApiV10EventAddress(params, requestOptions, signal);
return { queryKey, queryFn, retry: 3, retryDelay: 1000, ...queryOptions} as UseInfiniteQueryOptions<Awaited<ReturnType<typeof getApiV10EventAddress>>, TError, TData> & { queryKey: DataTag<QueryKey, TData, TError> }
}
export type GetApiV10EventAddressInfiniteQueryResult = NonNullable<Awaited<ReturnType<typeof getApiV10EventAddress>>>
export type GetApiV10EventAddressInfiniteQueryError = ErrorType<unknown>
export function useGetApiV10EventAddressInfinite<TData = InfiniteData<Awaited<ReturnType<typeof getApiV10EventAddress>>>, TError = ErrorType<unknown>>(
params: undefined | GetApiV10EventAddressParams, options: { query:Partial<UseInfiniteQueryOptions<Awaited<ReturnType<typeof getApiV10EventAddress>>, TError, TData>> & Pick<
DefinedInitialDataOptions<
Awaited<ReturnType<typeof getApiV10EventAddress>>,
TError,
Awaited<ReturnType<typeof getApiV10EventAddress>>
> , 'initialData'
>, request?: SecondParameter<typeof useCustomClient>}
, queryClient?: QueryClient
): DefinedUseInfiniteQueryResult<TData, TError> & { queryKey: DataTag<QueryKey, TData, TError> }
export function useGetApiV10EventAddressInfinite<TData = InfiniteData<Awaited<ReturnType<typeof getApiV10EventAddress>>>, TError = ErrorType<unknown>>(
params?: GetApiV10EventAddressParams, options?: { query?:Partial<UseInfiniteQueryOptions<Awaited<ReturnType<typeof getApiV10EventAddress>>, TError, TData>> & Pick<
UndefinedInitialDataOptions<
Awaited<ReturnType<typeof getApiV10EventAddress>>,
TError,
Awaited<ReturnType<typeof getApiV10EventAddress>>
> , 'initialData'
>, request?: SecondParameter<typeof useCustomClient>}
, queryClient?: QueryClient
): UseInfiniteQueryResult<TData, TError> & { queryKey: DataTag<QueryKey, TData, TError> }
export function useGetApiV10EventAddressInfinite<TData = InfiniteData<Awaited<ReturnType<typeof getApiV10EventAddress>>>, TError = ErrorType<unknown>>(
params?: GetApiV10EventAddressParams, options?: { query?:Partial<UseInfiniteQueryOptions<Awaited<ReturnType<typeof getApiV10EventAddress>>, TError, TData>>, request?: SecondParameter<typeof useCustomClient>}
, queryClient?: QueryClient
): UseInfiniteQueryResult<TData, TError> & { queryKey: DataTag<QueryKey, TData, TError> }
/**
* @summary Get all event addresses
*/
export function useGetApiV10EventAddressInfinite<TData = InfiniteData<Awaited<ReturnType<typeof getApiV10EventAddress>>>, TError = ErrorType<unknown>>(
params?: GetApiV10EventAddressParams, options?: { query?:Partial<UseInfiniteQueryOptions<Awaited<ReturnType<typeof getApiV10EventAddress>>, TError, TData>>, request?: SecondParameter<typeof useCustomClient>}
, queryClient?: QueryClient
): UseInfiniteQueryResult<TData, TError> & { queryKey: DataTag<QueryKey, TData, TError> } {
const queryOptions = getGetApiV10EventAddressInfiniteQueryOptions(params,options)
const query = useInfiniteQuery(queryOptions, queryClient) as UseInfiniteQueryResult<TData, TError> & { queryKey: DataTag<QueryKey, TData, TError> };
query.queryKey = queryOptions.queryKey ;
return query;
}
/**
* @summary Get all event addresses
*/
export const prefetchGetApiV10EventAddressInfiniteQuery = async <TData = Awaited<ReturnType<typeof getApiV10EventAddress>>, TError = ErrorType<unknown>>(
queryClient: QueryClient, params?: GetApiV10EventAddressParams, options?: { query?:Partial<UseInfiniteQueryOptions<Awaited<ReturnType<typeof getApiV10EventAddress>>, TError, TData>>, request?: SecondParameter<typeof useCustomClient>}
): Promise<QueryClient> => {
const queryOptions = getGetApiV10EventAddressInfiniteQueryOptions(params,options)
await queryClient.prefetchInfiniteQuery(queryOptions);
return queryClient;
}
export const getGetApiV10EventAddressQueryOptions = <TData = Awaited<ReturnType<typeof getApiV10EventAddress>>, TError = ErrorType<unknown>>(params?: GetApiV10EventAddressParams, options?: { query?:Partial<UseQueryOptions<Awaited<ReturnType<typeof getApiV10EventAddress>>, TError, TData>>, request?: SecondParameter<typeof useCustomClient>}
) => {
const {query: queryOptions, request: requestOptions} = options ?? {};
const queryKey = queryOptions?.queryKey ?? getGetApiV10EventAddressQueryKey(params);
const queryFn: QueryFunction<Awaited<ReturnType<typeof getApiV10EventAddress>>> = ({ signal }) => getApiV10EventAddress(params, requestOptions, signal);
return { queryKey, queryFn, retry: 3, retryDelay: 1000, ...queryOptions} as UseQueryOptions<Awaited<ReturnType<typeof getApiV10EventAddress>>, TError, TData> & { queryKey: DataTag<QueryKey, TData, TError> }
}
export type GetApiV10EventAddressQueryResult = NonNullable<Awaited<ReturnType<typeof getApiV10EventAddress>>>
export type GetApiV10EventAddressQueryError = ErrorType<unknown>
export function useGetApiV10EventAddress<TData = Awaited<ReturnType<typeof getApiV10EventAddress>>, TError = ErrorType<unknown>>(
params: undefined | GetApiV10EventAddressParams, options: { query:Partial<UseQueryOptions<Awaited<ReturnType<typeof getApiV10EventAddress>>, TError, TData>> & Pick<
DefinedInitialDataOptions<
Awaited<ReturnType<typeof getApiV10EventAddress>>,
TError,
Awaited<ReturnType<typeof getApiV10EventAddress>>
> , 'initialData'
>, request?: SecondParameter<typeof useCustomClient>}
, queryClient?: QueryClient
): DefinedUseQueryResult<TData, TError> & { queryKey: DataTag<QueryKey, TData, TError> }
export function useGetApiV10EventAddress<TData = Awaited<ReturnType<typeof getApiV10EventAddress>>, TError = ErrorType<unknown>>(
params?: GetApiV10EventAddressParams, options?: { query?:Partial<UseQueryOptions<Awaited<ReturnType<typeof getApiV10EventAddress>>, TError, TData>> & Pick<
UndefinedInitialDataOptions<
Awaited<ReturnType<typeof getApiV10EventAddress>>,
TError,
Awaited<ReturnType<typeof getApiV10EventAddress>>
> , 'initialData'
>, request?: SecondParameter<typeof useCustomClient>}
, queryClient?: QueryClient
): UseQueryResult<TData, TError> & { queryKey: DataTag<QueryKey, TData, TError> }
export function useGetApiV10EventAddress<TData = Awaited<ReturnType<typeof getApiV10EventAddress>>, TError = ErrorType<unknown>>(
params?: GetApiV10EventAddressParams, options?: { query?:Partial<UseQueryOptions<Awaited<ReturnType<typeof getApiV10EventAddress>>, TError, TData>>, request?: SecondParameter<typeof useCustomClient>}
, queryClient?: QueryClient
): UseQueryResult<TData, TError> & { queryKey: DataTag<QueryKey, TData, TError> }
/**
* @summary Get all event addresses
*/
export function useGetApiV10EventAddress<TData = Awaited<ReturnType<typeof getApiV10EventAddress>>, TError = ErrorType<unknown>>(
params?: GetApiV10EventAddressParams, options?: { query?:Partial<UseQueryOptions<Awaited<ReturnType<typeof getApiV10EventAddress>>, TError, TData>>, request?: SecondParameter<typeof useCustomClient>}
, queryClient?: QueryClient
): UseQueryResult<TData, TError> & { queryKey: DataTag<QueryKey, TData, TError> } {
const queryOptions = getGetApiV10EventAddressQueryOptions(params,options)
const query = useQuery(queryOptions, queryClient) as UseQueryResult<TData, TError> & { queryKey: DataTag<QueryKey, TData, TError> };
query.queryKey = queryOptions.queryKey ;
return query;
}
/**
* @summary Get all event addresses
*/
export const prefetchGetApiV10EventAddressQuery = async <TData = Awaited<ReturnType<typeof getApiV10EventAddress>>, TError = ErrorType<unknown>>(
queryClient: QueryClient, params?: GetApiV10EventAddressParams, options?: { query?:Partial<UseQueryOptions<Awaited<ReturnType<typeof getApiV10EventAddress>>, TError, TData>>, request?: SecondParameter<typeof useCustomClient>}
): Promise<QueryClient> => {
const queryOptions = getGetApiV10EventAddressQueryOptions(params,options)
await queryClient.prefetchQuery(queryOptions);
return queryClient;
}
/**
* Create a new event address record
* @summary Create an event address
*/
export const postApiV10EventAddress = (
eventAddressCreate: BodyType<EventAddressCreate>,
options?: SecondParameter<typeof useCustomClient>,signal?: AbortSignal
) => {
return useCustomClient<PostApiV10EventAddress200>(
{url: `/api/v1.0/eventAddress`, method: 'POST',
headers: {'Content-Type': 'application/json', },
data: eventAddressCreate, signal
},
options);
}
export const getPostApiV10EventAddressMutationOptions = <TError = ErrorType<unknown>,
TContext = unknown>(options?: { mutation?:UseMutationOptions<Awaited<ReturnType<typeof postApiV10EventAddress>>, TError,{data: BodyType<EventAddressCreate>}, TContext>, request?: SecondParameter<typeof useCustomClient>}
): UseMutationOptions<Awaited<ReturnType<typeof postApiV10EventAddress>>, TError,{data: BodyType<EventAddressCreate>}, TContext> => {
const mutationKey = ['postApiV10EventAddress'];
const {mutation: mutationOptions, request: requestOptions} = options ?
options.mutation && 'mutationKey' in options.mutation && options.mutation.mutationKey ?
options
: {...options, mutation: {...options.mutation, mutationKey}}
: {mutation: { mutationKey, }, request: undefined};
const mutationFn: MutationFunction<Awaited<ReturnType<typeof postApiV10EventAddress>>, {data: BodyType<EventAddressCreate>}> = (props) => {
const {data} = props ?? {};
return postApiV10EventAddress(data,requestOptions)
}
return { mutationFn, ...mutationOptions }}
export type PostApiV10EventAddressMutationResult = NonNullable<Awaited<ReturnType<typeof postApiV10EventAddress>>>
export type PostApiV10EventAddressMutationBody = BodyType<EventAddressCreate>
export type PostApiV10EventAddressMutationError = ErrorType<unknown>
/**
* @summary Create an event address
*/
export const usePostApiV10EventAddress = <TError = ErrorType<unknown>,
TContext = unknown>(options?: { mutation?:UseMutationOptions<Awaited<ReturnType<typeof postApiV10EventAddress>>, TError,{data: BodyType<EventAddressCreate>}, TContext>, request?: SecondParameter<typeof useCustomClient>}
, queryClient?: QueryClient): UseMutationResult<
Awaited<ReturnType<typeof postApiV10EventAddress>>,
TError,
{data: BodyType<EventAddressCreate>},
TContext
> => {
const mutationOptions = getPostApiV10EventAddressMutationOptions(options);
return useMutation(mutationOptions, queryClient);
}
\ No newline at end of file
/**
* Generated by orval v7.17.0 🍺
* Do not edit manually.
* VietProDev CMS Backend API
* Generated API documentation
* OpenAPI spec version: 1.0.0
*/
import type { ApiResponse } from './apiResponse';
import type { DeleteApiV10EventAddressId200AllOf } from './deleteApiV10EventAddressId200AllOf';
export type DeleteApiV10EventAddressId200 = ApiResponse & DeleteApiV10EventAddressId200AllOf;
/**
* Generated by orval v7.17.0 🍺
* Do not edit manually.
* VietProDev CMS Backend API
* Generated API documentation
* OpenAPI spec version: 1.0.0
*/
export type DeleteApiV10EventAddressId200AllOf = {
responseData?: boolean;
};
/**
* Generated by orval v7.17.0 🍺
* Do not edit manually.
* VietProDev CMS Backend API
* Generated API documentation
* OpenAPI spec version: 1.0.0
*/
export interface EventAddres {
id?: string;
information?: string;
}
/**
* Generated by orval v7.17.0 🍺
* Do not edit manually.
* VietProDev CMS Backend API
* Generated API documentation
* OpenAPI spec version: 1.0.0
*/
export interface EventAddresMutate {
information?: string;
}
/**
* Generated by orval v7.17.0 🍺
* Do not edit manually.
* VietProDev CMS Backend API
* Generated API documentation
* OpenAPI spec version: 1.0.0
*/
export interface EventAddress {
id: string;
information: string;
}
/**
* Generated by orval v7.17.0 🍺
* Do not edit manually.
* VietProDev CMS Backend API
* Generated API documentation
* OpenAPI spec version: 1.0.0
*/
export interface EventAddressCreate {
information: string;
}
/**
* Generated by orval v7.17.0 🍺
* Do not edit manually.
* VietProDev CMS Backend API
* Generated API documentation
* OpenAPI spec version: 1.0.0
*/
import type { EventAddressCreate } from './eventAddressCreate';
export type EventAddressMutate = EventAddressCreate;
/**
* Generated by orval v7.17.0 🍺
* Do not edit manually.
* VietProDev CMS Backend API
* Generated API documentation
* OpenAPI spec version: 1.0.0
*/
export interface EventAddressUpdate {
information?: string;
}
/**
* Generated by orval v7.17.0 🍺
* Do not edit manually.
* VietProDev CMS Backend API
* Generated API documentation
* OpenAPI spec version: 1.0.0
*/
import type { ApiResponse } from './apiResponse';
import type { GetApiV10EventAddressId200AllOf } from './getApiV10EventAddressId200AllOf';
export type GetApiV10EventAddressId200 = ApiResponse & GetApiV10EventAddressId200AllOf;
/**
* Generated by orval v7.17.0 🍺
* Do not edit manually.
* VietProDev CMS Backend API
* Generated API documentation
* OpenAPI spec version: 1.0.0
*/
import type { EventAddress } from './eventAddress';
export type GetApiV10EventAddressId200AllOf = {
responseData?: EventAddress;
};
/**
* Generated by orval v7.17.0 🍺
* Do not edit manually.
* VietProDev CMS Backend API
* Generated API documentation
* OpenAPI spec version: 1.0.0
*/
import type { FiltersParameter } from './filtersParameter';
import type { SortFieldParameter } from './sortFieldParameter';
import type { SortOrderParameter } from './sortOrderParameter';
import type { PageParameter } from './pageParameter';
import type { PageSizeParameter } from './pageSizeParameter';
export type GetApiV10EventAddressParams = {
/**
* filter, visit https://www.npmjs.com/package/sequelize-api-paginate for syntax
*/
filters?: FiltersParameter;
/**
* sortField, visit https://www.npmjs.com/package/sequelize-api-paginate for syntax
*/
sortField?: SortFieldParameter;
/**
* sort order, visit https://www.npmjs.com/package/sequelize-api-paginate for syntax
*/
sortOrder?: SortOrderParameter;
/**
* page, visit https://www.npmjs.com/package/sequelize-api-paginate for syntax
* @minimum 1
*/
page?: PageParameter;
/**
* pageSize, visit https://www.npmjs.com/package/sequelize-api-paginate for syntax
* @minimum 1
*/
pageSize?: PageSizeParameter;
};
......@@ -60,6 +60,8 @@ export * from './deleteApiV10CategoryId200';
export * from './deleteApiV10CategoryId200AllOf';
export * from './deleteApiV10ContactId200';
export * from './deleteApiV10ContactId200AllOf';
export * from './deleteApiV10EventAddressId200';
export * from './deleteApiV10EventAddressId200AllOf';
export * from './deleteApiV10FileId200';
export * from './deleteApiV10FileId200AllOf';
export * from './deleteApiV10LogoId200';
......@@ -88,6 +90,12 @@ export * from './deleteApiV10UserIdRoleBody';
export * from './deleteApiV10UserRoleId200';
export * from './deleteApiV10UserRoleId200AllOf';
export * from './deleteApiV10UserRoleId200AllOfResponseData';
export * from './eventAddres';
export * from './eventAddresMutate';
export * from './eventAddress';
export * from './eventAddressCreate';
export * from './eventAddressMutate';
export * from './eventAddressUpdate';
export * from './file';
export * from './fileCompressInfo';
export * from './fileImportInfo';
......@@ -125,6 +133,9 @@ export * from './getApiV10CategoryTree200AllOf';
export * from './getApiV10ContactId200';
export * from './getApiV10ContactId200AllOf';
export * from './getApiV10ContactParams';
export * from './getApiV10EventAddressId200';
export * from './getApiV10EventAddressId200AllOf';
export * from './getApiV10EventAddressParams';
export * from './getApiV10FileId200';
export * from './getApiV10FileId200AllOf';
export * from './getApiV10FileParams';
......@@ -263,6 +274,8 @@ export * from './postApiV10CategoryTagCategoryIdBulk200AllOf';
export * from './postApiV10CategoryTagCategoryIdBulkBody';
export * from './postApiV10Contact200';
export * from './postApiV10Contact200AllOf';
export * from './postApiV10EventAddress200';
export * from './postApiV10EventAddress200AllOf';
export * from './postApiV10FileUpload200';
export * from './postApiV10FileUpload200AllOf';
export * from './postApiV10FileUploadBody';
......@@ -341,6 +354,8 @@ export * from './putApiV10CategoryId200';
export * from './putApiV10CategoryId200AllOf';
export * from './putApiV10ContactId200';
export * from './putApiV10ContactId200AllOf';
export * from './putApiV10EventAddressId200';
export * from './putApiV10EventAddressId200AllOf';
export * from './putApiV10LogoId200';
export * from './putApiV10LogoId200AllOf';
export * from './putApiV10PageConfigIdBody';
......
......@@ -16,7 +16,6 @@ export interface Post {
release_at?: string;
is_active?: boolean;
release_mode?: string;
page_config_id?: string;
created_at?: string;
created_by?: string;
updated_at?: string;
......
/**
* Generated by orval v7.17.0 🍺
* Do not edit manually.
* VietProDev CMS Backend API
* Generated API documentation
* OpenAPI spec version: 1.0.0
*/
import type { ApiResponse } from './apiResponse';
import type { PostApiV10EventAddress200AllOf } from './postApiV10EventAddress200AllOf';
export type PostApiV10EventAddress200 = ApiResponse & PostApiV10EventAddress200AllOf;
/**
* Generated by orval v7.17.0 🍺
* Do not edit manually.
* VietProDev CMS Backend API
* Generated API documentation
* OpenAPI spec version: 1.0.0
*/
import type { EventAddress } from './eventAddress';
export type PostApiV10EventAddress200AllOf = {
responseData?: EventAddress;
};
......@@ -15,7 +15,6 @@ export interface PostMutate {
release_at?: string;
is_active?: boolean;
release_mode?: string;
page_config_id?: string;
is_featured?: boolean;
status?: string;
type?: string;
......
/**
* Generated by orval v7.17.0 🍺
* Do not edit manually.
* VietProDev CMS Backend API
* Generated API documentation
* OpenAPI spec version: 1.0.0
*/
import type { ApiResponse } from './apiResponse';
import type { PutApiV10EventAddressId200AllOf } from './putApiV10EventAddressId200AllOf';
export type PutApiV10EventAddressId200 = ApiResponse & PutApiV10EventAddressId200AllOf;
/**
* Generated by orval v7.17.0 🍺
* Do not edit manually.
* VietProDev CMS Backend API
* Generated API documentation
* OpenAPI spec version: 1.0.0
*/
import type { EventAddress } from './eventAddress';
export type PutApiV10EventAddressId200AllOf = {
responseData?: EventAddress;
};
......@@ -6,6 +6,7 @@ import SidebarAdvertisements from "@/components/shared/sidebar-advertisements";
import { findDisplayCategoryForPost } from "../data";
import { renderPostSummary } from "./components/post-summary-content";
import PostContent from "@/components/shared/post-content";
import { PostTextSection } from "@/components/shared/post-content/components/text-section";
import EventInfoCard from "./components/event-info-card";
import type { DynamicCategoryRouteItem } from "../types";
import type { DynamicPostItem } from "@/api/vcci-news/types/post";
......@@ -46,8 +47,8 @@ export default function NewsDetailPage({
{/* summary */}
{post.summary ? (
<div className="mt-5 max-w-4xl text-base font-semibold leading-7 text-[#374151] md:text-lg md:leading-8">
{renderPostSummary(post.summary)}
<div className="mt-5 max-w-4xl">
<PostTextSection>{renderPostSummary(post.summary)}</PostTextSection>
</div>
) : null}
......
......@@ -9,7 +9,7 @@ import {
useState,
} from "react";
import dayjs from "dayjs";
import { ArrowLeft, Save, Upload, X, Calendar as CalendarIcon } from "lucide-react";
import { ArrowLeft, Save, Upload, X, Calendar as CalendarIcon, Plus, Check, ChevronsUpDown } from "lucide-react";
import Link from "next/link";
import { useParams, useRouter, useSearchParams } from "next/navigation";
import { toast } from "sonner";
......@@ -31,6 +31,8 @@ import {
SelectValue,
} from "@/components/ui/select";
import { Switch } from "@/components/ui/switch";
import { Command, CommandItem, CommandList } from "@/components/ui/command";
import { Popover, PopoverAnchor, PopoverContent } from "@/components/ui/popover";
import {
type TagItem,
} from "@/api/vcci-news/types/tag";
......@@ -50,6 +52,7 @@ import {
getApiV10Tag,
postApiV10TagIds,
} from "@/api/vcci-news/endpoints/tag";
import { useGetApiV10EventAddress } from "@/api/vcci-news/endpoints/event-address";
import {
ADMIN_NEWS_TYPE_OPTIONS,
cloneAdminNewsFormValues,
......@@ -74,6 +77,7 @@ import {
} from "./constants";
import { DateTimePicker } from "@/components/shared/date-time-picker";
import { EventDatesDatePicker } from "./event-dates-date-picker";
import { EventAddressManagerDialog } from "./event-address-manager-dialog";
import { DraftRestoreDialog } from "./draft-restore-dialog";
import { FormSection } from "./form-section";
import { HeaderCategoryMultiPicker } from "./header-category-multi-picker";
......@@ -106,6 +110,37 @@ export function AdminNewsFormContent() {
const [isLoadingInitialData, setIsLoadingInitialData] = useState(true);
const [isMissingPost, setIsMissingPost] = useState(false);
const [useEventDates, setUseEventDates] = useState(false);
const [isAddressManagerOpen, setIsAddressManagerOpen] = useState(false);
const [isAddressSuggestOpen, setIsAddressSuggestOpen] = useState(false);
const eventAddressesQuery = useGetApiV10EventAddress({
page: 1,
pageSize: 100,
sortField: "information",
sortOrder: "asc",
});
const addressOptions = useMemo(() => {
const rows = eventAddressesQuery.data?.responseData?.rows ?? [];
const values = Array.from(
new Set(
rows
.map((row) => String((row as Record<string, unknown>)?.information ?? "").trim())
.filter(Boolean),
),
);
const currentLocation = form?.location?.trim();
if (currentLocation && !values.includes(currentLocation)) {
values.unshift(currentLocation);
}
return values;
}, [eventAddressesQuery.data, form?.location]);
const matchingAddressOptions = useMemo(() => {
const keyword = form?.location?.trim().toLowerCase() ?? "";
if (!keyword) return addressOptions;
return addressOptions.filter((option) => option.toLowerCase().includes(keyword));
}, [addressOptions, form?.location]);
// Draft auto-save (create mode only)
const draftHasHydrated = useNewsDraftStore((s) => s._hasHydrated);
......@@ -1003,12 +1038,76 @@ export function AdminNewsFormContent() {
</div>
<div>
<Label className="mb-1.5 block text-gray-700">Địa điểm</Label>
<Input
value={form.location}
onChange={(event) => handleField("location", event.target.value)}
placeholder="Nhập địa điểm"
className={fieldClassName}
<div className="mb-1.5 flex items-center justify-between gap-2">
<Label className="block text-gray-700">Địa điểm</Label>
<PermissionGate required="settings:write">
<button
type="button"
onClick={() => setIsAddressManagerOpen(true)}
className="flex items-center gap-1 text-xs font-medium text-[#063e8e] hover:underline"
>
<Plus className="h-3.5 w-3.5" />
Tạo địa điểm mới
</button>
</PermissionGate>
</div>
<Popover
open={isAddressSuggestOpen}
onOpenChange={setIsAddressSuggestOpen}
>
<PopoverAnchor asChild>
<div className="relative">
<Input
value={form.location}
onChange={(event) => {
handleField("location", event.target.value);
setIsAddressSuggestOpen(true);
}}
onFocus={() => setIsAddressSuggestOpen(true)}
placeholder="Nhập hoặc chọn địa điểm"
className={fieldClassName}
autoComplete="off"
/>
<ChevronsUpDown className="pointer-events-none absolute right-3 top-1/2 h-4 w-4 -translate-y-1/2 text-gray-400" />
</div>
</PopoverAnchor>
<PopoverContent
align="start"
onOpenAutoFocus={(event) => event.preventDefault()}
className="w-[var(--radix-popover-trigger-width)] min-w-[var(--radix-popover-trigger-width)] rounded-xl border-[#063e8e]/15 bg-white p-0 text-gray-700"
>
<Command className="bg-white text-gray-700">
<CommandList className="max-h-60">
{matchingAddressOptions.length === 0 ? (
<div className="px-3 py-2 text-sm text-gray-500">
Không có gợi ý — địa điểm sẽ dùng như đã nhập
</div>
) : (
matchingAddressOptions.map((option) => (
<CommandItem
key={option}
value={option}
onSelect={() => {
handleField("location", option);
setIsAddressSuggestOpen(false);
}}
className="gap-2 px-3 py-2 text-gray-700 data-[selected=true]:bg-[#063e8e]/10 data-[selected=true]:text-[#063e8e]"
>
<Check
className={`h-4 w-4 shrink-0 text-[#063e8e] ${form.location === option ? "opacity-100" : "opacity-0"
}`}
/>
<span className="truncate">{option}</span>
</CommandItem>
))
)}
</CommandList>
</Command>
</PopoverContent>
</Popover>
<EventAddressManagerDialog
open={isAddressManagerOpen}
onOpenChange={setIsAddressManagerOpen}
/>
</div>
......
"use client";
import { useMemo, useState } from "react";
import { useQueryClient } from "@tanstack/react-query";
import { Loader2, Pencil, Plus, Trash2 } from "lucide-react";
import { toast } from "sonner";
import {
useDeleteApiV10EventAddressId,
useGetApiV10EventAddress,
usePostApiV10EventAddress,
usePutApiV10EventAddressId,
} from "@/api/vcci-news/endpoints/event-address";
import { Button } from "@/components/ui/button";
import {
Dialog,
DialogContent,
DialogDescription,
DialogHeader,
DialogTitle,
} from "@/components/ui/dialog";
import { Input } from "@/components/ui/input";
import { PermissionGate } from "@/components/shared/permission-gate";
const EVENT_ADDRESS_QUERY_KEY = "/api/v1.0/eventAddress";
interface EventAddressItem {
id: string;
information: string;
}
interface EventAddressManagerDialogProps {
open: boolean;
onOpenChange: (open: boolean) => void;
}
export function EventAddressManagerDialog({
open,
onOpenChange,
}: EventAddressManagerDialogProps) {
const queryClient = useQueryClient();
const [newInformation, setNewInformation] = useState("");
const [editingId, setEditingId] = useState<string | null>(null);
const [editingInformation, setEditingInformation] = useState("");
const [deletingId, setDeletingId] = useState<string | null>(null);
const { data, isLoading } = useGetApiV10EventAddress(
open ? { page: 1, pageSize: 100, sortField: "information", sortOrder: "asc" } : undefined,
);
const addresses = useMemo(() => {
const rows = data?.responseData?.rows ?? [];
return rows
.map((row) => {
const record = (row ?? {}) as Record<string, unknown>;
return {
id: String(record.id ?? ""),
information: String(record.information ?? "").trim(),
};
})
.filter((item) => item.id && item.information);
}, [data]);
const invalidateAddresses = () => {
queryClient.invalidateQueries({
queryKey: [EVENT_ADDRESS_QUERY_KEY],
exact: false,
});
};
const createMutation = usePostApiV10EventAddress({
mutation: { onSettled: invalidateAddresses },
});
const updateMutation = usePutApiV10EventAddressId({
mutation: { onSettled: invalidateAddresses },
});
const deleteMutation = useDeleteApiV10EventAddressId({
mutation: { onSettled: invalidateAddresses },
});
const handleCreate = async () => {
const value = newInformation.trim();
if (!value) {
toast.error("Vui lòng nhập địa chỉ");
return;
}
try {
await createMutation.mutateAsync({ data: { information: value } });
toast.success("Tạo địa chỉ thành công");
setNewInformation("");
} catch (error) {
const err = error as { message?: string };
toast.error(err?.message || "Tạo địa chỉ thất bại");
}
};
const handleStartEdit = (item: EventAddressItem) => {
setEditingId(item.id);
setEditingInformation(item.information);
};
const handleCancelEdit = () => {
setEditingId(null);
setEditingInformation("");
};
const handleUpdate = async () => {
if (!editingId) return;
const value = editingInformation.trim();
if (!value) {
toast.error("Vui lòng nhập địa chỉ");
return;
}
try {
await updateMutation.mutateAsync({ id: editingId, data: { information: value } });
toast.success("Cập nhật địa chỉ thành công");
setEditingId(null);
setEditingInformation("");
} catch (error) {
const err = error as { message?: string };
toast.error(err?.message || "Cập nhật địa chỉ thất bại");
}
};
const handleConfirmDelete = async () => {
if (!deletingId) return;
try {
await deleteMutation.mutateAsync({ id: deletingId });
toast.success("Xóa địa chỉ thành công");
setDeletingId(null);
} catch (error) {
const err = error as { message?: string };
toast.error(err?.message || "Xóa địa chỉ thất bại");
}
};
const handleOpenChange = (nextOpen: boolean) => {
if (!nextOpen) {
setEditingId(null);
setEditingInformation("");
setDeletingId(null);
}
onOpenChange(nextOpen);
};
return (
<Dialog open={open} onOpenChange={handleOpenChange}>
<DialogContent className="max-w-lg">
<DialogHeader>
<DialogTitle>Quản lý địa điểm</DialogTitle>
<DialogDescription>
Danh sách địa điểm dùng cho các sự kiện trong hệ thống.
</DialogDescription>
</DialogHeader>
<PermissionGate required="settings:write">
<div className="flex gap-2">
<Input
value={newInformation}
onChange={(event) => setNewInformation(event.target.value)}
placeholder="Nhập địa chỉ mới"
className="rounded-xl border-[#063e8e]/15 bg-white text-gray-700 placeholder:text-gray-700 focus-visible:ring-[#063e8e]/30"
onKeyDown={(event) => {
if (event.key === "Enter") {
event.preventDefault();
handleCreate();
}
}}
/>
<Button
type="button"
onClick={handleCreate}
disabled={createMutation.isPending || !newInformation.trim()}
className="shrink-0 rounded-xl bg-[#063e8e] text-white hover:bg-[#063e8e]/90"
>
{createMutation.isPending ? (
<Loader2 className="h-4 w-4 animate-spin" />
) : (
<Plus className="h-4 w-4" />
)}
Thêm
</Button>
</div>
</PermissionGate>
<div className="mt-3 max-h-80 space-y-2 overflow-y-auto pr-1">
{isLoading ? (
<div className="flex items-center justify-center gap-2 py-8 text-sm text-gray-500">
<Loader2 className="h-4 w-4 animate-spin" />
Đang tải danh sách địa chỉ...
</div>
) : addresses.length === 0 ? (
<p className="py-8 text-center text-sm text-gray-500">Chưa có địa chỉ nào</p>
) : (
addresses.map((item) => (
<div
key={item.id}
className="flex items-center justify-between gap-2 rounded-xl border border-[#063e8e]/10 px-3 py-2"
>
{editingId === item.id ? (
<div className="flex flex-1 items-center gap-2">
<Input
value={editingInformation}
onChange={(event) => setEditingInformation(event.target.value)}
className="h-8 rounded-lg border-[#063e8e]/15 bg-white text-sm text-gray-700"
onKeyDown={(event) => {
if (event.key === "Enter") handleUpdate();
}}
/>
<Button
type="button"
size="sm"
onClick={handleUpdate}
disabled={updateMutation.isPending || !editingInformation.trim()}
>
Lưu
</Button>
<Button
type="button"
variant="outline"
size="sm"
onClick={handleCancelEdit}
>
Hủy
</Button>
</div>
) : deletingId === item.id ? (
<>
<span className="text-sm text-gray-700">Xóa địa chỉ này?</span>
<div className="flex gap-1">
<Button
type="button"
size="sm"
variant="destructive"
onClick={handleConfirmDelete}
disabled={deleteMutation.isPending}
>
Xóa
</Button>
<Button
type="button"
size="sm"
variant="outline"
onClick={() => setDeletingId(null)}
>
Hủy
</Button>
</div>
</>
) : (
<>
<span className="text-sm text-gray-700">{item.information}</span>
<PermissionGate required="settings:write">
<div className="flex gap-1">
<button
type="button"
onClick={() => handleStartEdit(item)}
className="rounded-full p-1.5 text-gray-500 hover:bg-[#063e8e]/10 hover:text-[#063e8e]"
aria-label="Sửa địa chỉ"
>
<Pencil className="h-4 w-4" />
</button>
<button
type="button"
onClick={() => setDeletingId(item.id)}
className="rounded-full p-1 text-gray-500 hover:bg-red-50 hover:text-red-600"
aria-label="Xóa địa chỉ"
>
<Trash2 className="h-4 w-4" />
</button>
</div>
</PermissionGate>
</>
)}
</div>
))
)}
</div>
</DialogContent>
</Dialog>
);
}
import parse from "html-react-parser";
import type { ReactNode } from "react";
import type { DynamicPostContentSection } from "@/api/vcci-news/types/post";
function normalizeCaptionShortcodes(html: string) {
......@@ -118,13 +119,10 @@ function renderStructuredHtml(html: string) {
return parse(normalizeImportedLayout(normalizeCaptionShortcodes(html)));
}
export function TextSection({ section }: { section: DynamicPostContentSection }) {
const content = section.content.trim();
if (!content) return null;
export function PostTextSection({ children }: { children: ReactNode }) {
return (
<div className="post-text-section">
{renderStructuredHtml(content)}
{children}
<style jsx global>{`
.post-text-section {
......@@ -215,3 +213,10 @@ export function TextSection({ section }: { section: DynamicPostContentSection })
</div>
);
}
export function TextSection({ section }: { section: DynamicPostContentSection }) {
const content = section.content.trim();
if (!content) return null;
return <PostTextSection>{renderStructuredHtml(content)}</PostTextSection>;
}
......@@ -415,6 +415,11 @@ export function AdminRichTextEditor({
margin-bottom: 1em;
}
.admin-rich-text-editor .jodit-wysiwyg a {
color: #14519f;
text-decoration: underline;
}
.admin-rich-text-editor .jodit-wysiwyg .article-content,
.admin-rich-text-editor .jodit-wysiwyg .article-content_toc,
.admin-rich-text-editor .jodit-wysiwyg table,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment