diff --git a/src/components/pages/Dashboard/Edit/index.tsx b/src/components/pages/Dashboard/Edit/index.tsx new file mode 100644 index 0000000..df9a9d8 --- /dev/null +++ b/src/components/pages/Dashboard/Edit/index.tsx @@ -0,0 +1,66 @@ +import { Button } from "@/components/ui/Button"; +import { Textfield } from "@/components/ui/Textfield"; +import useFetch from "@/hooks/useFetch"; +import { dashboardService } from "@/services/api/dashboard.service"; +import { useParams } from "react-router-dom"; +import useEdit from "./useEdit"; +import { useCallback, useEffect } from "react"; +import { MyNpubsCardProps } from "../MyNpubsCard"; +const sampleData: MyNpubsCardProps = { + username: "Ehsan@nosrt.eco", + npub: "npub1h5h535j4809uf23j8y9t4n23090", + id: "1", +}; + +const NpubEditForm = () => { + const { id } = useParams(); + + const fetchUsernames = useCallback(() => { + return dashboardService + .getMyUsername(id as string) + .then(res => res.data.data); + }, []); + const { data, loading } = useFetch(fetchUsernames); + + const { handleSubmit, register, errors, setValue } = useEdit(); + useEffect(() => { + if (data) { + setValue("npub", data?.npub); + } + }, []); + + if (loading) return "Loading..."; + + return ( +
+
+
+

+ Edit your Nip-05 records +

+

+ {sampleData?.username} +

+
+ +
+
+
+ + {errors.npub && ( +

+ {errors.npub.message} +

+ )} +
+
+
+ ); +}; + +export default NpubEditForm; diff --git a/src/components/pages/Dashboard/Edit/useEdit.ts b/src/components/pages/Dashboard/Edit/useEdit.ts new file mode 100644 index 0000000..3a7bcf7 --- /dev/null +++ b/src/components/pages/Dashboard/Edit/useEdit.ts @@ -0,0 +1,51 @@ +import * as yup from "yup"; +import { useForm } from "react-hook-form"; +import { yupResolver } from "@hookform/resolvers/yup"; +import { useState } from "react"; +import { useNavigate, useParams } from "react-router-dom"; +import { dashboardService } from "@/services/api/dashboard.service"; + +const schema = yup + .object({ + npub: yup.string().required("npub is required"), + }) + .required(); + +const useEdit = () => { + const navigate = useNavigate(); + const [loading, setLoading] = useState(false); + const { id } = useParams(); + + const { + register, + handleSubmit, + setValue, + formState: { errors }, + } = useForm({ + resolver: yupResolver(schema), + }); + + const onSubmit = async (data: { npub: string }) => { + try { + setLoading(true); + await dashboardService.editMyUsernames(id as string, data); + navigate(""); + } catch (error) { + console.log(error); + navigate(""); + } finally { + setLoading(false); + } + }; + + return { + setValue, + register, + onSubmit, + errors, + handleSubmit: handleSubmit(onSubmit), + loading, + }; +}; + +export default useEdit; diff --git a/src/components/pages/Dashboard/MyNpubsCard.tsx b/src/components/pages/Dashboard/MyNpubsCard.tsx new file mode 100644 index 0000000..5efbaab --- /dev/null +++ b/src/components/pages/Dashboard/MyNpubsCard.tsx @@ -0,0 +1,65 @@ +import { buttonVariants } from "@/components/ui/Button/buttonVariants"; +import Tag from "@/components/ui/Tag"; +import { cn } from "@/lib/utils"; +import { Link } from "react-router-dom"; + +export type MyNpubsCardProps = { + id: string; + username: string; + npub: string; + // items: { name: string; value: string }[]; +}; + +const MyNpubsCard = ({ username, id, npub }: MyNpubsCardProps) => { + return ( +
+
+
+

+ {username} +

+ + {" "} + Edit + +
+
+
+ npub +

+ {npub} +

+
+ {/* {items.map((item, key) => ( +
+ {item.name} +

+ {item.value} +

+
+ ))} */} +
+
+
+ ); +}; + +export default MyNpubsCard; diff --git a/src/components/pages/Dashboard/index.tsx b/src/components/pages/Dashboard/index.tsx new file mode 100644 index 0000000..c8633e3 --- /dev/null +++ b/src/components/pages/Dashboard/index.tsx @@ -0,0 +1,66 @@ +import { dashboardService } from "@/services/api/dashboard.service"; +import MyNpubsCard, { MyNpubsCardProps } from "./MyNpubsCard"; +import { Skeleton } from "@/components/ui/skeleton"; +import AnimateWrapper from "@/components/AnimateWrapper"; +import useFetch from "@/hooks/useFetch"; +import { useCallback } from "react"; +const sampleData: MyNpubsCardProps[] = [ + { + username: "Ehsan@nosrt.eco", + npub: "npub1h5h535j4809uf23j8y9t4n23090", + id: "1", + // items: [ + // { + // name: "npub", + // value: "npub1h5h535j4809uf23j8y9t4n23090", + // }, + // ], + }, +]; + +const Dashboard = () => { + const fetchUsernames = useCallback(() => { + return dashboardService.getMyUsernames().then(res => res.data.data); + }, []); + const { data, loading, error } = useFetch(fetchUsernames); + + if (error) + return ( +

+ Error: {error.message} +

+ ); + + return ( +
+

+ Hi, welcome + {/* TODO: add username */} +

+
+ {loading ? ( + <> + + + + ) : data && data.length > 0 ? ( + data?.map((card, key) => ( + + + + )) + ) : sampleData ? ( + sampleData?.map((card, key) => ( + + + + )) + ) : ( + "Not any username" + )} +
+
+ ); +}; + +export default Dashboard; diff --git a/src/components/pages/SetUserName/NameSuggestions.tsx b/src/components/pages/SetUserName/NameSuggestions.tsx index b4921b9..2ccca88 100644 --- a/src/components/pages/SetUserName/NameSuggestions.tsx +++ b/src/components/pages/SetUserName/NameSuggestions.tsx @@ -1,25 +1,14 @@ import { Skeleton } from "@/components/ui/skeleton"; import Tag from "@/components/ui/Tag"; +import useFetch from "@/hooks/useFetch"; import { usernameService } from "@/services/api/username.service"; -import { useEffect, useState } from "react"; const NameSuggestions = () => { - const [data, setData] = useState(); - const [loading, setLoading] = useState(false); - useEffect(() => { - const fetch = async () => { - try { - setLoading(true); - const res = await usernameService.getSuggestions(); - setData(res.data.data); - } catch (error) { - console.log(error); - } finally { - setLoading(false); - } - }; - fetch(); - }, []); + const fetchUsernames = () => + usernameService.getSuggestions().then(res => res.data.data); + + const { data, loading } = useFetch(fetchUsernames); + return (

diff --git a/src/hooks/useFetch.ts b/src/hooks/useFetch.ts new file mode 100644 index 0000000..d80a003 --- /dev/null +++ b/src/hooks/useFetch.ts @@ -0,0 +1,39 @@ +import { useState, useEffect, useCallback } from "react"; + +type UseFetchState = { + data: T | null; + loading: boolean; + error: Error | null; +}; + +function useFetch(fetchFunction: () => Promise) { + const [state, setState] = useState>({ + data: null, + loading: false, + error: null, + }); + + const [trigger, setTrigger] = useState(0); + + const fetchData = useCallback(async () => { + setState({ data: null, loading: true, error: null }); + try { + const data = await fetchFunction(); + setState({ data, loading: false, error: null }); + } catch (error) { + setState({ data: null, loading: false, error: error as Error }); + } + }, [fetchFunction]); + + useEffect(() => { + fetchData(); + }, [fetchData, trigger]); + + const refetch = useCallback(() => { + setTrigger(prev => prev + 1); + }, []); + + return { ...state, refetch }; +} + +export default useFetch; diff --git a/src/routes/index.tsx b/src/routes/index.tsx index 10fd0a4..ee22d17 100644 --- a/src/routes/index.tsx +++ b/src/routes/index.tsx @@ -5,6 +5,8 @@ import { HomePage, NotFoundPage } from "@/components/pages"; import AvailabilityPage from "@/components/pages/Availability"; import SetUserName from "@/components/pages/SetUserName"; import PaymentResult from "@/components/pages/PaymentResult"; +import Dashboard from "@/components/pages/Dashboard"; +import NpubEditForm from "@/components/pages/Dashboard/Edit"; export const router = createBrowserRouter([ { @@ -31,6 +33,15 @@ export const router = createBrowserRouter([ path: "*", element: , }, + + { + path: "/dashboard", + element: , + }, + { + path: "/dashboard/edit/:id", + element: , + }, ], }, ]); diff --git a/src/services/api/dashboard.service.ts b/src/services/api/dashboard.service.ts new file mode 100644 index 0000000..60b34c6 --- /dev/null +++ b/src/services/api/dashboard.service.ts @@ -0,0 +1,12 @@ +import { MyNpubsCardProps } from "@/components/pages/Dashboard/MyNpubsCard"; +import { mainApi } from "../../config/axios.config"; +import { ApiResponse } from "../../types/api.types"; + +export const dashboardService = { + getMyUsernames: () => + mainApi.get>(`/usernames`), + getMyUsername: (id: string) => + mainApi.get>(`/usernames/username/${id}`), + editMyUsernames: (id: string, data: { npub: string }) => + mainApi.put>(`/usernames/username/${id}`, data), +};