feat: add authentication

This commit is contained in:
2024-03-16 07:52:42 +07:00
parent ed5c715429
commit 1e8252d9da
28 changed files with 8519 additions and 138 deletions
+75
View File
@@ -0,0 +1,75 @@
import { cn } from "@/lib/utils";
import { ComponentPropsWithClassName } from "@/types/components";
import { View } from "react-native";
import Text from "./Text";
import { VariantProps, cva } from "class-variance-authority";
const alertVariants = cva(
"rounded-md bg-gray-100 border border-gray-300 px-3 py-2 w-full",
{
variants: {
variant: {
default: "bg-gray-100 border-gray-300",
success: "bg-green-100 border-green-300",
error: "bg-red-100 border-red-300",
warning: "bg-yellow-100 border-yellow-300",
info: "bg-blue-100 border-blue-300",
},
},
defaultVariants: {
variant: "default",
},
}
);
const alertTextVariants = cva("text-sm", {
variants: {
variant: {
default: "text-gray-700",
success: "text-green-700",
error: "text-red-700",
warning: "text-yellow-700",
info: "text-blue-700",
},
},
defaultVariants: {
variant: "default",
},
});
type Props = Omit<ComponentPropsWithClassName<typeof View>, "children"> &
VariantProps<typeof alertVariants> & {
children?: string;
textClassName?: string;
error?: unknown;
};
const Alert = ({
className,
textClassName,
children,
variant: variantName,
error,
}: Props) => {
let variant = variantName;
let message = children;
if (error) {
variant = "error";
message = (error as any)?.message || "An error occured!";
}
if (!message) {
return null;
}
return (
<View style={cn(alertVariants({ variant }), className)}>
<Text className={[alertTextVariants({ variant }), textClassName]}>
{message}
</Text>
</View>
);
};
export default Alert;
+6 -2
View File
@@ -54,12 +54,13 @@ const buttonTextVariants = cva("text-center font-medium", {
});
interface ButtonProps
extends React.ComponentPropsWithoutRef<typeof Pressable>,
extends Omit<React.ComponentPropsWithoutRef<typeof Pressable>, "children">,
VariantProps<typeof buttonVariants> {
label?: string;
labelClasses?: string;
className?: string;
icon?: React.ReactNode;
children?: string;
}
function Button({
label,
@@ -68,6 +69,7 @@ function Button({
variant,
size,
icon,
children,
...props
}: ButtonProps) {
const textStyles = cn(
@@ -86,7 +88,9 @@ function Button({
>
{icon ? <Slot.View style={textStyles}>{icon}</Slot.View> : null}
{label ? <Text style={textStyles}>{label}</Text> : null}
{label || children ? (
<Text style={textStyles}>{label || children}</Text>
) : null}
</Pressable>
);
}
+32
View File
@@ -0,0 +1,32 @@
import { ScrollView, View } from "react-native";
import React from "react";
import { cn } from "@/lib/utils";
type ContainerProps = {
className?: string;
children?: React.ReactNode;
scrollable?: boolean;
};
const Container = ({
className,
children,
scrollable = false,
}: ContainerProps) => {
const style = cn("mx-auto w-full max-w-xl", className);
if (scrollable) {
return (
<ScrollView
contentContainerStyle={style}
showsVerticalScrollIndicator={false}
>
{children}
</ScrollView>
);
}
return <View style={style}>{children}</View>;
};
export default Container;
+65
View File
@@ -0,0 +1,65 @@
import React from "react";
import { TextInput } from "react-native";
import { ComponentPropsWithClassName } from "@/types/components";
import { cn } from "@/lib/utils";
import Box from "./Box";
import Text from "./Text";
import { Controller, FieldValues, Path, UseFormReturn } from "react-hook-form";
type BaseInputProps = ComponentPropsWithClassName<typeof TextInput> & {
label?: string;
inputClassName?: string;
error?: string;
};
type InputProps<T extends FieldValues> = BaseInputProps & {
form?: UseFormReturn<T>;
path?: Path<T>;
};
const BaseInput = ({
className,
inputClassName,
label,
error,
...props
}: BaseInputProps) => {
return (
<Box className={className}>
{label ? <Text className="text-sm mb-1">{label}</Text> : null}
<TextInput
style={cn(
"border border-gray-300 rounded-lg px-3 h-10 w-full",
inputClassName
)}
{...props}
/>
{error ? (
<Text className="text-red-500 text-sm mt-1">{error}</Text>
) : null}
</Box>
);
};
const Input = <T extends FieldValues>({
form,
path,
...props
}: InputProps<T>) => {
if (form && path) {
return (
<Controller
control={form.control}
name={path}
render={({ field: { ref, ...field }, fieldState }) => (
<BaseInput {...props} {...field} error={fieldState.error?.message} />
)}
/>
);
}
return <BaseInput {...props} />;
};
export default Input;