45
resources/client/reviews/requests/use-create-review.ts
Executable file
45
resources/client/reviews/requests/use-create-review.ts
Executable file
@@ -0,0 +1,45 @@
|
||||
import {BackendResponse} from '@common/http/backend-response/backend-response';
|
||||
import {useMutation} from '@tanstack/react-query';
|
||||
import {apiClient, queryClient} from '@common/http/query-client';
|
||||
import {showHttpErrorToast} from '@common/utils/http/show-http-error-toast';
|
||||
import {Review} from '@app/titles/models/review';
|
||||
import {Reviewable} from '@app/reviews/reviewable';
|
||||
import {UseFormReturn} from 'react-hook-form';
|
||||
import {onFormQueryError} from '@common/errors/on-form-query-error';
|
||||
import {reviewsQueryKey} from '@app/reviews/requests/use-reviews';
|
||||
|
||||
interface Response extends BackendResponse {
|
||||
review: Review;
|
||||
}
|
||||
|
||||
export interface CreateReviewPayload {
|
||||
score: number;
|
||||
title?: string;
|
||||
body?: string;
|
||||
}
|
||||
|
||||
interface Payload extends CreateReviewPayload {
|
||||
reviewable: Reviewable;
|
||||
}
|
||||
|
||||
export function useCreateReview(form?: UseFormReturn<CreateReviewPayload>) {
|
||||
return useMutation({
|
||||
mutationFn: (payload: Payload) => createReview(payload),
|
||||
onSuccess: async () => {
|
||||
await queryClient.invalidateQueries({queryKey: reviewsQueryKey()});
|
||||
},
|
||||
onError: r => (form ? onFormQueryError(r, form) : showHttpErrorToast(r)),
|
||||
});
|
||||
}
|
||||
|
||||
function createReview(payload: Payload): Promise<Response> {
|
||||
return apiClient
|
||||
.post(`reviews`, {
|
||||
reviewable_id: payload.reviewable.id,
|
||||
reviewable_type: payload.reviewable.model_type,
|
||||
score: payload.score,
|
||||
title: payload.title,
|
||||
body: payload.body,
|
||||
})
|
||||
.then(r => r.data);
|
||||
}
|
||||
36
resources/client/reviews/requests/use-current-user-ratings.ts
Executable file
36
resources/client/reviews/requests/use-current-user-ratings.ts
Executable file
@@ -0,0 +1,36 @@
|
||||
import {useQuery} from '@tanstack/react-query';
|
||||
import {apiClient} from '@common/http/query-client';
|
||||
import {BackendResponse} from '@common/http/backend-response/backend-response';
|
||||
import {useAuth} from '@common/auth/use-auth';
|
||||
import {Title} from '@app/titles/models/title';
|
||||
import {Episode} from '@app/titles/models/episode';
|
||||
|
||||
interface Response extends BackendResponse {
|
||||
ratings: {
|
||||
episode: Record<number, {id: number; score: number}>;
|
||||
title: Record<number, {id: number; score: number}>;
|
||||
};
|
||||
}
|
||||
|
||||
export function useCurrentUserRatings() {
|
||||
const {user} = useAuth();
|
||||
return useQuery({
|
||||
queryKey: ['reviews', 'users', `${user?.id}`],
|
||||
queryFn: () => fetchRatings(),
|
||||
enabled: !!user,
|
||||
});
|
||||
}
|
||||
|
||||
export function useCurrentUserRatingFor(item: Title | Episode) {
|
||||
const query = useCurrentUserRatings();
|
||||
return {
|
||||
isLoading: query.isLoading && query.fetchStatus !== 'idle',
|
||||
rating: query.data?.ratings?.[item.model_type]?.[item.id],
|
||||
};
|
||||
}
|
||||
|
||||
function fetchRatings() {
|
||||
return apiClient
|
||||
.get<Response>(`users/me/ratings`)
|
||||
.then(response => response.data);
|
||||
}
|
||||
27
resources/client/reviews/requests/use-delete-reviews.ts
Executable file
27
resources/client/reviews/requests/use-delete-reviews.ts
Executable file
@@ -0,0 +1,27 @@
|
||||
import {BackendResponse} from '@common/http/backend-response/backend-response';
|
||||
import {useMutation} from '@tanstack/react-query';
|
||||
import {apiClient, queryClient} from '@common/http/query-client';
|
||||
import {showHttpErrorToast} from '@common/utils/http/show-http-error-toast';
|
||||
import {reviewsQueryKey} from '@app/reviews/requests/use-reviews';
|
||||
|
||||
interface Response extends BackendResponse {
|
||||
//
|
||||
}
|
||||
|
||||
interface Payload {
|
||||
reviewIds: number[];
|
||||
}
|
||||
|
||||
export function useDeleteReviews() {
|
||||
return useMutation({
|
||||
mutationFn: (payload: Payload) => deleteReviews(payload),
|
||||
onSuccess: async () => {
|
||||
await queryClient.invalidateQueries({queryKey: reviewsQueryKey()});
|
||||
},
|
||||
onError: r => showHttpErrorToast(r),
|
||||
});
|
||||
}
|
||||
|
||||
function deleteReviews({reviewIds}: Payload): Promise<Response> {
|
||||
return apiClient.delete(`reviews/${reviewIds.join(',')}`).then(r => r.data);
|
||||
}
|
||||
46
resources/client/reviews/requests/use-reviews.ts
Executable file
46
resources/client/reviews/requests/use-reviews.ts
Executable file
@@ -0,0 +1,46 @@
|
||||
import {useInfiniteData} from '@common/ui/infinite-scroll/use-infinite-data';
|
||||
import {Reviewable} from '@app/reviews/reviewable';
|
||||
import {Review} from '@app/titles/models/review';
|
||||
import {useLocalStorage} from '@common/utils/hooks/local-storage';
|
||||
import {useSearchParams} from 'react-router-dom';
|
||||
|
||||
export interface UseReviewAdditionalData {
|
||||
current_user_review?: Review;
|
||||
shared_review?: Review;
|
||||
}
|
||||
|
||||
export function reviewsQueryKey(
|
||||
reviewable?: Reviewable,
|
||||
params?: Record<string, any>,
|
||||
) {
|
||||
const key: any[] = ['reviews'];
|
||||
if (reviewable) {
|
||||
key.push(`${reviewable.id}-${reviewable.model_type}`);
|
||||
}
|
||||
if (params) {
|
||||
key.push(params);
|
||||
}
|
||||
return key;
|
||||
}
|
||||
|
||||
export function useReviews(reviewable: Reviewable) {
|
||||
const [searchParams] = useSearchParams();
|
||||
const [sort] = useLocalStorage(
|
||||
`reviewSort.${reviewable.model_type}`,
|
||||
'created_at:desc',
|
||||
);
|
||||
const [defaultOrderBy, defaultOrderDir] = sort.split(':');
|
||||
return useInfiniteData<Review, UseReviewAdditionalData>({
|
||||
willSortOrFilter: true,
|
||||
queryKey: reviewsQueryKey(reviewable, {sort}),
|
||||
endpoint: 'reviewable/reviews',
|
||||
defaultOrderBy,
|
||||
defaultOrderDir: defaultOrderDir as 'asc' | 'desc',
|
||||
queryParams: {
|
||||
reviewable_type: reviewable.model_type,
|
||||
reviewable_id: reviewable.id,
|
||||
perPage: 5,
|
||||
sharedReviewId: searchParams.get('reviewId'),
|
||||
},
|
||||
});
|
||||
}
|
||||
33
resources/client/reviews/requests/use-submit-review-feedback.ts
Executable file
33
resources/client/reviews/requests/use-submit-review-feedback.ts
Executable file
@@ -0,0 +1,33 @@
|
||||
import {BackendResponse} from '@common/http/backend-response/backend-response';
|
||||
import {useMutation} from '@tanstack/react-query';
|
||||
import {apiClient} from '@common/http/query-client';
|
||||
import {showHttpErrorToast} from '@common/utils/http/show-http-error-toast';
|
||||
import {Review} from '@app/titles/models/review';
|
||||
import {toast} from '@common/ui/toast/toast';
|
||||
import {message} from '@common/i18n/message';
|
||||
|
||||
interface Response extends BackendResponse {
|
||||
review: Review;
|
||||
}
|
||||
|
||||
interface Payload {
|
||||
isHelpful: boolean;
|
||||
}
|
||||
|
||||
export function useSubmitReviewFeedback(review: Review) {
|
||||
return useMutation({
|
||||
mutationFn: (payload: Payload) => submitFeedback(payload, review),
|
||||
onSuccess: () => {
|
||||
toast(message('Feedback submitted'));
|
||||
},
|
||||
onError: r => showHttpErrorToast(r),
|
||||
});
|
||||
}
|
||||
|
||||
function submitFeedback(payload: Payload, review: Review): Promise<Response> {
|
||||
return apiClient
|
||||
.post(`reviews/${review.id}/feedback`, {
|
||||
is_helpful: payload.isHelpful,
|
||||
})
|
||||
.then(r => r.data);
|
||||
}
|
||||
Reference in New Issue
Block a user