mirror of
https://github.com/fergalmoran/opengifame.git
synced 2025-12-25 11:09:40 +00:00
Fix build errors
This commit is contained in:
@@ -11,6 +11,7 @@ const config = {
|
|||||||
"plugin:@typescript-eslint/stylistic-type-checked",
|
"plugin:@typescript-eslint/stylistic-type-checked",
|
||||||
],
|
],
|
||||||
rules: {
|
rules: {
|
||||||
|
"@typescript-eslint/no-empty-object-type": "off",
|
||||||
"@typescript-eslint/prefer-nullish-coalescing": "off",
|
"@typescript-eslint/prefer-nullish-coalescing": "off",
|
||||||
"@typescript-eslint/array-type": "off",
|
"@typescript-eslint/array-type": "off",
|
||||||
"@typescript-eslint/consistent-type-definitions": "off",
|
"@typescript-eslint/consistent-type-definitions": "off",
|
||||||
|
|||||||
2
.vscode/settings.json
vendored
2
.vscode/settings.json
vendored
@@ -1,4 +1,4 @@
|
|||||||
{
|
{
|
||||||
// "workbench.colorTheme": "Tinacious Design (High Contrast)"
|
// "workbench.colorTheme": "Tinacious Design (High Contrast)"
|
||||||
"workbench.colorTheme": "Cyberpunk 2077 rebuild",
|
"workbench.colorTheme": "Moonlight",
|
||||||
}
|
}
|
||||||
8519
package-lock.json
generated
Normal file
8519
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
BIN
public/images/default-image.jpg
Normal file
BIN
public/images/default-image.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 53 KiB |
59
src/components/ui/alert.tsx
Normal file
59
src/components/ui/alert.tsx
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
import * as React from "react"
|
||||||
|
import { cva, type VariantProps } from "class-variance-authority"
|
||||||
|
|
||||||
|
import { cn } from "@/lib/utils"
|
||||||
|
|
||||||
|
const alertVariants = cva(
|
||||||
|
"relative w-full rounded-lg border px-4 py-3 text-sm [&>svg+div]:translate-y-[-3px] [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg]:text-foreground [&>svg~*]:pl-7",
|
||||||
|
{
|
||||||
|
variants: {
|
||||||
|
variant: {
|
||||||
|
default: "bg-background text-foreground",
|
||||||
|
destructive:
|
||||||
|
"border-destructive/50 text-destructive dark:border-destructive [&>svg]:text-destructive",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
defaultVariants: {
|
||||||
|
variant: "default",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
const Alert = React.forwardRef<
|
||||||
|
HTMLDivElement,
|
||||||
|
React.HTMLAttributes<HTMLDivElement> & VariantProps<typeof alertVariants>
|
||||||
|
>(({ className, variant, ...props }, ref) => (
|
||||||
|
<div
|
||||||
|
ref={ref}
|
||||||
|
role="alert"
|
||||||
|
className={cn(alertVariants({ variant }), className)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
))
|
||||||
|
Alert.displayName = "Alert"
|
||||||
|
|
||||||
|
const AlertTitle = React.forwardRef<
|
||||||
|
HTMLParagraphElement,
|
||||||
|
React.HTMLAttributes<HTMLHeadingElement>
|
||||||
|
>(({ className, ...props }, ref) => (
|
||||||
|
<h5
|
||||||
|
ref={ref}
|
||||||
|
className={cn("mb-1 font-medium leading-none tracking-tight", className)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
))
|
||||||
|
AlertTitle.displayName = "AlertTitle"
|
||||||
|
|
||||||
|
const AlertDescription = React.forwardRef<
|
||||||
|
HTMLParagraphElement,
|
||||||
|
React.HTMLAttributes<HTMLParagraphElement>
|
||||||
|
>(({ className, ...props }, ref) => (
|
||||||
|
<div
|
||||||
|
ref={ref}
|
||||||
|
className={cn("text-sm [&_p]:leading-relaxed", className)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
))
|
||||||
|
AlertDescription.displayName = "AlertDescription"
|
||||||
|
|
||||||
|
export { Alert, AlertTitle, AlertDescription }
|
||||||
25
src/components/ui/input.tsx
Normal file
25
src/components/ui/input.tsx
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
import * as React from "react"
|
||||||
|
|
||||||
|
import { cn } from "@/lib/utils"
|
||||||
|
|
||||||
|
export interface InputProps
|
||||||
|
extends React.InputHTMLAttributes<HTMLInputElement> {}
|
||||||
|
|
||||||
|
const Input = React.forwardRef<HTMLInputElement, InputProps>(
|
||||||
|
({ className, type, ...props }, ref) => {
|
||||||
|
return (
|
||||||
|
<input
|
||||||
|
type={type}
|
||||||
|
className={cn(
|
||||||
|
"flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
ref={ref}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
Input.displayName = "Input"
|
||||||
|
|
||||||
|
export { Input }
|
||||||
@@ -1,99 +1,99 @@
|
|||||||
'use client';
|
"use client";
|
||||||
import React from 'react';
|
import React from "react";
|
||||||
import Image from 'next/image';
|
import Image from "next/image";
|
||||||
import { TbThumbUp, TbThumbDown } from 'react-icons/tb';
|
import { TbThumbUp, TbThumbDown } from "react-icons/tb";
|
||||||
import Link from 'next/link';
|
import Link from "next/link";
|
||||||
|
|
||||||
interface IGifContainerProps {
|
// interface IGifContainerProps {
|
||||||
gif: Gif;
|
// gif: Gif;
|
||||||
isLink?: boolean;
|
// isLink?: boolean;
|
||||||
showDetails?: boolean;
|
// showDetails?: boolean;
|
||||||
}
|
// }
|
||||||
const GifContainer: React.FC<IGifContainerProps> = ({
|
// const GifContainer: React.FC<IGifContainerProps> = ({
|
||||||
gif,
|
// gif,
|
||||||
isLink = true,
|
// isLink = true,
|
||||||
showDetails = true,
|
// showDetails = true,
|
||||||
}) => {
|
// }) => {
|
||||||
const [upVotes, setUpVotes] = React.useState<number>(gif.upVotes);
|
// const [upVotes, setUpVotes] = React.useState<number>(gif.upVotes);
|
||||||
const [downVotes, setDownVotes] = React.useState<number>(gif.downVotes);
|
// const [downVotes, setDownVotes] = React.useState<number>(gif.downVotes);
|
||||||
|
|
||||||
const _doot = async (id: string, isUp: boolean) => {
|
// const _doot = async (id: string, isUp: boolean) => {
|
||||||
const response = await fetch(`api/votes?gifId=${id}&isUp=${isUp ? 1 : 0}`, {
|
// const response = await fetch(`api/votes?gifId=${id}&isUp=${isUp ? 1 : 0}`, {
|
||||||
method: 'POST',
|
// method: 'POST',
|
||||||
});
|
// });
|
||||||
if (response.status === 200) {
|
// if (response.status === 200) {
|
||||||
const result = (await response.json()) as Gif;
|
// const result = (await response.json()) as Gif;
|
||||||
setUpVotes(result.upVotes);
|
// setUpVotes(result.upVotes);
|
||||||
setDownVotes(result.downVotes);
|
// setDownVotes(result.downVotes);
|
||||||
}
|
// }
|
||||||
};
|
// };
|
||||||
return (
|
// return (
|
||||||
<>
|
// <>
|
||||||
<div className="group relative h-[17.5rem] transform overflow-hidden rounded-4xl">
|
// <div className="group relative h-[17.5rem] transform overflow-hidden rounded-4xl">
|
||||||
<div className="absolute inset-0">
|
// <div className="absolute inset-0">
|
||||||
{isLink ? (
|
// {isLink ? (
|
||||||
<Link
|
// <Link
|
||||||
href={`gifs/${gif.slug}`}
|
// href={`gifs/${gif.slug}`}
|
||||||
title={gif.title}
|
// title={gif.title}
|
||||||
>
|
// >
|
||||||
<Image
|
// <Image
|
||||||
alt={gif.title}
|
// alt={gif.title}
|
||||||
className="absolute inset-0 transition duration-300 group-hover:scale-110"
|
// className="absolute inset-0 transition duration-300 group-hover:scale-110"
|
||||||
src={gif.fileName}
|
// src={gif.fileName}
|
||||||
fill
|
// fill
|
||||||
sizes="100vw"
|
// sizes="100vw"
|
||||||
style={{
|
// style={{
|
||||||
objectFit: 'fill',
|
// objectFit: 'fill',
|
||||||
}}
|
// }}
|
||||||
/>
|
// />
|
||||||
</Link>
|
// </Link>
|
||||||
) : (
|
// ) : (
|
||||||
<Image
|
// <Image
|
||||||
alt={gif.title}
|
// alt={gif.title}
|
||||||
className="absolute inset-0 transition duration-300 group-hover:scale-110"
|
// className="absolute inset-0 transition duration-300 group-hover:scale-110"
|
||||||
src={gif.fileName}
|
// src={gif.fileName}
|
||||||
fill
|
// fill
|
||||||
sizes="100vw"
|
// sizes="100vw"
|
||||||
style={{
|
// style={{
|
||||||
objectFit: 'fill',
|
// objectFit: 'fill',
|
||||||
}}
|
// }}
|
||||||
/>
|
// />
|
||||||
)}
|
// )}
|
||||||
</div>
|
// </div>
|
||||||
</div>
|
// </div>
|
||||||
{showDetails && (
|
// {showDetails && (
|
||||||
<div className="flex flex-row p-2">
|
// <div className="flex flex-row p-2">
|
||||||
<div className="flex-1 space-x-2 text-base">
|
// <div className="flex-1 space-x-2 text-base">
|
||||||
{gif.searchTerms?.map((t) => (
|
// {gif.searchTerms?.map((t) => (
|
||||||
<div
|
// <div
|
||||||
key={t}
|
// key={t}
|
||||||
className="mr-0.5 badge badge-info badge-md badge-outline"
|
// className="mr-0.5 badge badge-info badge-md badge-outline"
|
||||||
>
|
// >
|
||||||
{`#${t}`}
|
// {`#${t}`}
|
||||||
</div>
|
// </div>
|
||||||
))}
|
// ))}
|
||||||
</div>
|
// </div>
|
||||||
<div className="flex items-center justify-center space-x-1">
|
// <div className="flex items-center justify-center space-x-1">
|
||||||
<div className="flex transition duration-75 ease-in-out delay-150 hover:text-orange-700 hover:cursor-pointer">
|
// <div className="flex transition duration-75 ease-in-out delay-150 hover:text-orange-700 hover:cursor-pointer">
|
||||||
<span onClick={() => _doot(gif.id, true)}>
|
// <span onClick={() => _doot(gif.id, true)}>
|
||||||
<TbThumbUp className="w-5" />
|
// <TbThumbUp className="w-5" />
|
||||||
</span>
|
// </span>
|
||||||
<span className="text-xs">{upVotes}</span>
|
// <span className="text-xs">{upVotes}</span>
|
||||||
</div>
|
// </div>
|
||||||
<div className="flex transition duration-75 ease-in-out delay-150 hover:text-orange-700 hover:cursor-pointer">
|
// <div className="flex transition duration-75 ease-in-out delay-150 hover:text-orange-700 hover:cursor-pointer">
|
||||||
<span
|
// <span
|
||||||
onClick={() => _doot(gif.id, false)}
|
// onClick={() => _doot(gif.id, false)}
|
||||||
className="pl-2 "
|
// className="pl-2 "
|
||||||
>
|
// >
|
||||||
<TbThumbDown className="w-5" />
|
// <TbThumbDown className="w-5" />
|
||||||
</span>
|
// </span>
|
||||||
<span className="text-xs">{downVotes}</span>
|
// <span className="text-xs">{downVotes}</span>
|
||||||
</div>
|
// </div>
|
||||||
</div>
|
// </div>
|
||||||
</div>
|
// </div>
|
||||||
)}
|
// )}
|
||||||
</>
|
// </>
|
||||||
);
|
// );
|
||||||
};
|
// };
|
||||||
|
|
||||||
export default GifContainer;
|
// export default GifContainer;
|
||||||
|
|||||||
@@ -1,64 +1,61 @@
|
|||||||
/* eslint-disable @next/next/no-img-element */
|
// /* eslint-disable @next/next/no-img-element */
|
||||||
import React from 'react';
|
// import React from "react";
|
||||||
import { HiOutlineXMark } from 'react-icons/hi2';
|
// import { HiOutlineXMark } from "react-icons/hi2";
|
||||||
import { ImUpload2 } from 'react-icons/im';
|
// import { ImUpload2 } from "react-icons/im";
|
||||||
interface IImageUploadProps {
|
// interface IImageUploadProps {
|
||||||
value: string | undefined;
|
// value: string | undefined;
|
||||||
onChange: (image: File) => void;
|
// onChange: (image: File) => void;
|
||||||
}
|
// }
|
||||||
const ImageUpload: React.FC<IImageUploadProps> = ({ onChange }) => {
|
// const ImageUpload: React.FC<IImageUploadProps> = ({ onChange }) => {
|
||||||
const [image, setImage] = React.useState<string>();
|
// const [image, setImage] = React.useState<string>();
|
||||||
const onImageChange = ($event: React.ChangeEvent<HTMLInputElement>) => {
|
// const onImageChange = ($event: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
console.log('ImageUpload', 'onImageChange', $event);
|
// console.log("ImageUpload", "onImageChange", $event);
|
||||||
if ($event.target.files) {
|
// if ($event.target.files) {
|
||||||
const url = URL.createObjectURL($event.target.files[0]);
|
// const url = URL.createObjectURL($event.target.files[0]);
|
||||||
setImage(url);
|
// setImage(url);
|
||||||
onChange($event.target.files[0]);
|
// onChange($event.target.files[0]);
|
||||||
}
|
// }
|
||||||
};
|
// };
|
||||||
return (
|
// return (
|
||||||
<div className="flex justify-center px-6 pt-5 pb-6 mt-1 border-2 border-dashed rounded-md border-secondary">
|
// <div className="mt-1 flex justify-center rounded-md border-2 border-dashed border-secondary px-6 pb-6 pt-5">
|
||||||
{image ? (
|
// {image ? (
|
||||||
<div>
|
// <div>
|
||||||
<div className="relative">
|
// <div className="relative">
|
||||||
<img
|
// <img src={image} alt="Preview" />
|
||||||
src={image}
|
// <button
|
||||||
alt="Preview"
|
// type="button"
|
||||||
/>
|
// className="absolute right-0 top-0 m-2 rounded-full p-2"
|
||||||
<button
|
// onClick={() => setImage("")}
|
||||||
type="button"
|
// >
|
||||||
className="absolute top-0 right-0 p-2 m-2 rounded-full "
|
// {""}
|
||||||
onClick={() => setImage('')}
|
// <HiOutlineXMark className="h-5 w-5" />
|
||||||
>
|
// </button>
|
||||||
{''}
|
// </div>
|
||||||
<HiOutlineXMark className="w-5 h-5" />
|
// </div>
|
||||||
</button>
|
// ) : (
|
||||||
</div>
|
// <div className="space-y-1 text-center">
|
||||||
</div>
|
// <ImUpload2 className="text-base-content/70 mx-auto mb-3 h-8 w-8" />
|
||||||
) : (
|
// <div className="text-base-content flex text-sm">
|
||||||
<div className="space-y-1 text-center">
|
// <label
|
||||||
<ImUpload2 className="w-8 h-8 mx-auto mb-3 text-base-content/70" />
|
// htmlFor="gif-upload"
|
||||||
<div className="flex text-sm text-base-content">
|
// className="badge badge-primary relative cursor-pointer rounded-md font-medium hover:text-accent"
|
||||||
<label
|
// >
|
||||||
htmlFor="gif-upload"
|
// <span>Upload a file</span>
|
||||||
className="relative font-medium rounded-md cursor-pointer hover:text-accent badge badge-primary"
|
// <input
|
||||||
>
|
// accept="image/gif,video/mp4,video/mov,video/quicktime,video/webm,youtube,vimeo"
|
||||||
<span>Upload a file</span>
|
// id="gif-upload"
|
||||||
<input
|
// type="file"
|
||||||
accept="image/gif,video/mp4,video/mov,video/quicktime,video/webm,youtube,vimeo"
|
// className="sr-only"
|
||||||
id="gif-upload"
|
// onChange={onImageChange}
|
||||||
type="file"
|
// />
|
||||||
className="sr-only"
|
// </label>
|
||||||
onChange={onImageChange}
|
// <p className="pl-1">or drag and drop</p>
|
||||||
/>
|
// </div>
|
||||||
</label>
|
// <p className="text-xs">PNG, JPG, GIF up to 10MB</p>
|
||||||
<p className="pl-1">or drag and drop</p>
|
// </div>
|
||||||
</div>
|
// )}
|
||||||
<p className="text-xs ">PNG, JPG, GIF up to 10MB</p>
|
// </div>
|
||||||
</div>
|
// );
|
||||||
)}
|
// };
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default ImageUpload;
|
// export default ImageUpload;
|
||||||
|
|||||||
@@ -1,143 +1,143 @@
|
|||||||
import { logger } from "@/lib/logger";
|
// import { logger } from "@/lib/logger";
|
||||||
import React, { KeyboardEventHandler } from "react";
|
// import React, { KeyboardEventHandler } from "react";
|
||||||
|
|
||||||
interface ITaggedInputProps {
|
// interface ITaggedInputProps {
|
||||||
label: string;
|
// label: string;
|
||||||
value: string[];
|
// value: string[];
|
||||||
onChange: (tags: string[]) => void;
|
// onChange: (tags: string[]) => void;
|
||||||
}
|
// }
|
||||||
const TaggedInput: React.FC<ITaggedInputProps> = ({
|
// const TaggedInput: React.FC<ITaggedInputProps> = ({
|
||||||
label,
|
// label,
|
||||||
value,
|
// value,
|
||||||
onChange,
|
// onChange,
|
||||||
}) => {
|
// }) => {
|
||||||
const [isSearching, setIsSearching] = React.useState(false);
|
// const [isSearching, setIsSearching] = React.useState(false);
|
||||||
const [searchText, setSearchText] = React.useState<string>("");
|
// const [searchText, setSearchText] = React.useState<string>("");
|
||||||
const [searchResults, setSearchResults] = React.useState<Array<string>>([]);
|
// const [searchResults, setSearchResults] = React.useState<Array<string>>([]);
|
||||||
const [tags, setTags] = React.useState<Array<string>>(value);
|
// const [tags, setTags] = React.useState<Array<string>>(value);
|
||||||
|
|
||||||
React.useEffect(() => {
|
// React.useEffect(() => {
|
||||||
logger.debug("TaggedInput", "callingOnChange", tags);
|
// logger.debug("TaggedInput", "callingOnChange", tags);
|
||||||
onChange(tags);
|
// onChange(tags);
|
||||||
}, [tags, onChange]);
|
// }, [tags, onChange]);
|
||||||
const removeTag = (tag: string) => {
|
// const removeTag = (tag: string) => {
|
||||||
setTags(tags.filter((obj) => obj !== tag));
|
// setTags(tags.filter((obj) => obj !== tag));
|
||||||
};
|
// };
|
||||||
const searchTags = async (query: string) => {
|
// const searchTags = async (query: string) => {
|
||||||
if (!query) {
|
// if (!query) {
|
||||||
setSearchResults([]);
|
// setSearchResults([]);
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
setIsSearching(true);
|
// setIsSearching(true);
|
||||||
const response = await fetch(`api/tags/search?q=${searchText}`);
|
// const response = await fetch(`api/tags/search?q=${searchText}`);
|
||||||
if (response.status === 200) {
|
// if (response.status === 200) {
|
||||||
const results = await response.json();
|
// const results = await response.json();
|
||||||
setSearchResults(results.map((r: { name: string }) => r.name));
|
// setSearchResults(results.map((r: { name: string }) => r.name));
|
||||||
}
|
// }
|
||||||
setIsSearching(false);
|
// setIsSearching(false);
|
||||||
};
|
// };
|
||||||
const handleChange = async ($event: React.ChangeEvent<HTMLInputElement>) => {
|
// const handleChange = async ($event: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
const { value } = $event.target;
|
// const { value } = $event.target;
|
||||||
setSearchText(value);
|
// setSearchText(value);
|
||||||
await searchTags(value);
|
// await searchTags(value);
|
||||||
};
|
// };
|
||||||
const handleKeyPress = ($event: React.KeyboardEvent<HTMLInputElement>) => {
|
// const handleKeyPress = ($event: React.KeyboardEvent<HTMLInputElement>) => {
|
||||||
if ($event.code === "Enter" || $event.code === "NumpadEnter") {
|
// if ($event.code === "Enter" || $event.code === "NumpadEnter") {
|
||||||
__addTag(searchText);
|
// __addTag(searchText);
|
||||||
}
|
// }
|
||||||
};
|
// };
|
||||||
const __addTag = (tag: string) => {
|
// const __addTag = (tag: string) => {
|
||||||
setTags([...tags, tag]);
|
// setTags([...tags, tag]);
|
||||||
setSearchResults([]);
|
// setSearchResults([]);
|
||||||
setIsSearching(false);
|
// setIsSearching(false);
|
||||||
setSearchText("");
|
// setSearchText("");
|
||||||
};
|
// };
|
||||||
const doResultClick = ($event: any) =>
|
// const doResultClick = ($event: any) =>
|
||||||
__addTag($event.target.textContent as string);
|
// __addTag($event.target.textContent as string);
|
||||||
return (
|
// return (
|
||||||
<>
|
// <>
|
||||||
<label htmlFor="{name}" className="block text-sm font-medium">
|
// <label htmlFor="{name}" className="block text-sm font-medium">
|
||||||
{label}
|
// {label}
|
||||||
</label>
|
// </label>
|
||||||
<div className="border-accent flex w-full rounded-lg border align-middle text-sm shadow-sm">
|
// <div className="border-accent flex w-full rounded-lg border align-middle text-sm shadow-sm">
|
||||||
<div className="flex flex-row space-x-1 pl-2 pt-3">
|
// <div className="flex flex-row space-x-1 pl-2 pt-3">
|
||||||
{tags &&
|
// {tags &&
|
||||||
tags.map((tag) => (
|
// tags.map((tag) => (
|
||||||
<span key={tag} className="badge badge-primary badge-lg py-0.5">
|
// <span key={tag} className="badge badge-primary badge-lg py-0.5">
|
||||||
{tag}
|
// {tag}
|
||||||
<button
|
// <button
|
||||||
onClick={() => removeTag(tag)}
|
// onClick={() => removeTag(tag)}
|
||||||
type="button"
|
// type="button"
|
||||||
className="ml-0.5 inline-flex h-4 w-4 flex-shrink-0 items-center justify-center rounded-full"
|
// className="ml-0.5 inline-flex h-4 w-4 flex-shrink-0 items-center justify-center rounded-full"
|
||||||
>
|
// >
|
||||||
<span className="sr-only">{tag}</span>
|
// <span className="sr-only">{tag}</span>
|
||||||
<svg
|
// <svg
|
||||||
className="h-2 w-2"
|
// className="h-2 w-2"
|
||||||
stroke="currentColor"
|
// stroke="currentColor"
|
||||||
fill="none"
|
// fill="none"
|
||||||
viewBox="0 0 8 8"
|
// viewBox="0 0 8 8"
|
||||||
>
|
// >
|
||||||
<path
|
// <path
|
||||||
strokeLinecap="round"
|
// strokeLinecap="round"
|
||||||
strokeWidth={1.5}
|
// strokeWidth={1.5}
|
||||||
d="M1 1l6 6m0-6L1 7"
|
// d="M1 1l6 6m0-6L1 7"
|
||||||
/>
|
// />
|
||||||
</svg>
|
// </svg>
|
||||||
</button>
|
// </button>
|
||||||
</span>
|
// </span>
|
||||||
))}
|
// ))}
|
||||||
</div>
|
// </div>
|
||||||
<input
|
// <input
|
||||||
value={searchText}
|
// value={searchText}
|
||||||
onKeyDown={handleKeyPress}
|
// onKeyDown={handleKeyPress}
|
||||||
onChange={handleChange}
|
// onChange={handleChange}
|
||||||
placeholder="Start typing and press enter"
|
// placeholder="Start typing and press enter"
|
||||||
className="input w-full focus:outline-none"
|
// className="input w-full focus:outline-none"
|
||||||
/>
|
// />
|
||||||
</div>
|
// </div>
|
||||||
{isSearching && (
|
// {isSearching && (
|
||||||
<div role="status" className="z-50 -mt-3 ml-5">
|
// <div role="status" className="z-50 -mt-3 ml-5">
|
||||||
<svg
|
// <svg
|
||||||
aria-hidden="true"
|
// aria-hidden="true"
|
||||||
className="mr-2 h-4 w-4"
|
// className="mr-2 h-4 w-4"
|
||||||
viewBox="0 0 100 101"
|
// viewBox="0 0 100 101"
|
||||||
fill="none"
|
// fill="none"
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
// xmlns="http://www.w3.org/2000/svg"
|
||||||
>
|
// >
|
||||||
<path
|
// <path
|
||||||
d="M100 50.5908C100 78.2051 77.6142 100.591 50 100.591C22.3858 100.591 0 78.2051 0 50.5908C0 22.9766 22.3858 0.59082 50 0.59082C77.6142 0.59082 100 22.9766 100 50.5908ZM9.08144 50.5908C9.08144 73.1895 27.4013 91.5094 50 91.5094C72.5987 91.5094 90.9186 73.1895 90.9186 50.5908C90.9186 27.9921 72.5987 9.67226 50 9.67226C27.4013 9.67226 9.08144 27.9921 9.08144 50.5908Z"
|
// d="M100 50.5908C100 78.2051 77.6142 100.591 50 100.591C22.3858 100.591 0 78.2051 0 50.5908C0 22.9766 22.3858 0.59082 50 0.59082C77.6142 0.59082 100 22.9766 100 50.5908ZM9.08144 50.5908C9.08144 73.1895 27.4013 91.5094 50 91.5094C72.5987 91.5094 90.9186 73.1895 90.9186 50.5908C90.9186 27.9921 72.5987 9.67226 50 9.67226C27.4013 9.67226 9.08144 27.9921 9.08144 50.5908Z"
|
||||||
fill="currentColor"
|
// fill="currentColor"
|
||||||
/>
|
// />
|
||||||
<path
|
// <path
|
||||||
d="M93.9676 39.0409C96.393 38.4038 97.8624 35.9116 97.0079 33.5539C95.2932 28.8227 92.871 24.3692 89.8167 20.348C85.8452 15.1192 80.8826 10.7238 75.2124 7.41289C69.5422 4.10194 63.2754 1.94025 56.7698 1.05124C51.7666 0.367541 46.6976 0.446843 41.7345 1.27873C39.2613 1.69328 37.813 4.19778 38.4501 6.62326C39.0873 9.04874 41.5694 10.4717 44.0505 10.1071C47.8511 9.54855 51.7191 9.52689 55.5402 10.0491C60.8642 10.7766 65.9928 12.5457 70.6331 15.2552C75.2735 17.9648 79.3347 21.5619 82.5849 25.841C84.9175 28.9121 86.7997 32.2913 88.1811 35.8758C89.083 38.2158 91.5421 39.6781 93.9676 39.0409Z"
|
// d="M93.9676 39.0409C96.393 38.4038 97.8624 35.9116 97.0079 33.5539C95.2932 28.8227 92.871 24.3692 89.8167 20.348C85.8452 15.1192 80.8826 10.7238 75.2124 7.41289C69.5422 4.10194 63.2754 1.94025 56.7698 1.05124C51.7666 0.367541 46.6976 0.446843 41.7345 1.27873C39.2613 1.69328 37.813 4.19778 38.4501 6.62326C39.0873 9.04874 41.5694 10.4717 44.0505 10.1071C47.8511 9.54855 51.7191 9.52689 55.5402 10.0491C60.8642 10.7766 65.9928 12.5457 70.6331 15.2552C75.2735 17.9648 79.3347 21.5619 82.5849 25.841C84.9175 28.9121 86.7997 32.2913 88.1811 35.8758C89.083 38.2158 91.5421 39.6781 93.9676 39.0409Z"
|
||||||
fill="currentFill"
|
// fill="currentFill"
|
||||||
/>
|
// />
|
||||||
</svg>
|
// </svg>
|
||||||
<span className="sr-only">Loading...</span>
|
// <span className="sr-only">Loading...</span>
|
||||||
</div>
|
// </div>
|
||||||
)}
|
// )}
|
||||||
{searchResults && searchResults.length !== 0 && (
|
// {searchResults && searchResults.length !== 0 && (
|
||||||
<div className={`z-50 mb-4 flex space-y-0`}>
|
// <div className={`z-50 mb-4 flex space-y-0`}>
|
||||||
<aside
|
// <aside
|
||||||
aria-labelledby="menu-heading"
|
// aria-labelledby="menu-heading"
|
||||||
className="absolute z-50 -mt-5 flex w-64 flex-col items-start rounded-md border bg-white text-sm shadow-md"
|
// className="absolute z-50 -mt-5 flex w-64 flex-col items-start rounded-md border bg-white text-sm shadow-md"
|
||||||
>
|
// >
|
||||||
<ul className="flex w-full flex-col">
|
// <ul className="flex w-full flex-col">
|
||||||
{searchResults.map((result) => (
|
// {searchResults.map((result) => (
|
||||||
<li
|
// <li
|
||||||
key={result}
|
// key={result}
|
||||||
onClick={doResultClick}
|
// onClick={doResultClick}
|
||||||
className="cursor-pointer space-x-2 px-2 py-1 hover:bg-indigo-500 hover:text-white focus:bg-indigo-500 focus:text-white focus:outline-none"
|
// className="cursor-pointer space-x-2 px-2 py-1 hover:bg-indigo-500 hover:text-white focus:bg-indigo-500 focus:text-white focus:outline-none"
|
||||||
>
|
// >
|
||||||
{result}
|
// {result}
|
||||||
</li>
|
// </li>
|
||||||
))}
|
// ))}
|
||||||
</ul>
|
// </ul>
|
||||||
</aside>
|
// </aside>
|
||||||
</div>
|
// </div>
|
||||||
)}
|
// )}
|
||||||
</>
|
// </>
|
||||||
);
|
// );
|
||||||
};
|
// };
|
||||||
|
|
||||||
export default TaggedInput;
|
// export default TaggedInput;
|
||||||
|
|||||||
@@ -3,13 +3,17 @@ import React, { Fragment } from "react";
|
|||||||
import { Menu, Transition } from "@headlessui/react";
|
import { Menu, Transition } from "@headlessui/react";
|
||||||
import { signOut } from "next-auth/react";
|
import { signOut } from "next-auth/react";
|
||||||
import { logger } from "@/lib/logger";
|
import { logger } from "@/lib/logger";
|
||||||
|
import { type Session } from "next-auth";
|
||||||
|
|
||||||
interface IUserNavDropdownProps {
|
interface IUserNavDropdownProps {
|
||||||
session: any;
|
session: Session | null;
|
||||||
}
|
}
|
||||||
const UserNavDropdown: React.FC<IUserNavDropdownProps> = ({ session }) => {
|
const UserNavDropdown: React.FC<IUserNavDropdownProps> = ({ session }) => {
|
||||||
|
const [profileImage, setProfileImage] = React.useState<string>();
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
logger.debug("UserNavDropdown", "session", session);
|
logger.debug("UserNavDropdown", "session", session);
|
||||||
|
|
||||||
|
setProfileImage(session?.user?.image || "/images/default-profile.jpg");
|
||||||
}, [session]);
|
}, [session]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -20,7 +24,7 @@ const UserNavDropdown: React.FC<IUserNavDropdownProps> = ({ session }) => {
|
|||||||
<span className="sr-only">Open user menu</span>
|
<span className="sr-only">Open user menu</span>
|
||||||
<img
|
<img
|
||||||
className="h-8 w-8 rounded-full"
|
className="h-8 w-8 rounded-full"
|
||||||
src={session?.user?.image as string}
|
src={profileImage}
|
||||||
alt="Profile image"
|
alt="Profile image"
|
||||||
/>
|
/>
|
||||||
</Menu.Button>
|
</Menu.Button>
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ export const authOptions: NextAuthOptions = {
|
|||||||
const s = {
|
const s = {
|
||||||
...session,
|
...session,
|
||||||
user: {
|
user: {
|
||||||
...session.user
|
...session.user,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
return s;
|
return s;
|
||||||
@@ -67,12 +67,7 @@ export const authOptions: NextAuthOptions = {
|
|||||||
if (!user || user.length < 1) {
|
if (!user || user.length < 1) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
if (
|
if (!(await bcrypt.compare(credentials.password, user[0]!.password!))) {
|
||||||
!(await bcrypt.compare(
|
|
||||||
credentials.password,
|
|
||||||
user[0]!.password as string,
|
|
||||||
))
|
|
||||||
) {
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return { id: user[0]!.id, email: user[0]!.email };
|
return { id: user[0]!.id, email: user[0]!.email };
|
||||||
|
|||||||
Reference in New Issue
Block a user