feat(spa): comment field in queue review, date picker in log sheet
All checks were successful
CI / Check / Test (push) Successful in 17m20s
All checks were successful
CI / Check / Test (push) Successful in 17m20s
This commit is contained in:
@@ -1,9 +1,13 @@
|
|||||||
import { useState } from "react"
|
import { useState } from "react"
|
||||||
import { useTranslation } from "react-i18next"
|
import { useTranslation } from "react-i18next"
|
||||||
import { VisuallyHidden } from "radix-ui"
|
import { VisuallyHidden } from "radix-ui"
|
||||||
|
import { CalendarIcon } from "lucide-react"
|
||||||
|
import { format } from "date-fns"
|
||||||
import { Drawer, DrawerContent, DrawerTitle } from "@/components/ui/drawer"
|
import { Drawer, DrawerContent, DrawerTitle } from "@/components/ui/drawer"
|
||||||
import { Button } from "@/components/ui/button"
|
import { Button } from "@/components/ui/button"
|
||||||
import { Textarea } from "@/components/ui/textarea"
|
import { Textarea } from "@/components/ui/textarea"
|
||||||
|
import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover"
|
||||||
|
import { Calendar } from "@/components/ui/calendar"
|
||||||
import { StarRating } from "@/components/star-rating"
|
import { StarRating } from "@/components/star-rating"
|
||||||
import { SearchOverlay } from "@/components/search-overlay"
|
import { SearchOverlay } from "@/components/search-overlay"
|
||||||
import type { MovieSelection } from "@/components/search-overlay"
|
import type { MovieSelection } from "@/components/search-overlay"
|
||||||
@@ -22,12 +26,14 @@ export function LogSheet({ open, onOpenChange }: LogSheetProps) {
|
|||||||
const [movie, setMovie] = useState<MovieSelection | null>(null)
|
const [movie, setMovie] = useState<MovieSelection | null>(null)
|
||||||
const [rating, setRating] = useState(0)
|
const [rating, setRating] = useState(0)
|
||||||
const [comment, setComment] = useState("")
|
const [comment, setComment] = useState("")
|
||||||
|
const [watchedAt, setWatchedAt] = useState<Date>(new Date())
|
||||||
const logMutation = useLogReview()
|
const logMutation = useLogReview()
|
||||||
|
|
||||||
function reset() {
|
function reset() {
|
||||||
setMovie(null)
|
setMovie(null)
|
||||||
setRating(0)
|
setRating(0)
|
||||||
setComment("")
|
setComment("")
|
||||||
|
setWatchedAt(new Date())
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleClose() {
|
function handleClose() {
|
||||||
@@ -45,7 +51,7 @@ export function LogSheet({ open, onOpenChange }: LogSheetProps) {
|
|||||||
manual_director: movie.director,
|
manual_director: movie.director,
|
||||||
rating,
|
rating,
|
||||||
comment: comment || undefined,
|
comment: comment || undefined,
|
||||||
watched_at: new Date().toISOString().replace("Z", "").split(".")[0]!,
|
watched_at: watchedAt.toISOString().replace("Z", "").split(".")[0]!,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
onSuccess: () => {
|
onSuccess: () => {
|
||||||
@@ -86,6 +92,28 @@ export function LogSheet({ open, onOpenChange }: LogSheetProps) {
|
|||||||
|
|
||||||
<Textarea value={comment} onChange={(e) => setComment(e.target.value)} placeholder={t("logReview.commentPlaceholder")} className="mb-5" rows={3} />
|
<Textarea value={comment} onChange={(e) => setComment(e.target.value)} placeholder={t("logReview.commentPlaceholder")} className="mb-5" rows={3} />
|
||||||
|
|
||||||
|
<div className="mb-5">
|
||||||
|
<p className="mb-2 text-xs uppercase tracking-wide text-muted-foreground">{t("logReview.watchedAt")}</p>
|
||||||
|
<Popover modal>
|
||||||
|
<PopoverTrigger asChild>
|
||||||
|
<Button variant="outline" className="w-full justify-start text-left font-normal">
|
||||||
|
<CalendarIcon className="mr-2 size-4" />
|
||||||
|
{format(watchedAt, "PPP")}
|
||||||
|
</Button>
|
||||||
|
</PopoverTrigger>
|
||||||
|
<PopoverContent className="w-auto p-0" align="start">
|
||||||
|
<Calendar
|
||||||
|
mode="single"
|
||||||
|
fixedWeeks
|
||||||
|
selected={watchedAt}
|
||||||
|
onSelect={(d) => d && setWatchedAt(d)}
|
||||||
|
disabled={(d) => d > new Date()}
|
||||||
|
autoFocus
|
||||||
|
/>
|
||||||
|
</PopoverContent>
|
||||||
|
</Popover>
|
||||||
|
</div>
|
||||||
|
|
||||||
<Button onClick={handleSubmit} disabled={!rating || logMutation.isPending} className="w-full" size="lg">
|
<Button onClick={handleSubmit} disabled={!rating || logMutation.isPending} className="w-full" size="lg">
|
||||||
{logMutation.isPending ? t("logReview.logging") : t("logReview.logReview")}
|
{logMutation.isPending ? t("logReview.logging") : t("logReview.logReview")}
|
||||||
</Button>
|
</Button>
|
||||||
|
|||||||
@@ -274,7 +274,9 @@
|
|||||||
"commentPlaceholder": "Add a comment... (optional)",
|
"commentPlaceholder": "Add a comment... (optional)",
|
||||||
"logging": "Logging...",
|
"logging": "Logging...",
|
||||||
"logReview": "Log Review",
|
"logReview": "Log Review",
|
||||||
"logged": "{{title}} logged!"
|
"logged": "{{title}} logged!",
|
||||||
|
"watchedAt": "Watched on",
|
||||||
|
"pickDate": "Pick a date"
|
||||||
},
|
},
|
||||||
"searchOverlay": {
|
"searchOverlay": {
|
||||||
"backToSearch": "Back to search",
|
"backToSearch": "Back to search",
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import { VirtualList } from "@/components/virtual-list"
|
|||||||
import { Button } from "@/components/ui/button"
|
import { Button } from "@/components/ui/button"
|
||||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"
|
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"
|
||||||
import { Skeleton } from "@/components/ui/skeleton"
|
import { Skeleton } from "@/components/ui/skeleton"
|
||||||
|
import { Textarea } from "@/components/ui/textarea"
|
||||||
import { StarRating } from "@/components/star-rating"
|
import { StarRating } from "@/components/star-rating"
|
||||||
import { useAuth } from "@/components/auth-provider"
|
import { useAuth } from "@/components/auth-provider"
|
||||||
import { useQueryClient } from "@tanstack/react-query"
|
import { useQueryClient } from "@tanstack/react-query"
|
||||||
@@ -204,6 +205,7 @@ function QueueTab() {
|
|||||||
const confirmMutation = useConfirmWatch()
|
const confirmMutation = useConfirmWatch()
|
||||||
const dismissMutation = useDismissWatch()
|
const dismissMutation = useDismissWatch()
|
||||||
const [ratings, setRatings] = useState<Record<string, number>>({})
|
const [ratings, setRatings] = useState<Record<string, number>>({})
|
||||||
|
const [comments, setComments] = useState<Record<string, string>>({})
|
||||||
|
|
||||||
if (isPending) return <FeedSkeleton />
|
if (isPending) return <FeedSkeleton />
|
||||||
if (!data?.length)
|
if (!data?.length)
|
||||||
@@ -224,13 +226,24 @@ function QueueTab() {
|
|||||||
size="sm"
|
size="sm"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
<Textarea
|
||||||
|
className="mt-2"
|
||||||
|
placeholder={t("diary.commentPlaceholder")}
|
||||||
|
value={comments[entry.id] ?? ""}
|
||||||
|
onChange={(e) => setComments((p) => ({ ...p, [entry.id]: e.target.value }))}
|
||||||
|
rows={2}
|
||||||
|
/>
|
||||||
<div className="mt-2 flex gap-2">
|
<div className="mt-2 flex gap-2">
|
||||||
<Button
|
<Button
|
||||||
size="sm"
|
size="sm"
|
||||||
disabled={!ratings[entry.id]}
|
disabled={!ratings[entry.id]}
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
confirmMutation.mutate({
|
confirmMutation.mutate({
|
||||||
confirmations: [{ watch_event_id: entry.id, rating: ratings[entry.id]! }],
|
confirmations: [{
|
||||||
|
watch_event_id: entry.id,
|
||||||
|
rating: ratings[entry.id]!,
|
||||||
|
comment: comments[entry.id] || undefined,
|
||||||
|
}],
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
|
|||||||
Reference in New Issue
Block a user