Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
65 commits
Select commit Hold shift + click to select a range
89e820e
feat: aplly responsive on the home page
yasersharifi Feb 3, 2025
0e43c67
fix: code format
yasersharifi Feb 5, 2025
3a33ee4
feat: apply the responsive on the availibility page
yasersharifi Feb 9, 2025
0927738
feat: responsive - navbar and add sidebar
yasersharifi Feb 9, 2025
64d9f88
feat: responsive - navbar and add sidebar
yasersharifi Feb 9, 2025
e80d02e
Merge branch 'main' into feat/responsive
yasersharifi Feb 9, 2025
33582f6
feat: new responsive code on the home page
yasersharifi Feb 10, 2025
6a3d07c
feat: responsive of services card
yasersharifi Feb 10, 2025
ed6fb9f
Merge branch 'feat/responsive' of https://github.com/yasersharifi/jel…
yasersharifi Feb 10, 2025
0b82ba1
feat: private pages responsive codes
yasersharifi Feb 10, 2025
cfcdad5
feat: private pages responsive codes
yasersharifi Feb 10, 2025
4c4f5f1
feat: implement sell relay page
yasersharifi Feb 13, 2025
e459da3
fix: format
yasersharifi Feb 13, 2025
76c0249
fix: comment un used codes
yasersharifi Feb 13, 2025
dcdbe6d
feat: define another layout and sidebar for dashboard
yasersharifi Feb 17, 2025
ff7a679
feat: implement dashboard sidebar
yasersharifi Feb 17, 2025
655b3c0
fix: change for test
yasersharifi Feb 17, 2025
93cdc9e
fix: for test
yasersharifi Feb 17, 2025
3ef1c69
fix: apply last modified
yasersharifi Feb 24, 2025
2f2e9b7
fix: apply last modified
yasersharifi Feb 24, 2025
195d456
fix: apply last modified
yasersharifi Feb 24, 2025
9bc5302
Merge pull request #1 from yasersharifi/bugfix/fix-last-modified
yasersharifi Feb 24, 2025
c62f129
fix: create new pr
yasersharifi Feb 24, 2025
751de05
Merge branch 'main' into fix/conflicts
yasersharifi Feb 24, 2025
34142f9
Update index.html
yasersharifi Feb 24, 2025
e95ff4d
feat: change favicon
yasersharifi Feb 26, 2025
8422933
Merge branch 'fix/conflicts' of https://github.com/yasersharifi/jelly…
yasersharifi Feb 26, 2025
aaed8f3
fix: change favicon and some issue
yasersharifi Feb 26, 2025
0b30f51
Merge branch 'main' into fix/conflicts
yasersharifi Feb 26, 2025
26cef0d
fix: bug of items location and maintanance page
yasersharifi Feb 26, 2025
ab664f8
fix: format
yasersharifi Feb 26, 2025
a0d7d37
Merge branch 'fix/conflicts' of https://github.com/yasersharifi/jelly…
yasersharifi Feb 26, 2025
0b46b13
feat: implement login
yasersharifi Mar 10, 2025
649d213
feat: implement login
yasersharifi Mar 10, 2025
fa8e128
Merge branch 'main' into feat/login-by-nostr-hooks
yasersharifi Mar 10, 2025
e6e50c4
feat: connect to the subscription api
yasersharifi Mar 12, 2025
fbc9581
t Merge branch 'feat/login-by-nostr-hooks' of https://github.com/yase…
yasersharifi Mar 12, 2025
80d9a1d
feat: checkout subscription
yasersharifi Mar 12, 2025
5988a9a
fix: remove un used imports
yasersharifi Mar 12, 2025
5eb126b
fix: solved
yasersharifi Mar 15, 2025
d3659c6
fix: solved
yasersharifi Mar 15, 2025
b6d019e
Merge branch 'main' into fix/ui-last-issues
yasersharifi Mar 15, 2025
b2c84e1
feat: added the join to raley button
yasersharifi Mar 16, 2025
4045027
Merge branch 'fix/ui-last-issues' of https://github.com/yasersharifi/…
yasersharifi Mar 16, 2025
9a9ae99
feat: define env variable
yasersharifi Mar 16, 2025
6263faf
fix: alert data
yasersharifi Mar 16, 2025
812aa43
Merge branch 'main' into fix/ui-last-issues
yasersharifi Mar 16, 2025
f77c09c
feat: connect to profile api
yasersharifi Apr 6, 2025
9fba75f
feat: added env example
yasersharifi Apr 6, 2025
f3b3bc9
feat: implement profile data and set avatar placeholder image
yasersharifi Apr 12, 2025
a5424a9
feat: implement remaning api
yasersharifi Apr 14, 2025
f2108c9
Merge branch 'main' into main
yasersharifi Apr 14, 2025
6ccfa2f
fix: redired and auth provider
yasersharifi Apr 15, 2025
6637b60
fix: remove un use imports
yasersharifi Apr 15, 2025
165c6f3
fix: remove un use imports
yasersharifi Apr 15, 2025
fb961b1
Merge branch 'main' of https://github.com/yasersharifi/jellyfish into…
yasersharifi Apr 15, 2025
e74b7d0
fix: conflicts
yasersharifi Apr 15, 2025
724b016
fix: change file name
yasersharifi Apr 15, 2025
8d983e8
fix: change file name
yasersharifi Apr 15, 2025
8605fb4
fix: change file name
yasersharifi Apr 15, 2025
9b68910
Merge branch 'main' into feat/connect-to-remaining
yasersharifi Apr 15, 2025
bb6b793
fix: change file name
yasersharifi Apr 15, 2025
9bb09a3
Merge branch 'feat/connect-to-remaining' of https://github.com/yasers…
yasersharifi Apr 15, 2025
856231e
feat: changes
yasersharifi Apr 15, 2025
7fc523e
feat: changes
yasersharifi Apr 15, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion _config.yml
Original file line number Diff line number Diff line change
@@ -1 +1 @@
include: [".well-known"]
include: [".well-known"]
2 changes: 1 addition & 1 deletion index.html
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@
content="index, follow, max-video-preview:max-video-preview:-1, max-image-preview:max-image-preview:large, max-snippet:max-snippet:-1"
/>
<title>JellyFish</title>
<meta http-equiv="X-Frame-Options" content="SAMEORIGIN">
<meta http-equiv="X-Frame-Options" content="SAMEORIGIN" />
<link
href="https://fonts.googleapis.com/css2?family=Roboto-Mono:wght@400;500;700&display=swap"
rel="stylesheet"
Expand Down
7 changes: 7 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
"axios": "^1.8.2",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"dayjs": "^1.11.13",
"embla-carousel-react": "^8.5.2",
"framer-motion": "^11.15.0",
"js-cookie": "^3.0.5",
Expand Down
Binary file removed public/images/avatar-paceholder.png
Binary file not shown.
Binary file added public/images/avatar-paceholder1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
9 changes: 6 additions & 3 deletions src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
import { RouterProvider } from "react-router-dom";
import { router } from "./routes";
import ReactQueryProvider from "./providers/ReactQueryProviders";
import AuthProvider from "./providers/AuthProvider";

function App() {
return (
<ReactQueryProvider>
<RouterProvider router={router} />
</ReactQueryProvider>
<AuthProvider>
<ReactQueryProvider>
<RouterProvider router={router} />
</ReactQueryProvider>
</AuthProvider>
);
}

Expand Down
8 changes: 8 additions & 0 deletions src/components/common/ProtectedRoute.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { useAuth } from "@/providers/AuthProvider";
import { Navigate, Outlet } from "react-router-dom";

export function ProtectedRoute() {
const { isAuthenticated } = useAuth();

return isAuthenticated ? <Outlet /> : <Navigate to="/" />;
}
4 changes: 2 additions & 2 deletions src/components/pages/Dashboard/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import { useEffect, useState } from "react";
import { useQuery } from "@tanstack/react-query";
import { Skeleton } from "@/components/ui/skeleton";
import { getRemaningFormattedTime } from "@/utils/dayjs";

const Dashboard = () => {
const { profile, pubKey } = useProfileStore(state => state);
Expand All @@ -31,7 +32,7 @@
});

useEffect(() => {
getRemainingQuery.refetch();

Check warning on line 35 in src/components/pages/Dashboard/index.tsx

View workflow job for this annotation

GitHub Actions / Linting

React Hook useEffect has a missing dependency: 'getRemainingQuery'. Either include it or remove the dependency array
}, [token]);

useEffect(() => {
Expand Down Expand Up @@ -70,8 +71,7 @@
) : (
<>
<p className="flex-1 text-[#ACCDF2] font-roboto-mono text-2xl sm:text-3xl md:text-4xl lg:text-[36px]">
{remaring ?? 0} day{remaring > 1 ? "s" : ""}{" "}
remain until the subscription is finished
{getRemaningFormattedTime(remaring)}
</p>

<Link
Expand Down
2 changes: 1 addition & 1 deletion src/components/pages/Home/HeroSection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,4 @@
);
};

export default HeroSection;
export default HeroSection;

Check warning on line 46 in src/components/pages/Home/HeroSection.tsx

View workflow job for this annotation

GitHub Actions / Linting

Insert `⏎`
2 changes: 1 addition & 1 deletion src/data/alert.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@
linkText: "",
link: "",
show: false,
};
};

Check warning on line 7 in src/data/alert.ts

View workflow job for this annotation

GitHub Actions / Linting

Insert `⏎`
21 changes: 18 additions & 3 deletions src/layout/dashboard-layout/DashboardSidebar.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
import { Button } from "@/components/ui/Button";
import SidebarItem from "./SidebarItem";
import { ChevronLeft, ChevronRight, HomeIcon } from "lucide-react";
import { ChevronLeft, ChevronRight, HomeIcon, LogOutIcon } from "lucide-react";
import { JellyFishIcon } from "@/assets/icons/nav/JellyFishIcon";
import { Link } from "react-router-dom";
import { useDashboardSidebar } from "./DashboardSidebarContext";
import AuthenticationAction from "./../layout/AuthenticationActions";
import { useAuth } from "@/providers/AuthProvider";

const DashboardSidebar = () => {
const { isCollapsed, toggleCollapse } = useDashboardSidebar();
const { logout } = useAuth();

return (
<>
Expand Down Expand Up @@ -54,10 +56,23 @@ const DashboardSidebar = () => {
</div>

{/* Sidebar Footer */}
<div className="p-4 border-t border-gray-700 md:hidden">
<div className="flex items-center gap-2 cursor-pointer">
<div className="p-4 border-t border-gray-700 ">
<div className="flex items-center gap-2 mb-4 cursor-pointer md:hidden">
<AuthenticationAction isCollapsed={isCollapsed} />
</div>

<Button
className="w-full text-red-700 "
onClick={() => {
if (logout) logout();
}}
>
<SidebarItem
icon={<LogOutIcon className="w-5 h-5 " />}
label="Log Out"
isCollapsed={isCollapsed}
/>
</Button>
</div>
</div>
</>
Expand Down
33 changes: 22 additions & 11 deletions src/layout/layout/AuthenticationActions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import useProfileStore from "@/stores/profile-store";
import { useQuery } from "@tanstack/react-query";

import { useNip98 } from "nostr-hooks";
import { useNavigate } from "react-router-dom";

type Props = {
isCollapsed?: boolean;
Expand All @@ -19,12 +20,13 @@ type TProfileGetOutput = {
};

const AuthenticationButton: React.FC<Props> = ({ isCollapsed }) => {
const navigate = useNavigate();
const { loginWithExtension } = useLogin();
const { activeUser } = useActiveUser();
const { getToken } = useNip98();

// Get and Set pubKey from profile store
const { pubKey, profile, setToken, setPubKey, setProfile } =
const { pubKey, profile, setToken, setPubKey, setProfile, setIsLoggedIn } =
useProfileStore(state => state);

// Get Profile Api
Expand Down Expand Up @@ -74,6 +76,10 @@ const AuthenticationButton: React.FC<Props> = ({ isCollapsed }) => {
}
};

const handleNavigateToDashboard = () => {
navigate("/dashboard");
};

useEffect(() => {
if (pubKey) {
getProfileQuery.refetch();
Expand All @@ -87,12 +93,6 @@ const AuthenticationButton: React.FC<Props> = ({ isCollapsed }) => {
}, [getProfileQuery.isFetched]);

useEffect(() => {
console.log(
"LOGIN USER",
activeUser,
pubKey,
activeUser?.pubkey && activeUser?.pubkey !== pubKey,
);
if (activeUser?.pubkey && activeUser?.pubkey !== pubKey) {
setPubKey(activeUser?.pubkey);
getToken({
Expand All @@ -103,6 +103,8 @@ const AuthenticationButton: React.FC<Props> = ({ isCollapsed }) => {
})
.then(token => {
setToken(token);
setIsLoggedIn(true);
handleNavigateToDashboard();
})
.catch(err => {
console.error("Error get token: ", err);
Expand All @@ -123,26 +125,35 @@ const AuthenticationButton: React.FC<Props> = ({ isCollapsed }) => {
return (
<>
{isCollapsed ? (
<Avatar className="w-8 h-8" title="John Doe">
<Avatar
className="w-8 h-8"
title={profile?.display_name ?? pubKey?.substring(0, 6)}
onClick={() => handleNavigateToDashboard()}
>
<AvatarImage
src={
profile?.picture ??
"/images/avatar-paceholder.png"
"/images/avatar-paceholder1.png"
}
alt="User Avatar"
/>
<AvatarFallback>User name</AvatarFallback>
<AvatarFallback>
{" "}
{profile?.display_name ?? pubKey?.substring(0, 6)}
</AvatarFallback>
</Avatar>
) : (
<Button
variant="outline"
className="justify-start min-w-[100px] w-full h-12 rounded-full"
onClick={() => handleNavigateToDashboard()}
title={profile?.display_name ?? pubKey?.substring(0, 6)}
>
<Avatar className="w-8 h-8 shrink-0">
<AvatarImage
src={
profile?.picture ??
"/images/avatar-paceholder.png"
"/images/avatar-paceholder1.png"
}
alt="User Avatar"
/>
Expand Down
33 changes: 33 additions & 0 deletions src/providers/AuthProvider.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import useProfileStore from "@/stores/profile-store";
import React, { createContext, PropsWithChildren, useContext } from "react";

const AuthContext = createContext<{
isAuthenticated: boolean;
logout?: () => void;
}>({ isAuthenticated: false });

type Props = PropsWithChildren;

export function useAuth() {
return useContext(AuthContext);
}

const AuthProvider: React.FC<Props> = ({ children }) => {
const { isLoggedIn, setToken, setPubKey, setProfile, setIsLoggedIn } =
useProfileStore(state => state);

const logout = () => {
setPubKey(undefined);
setProfile(undefined);
setToken(undefined);
setIsLoggedIn(false);
};

return (
<AuthContext.Provider value={{ isAuthenticated: !!isLoggedIn, logout }}>
{children}
</AuthContext.Provider>
);
};

export default AuthProvider;
22 changes: 14 additions & 8 deletions src/routes/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import SellRelay from "@/components/pages/SellRelay";
import NpubEditForm from "@/components/pages/Dashboard/Edit";
import DashboardLayout from "@/layout/dashboard-layout";
import Maintanance from "@/components/pages/Maintanance";
import { ProtectedRoute } from "@/components/common/ProtectedRoute";

export const router = createBrowserRouter([
{
Expand Down Expand Up @@ -43,16 +44,21 @@ export const router = createBrowserRouter([
],
},
{
path: "dashboard",
element: <DashboardLayout />,
element: <ProtectedRoute />,
children: [
{
path: "",
element: <Dashboard />,
},
{
path: "edit/:id",
element: <NpubEditForm />,
path: "dashboard",
element: <DashboardLayout />,
children: [
{
path: "",
element: <Dashboard />,
},
{
path: "edit/:id",
element: <NpubEditForm />,
},
],
},
],
},
Expand Down
9 changes: 6 additions & 3 deletions src/stores/profile-store.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,15 @@ type TProfile = {

type State = {
pubKey?: string;
isLoggedIn?: boolean;
profile?: TProfile;
token?: string;
};

type Actions = {
setPubKey: (pubKey: string) => void;
setProfile: (picture: TProfile) => void;
setPubKey: (pubKey?: string) => void;
setProfile: (picture?: TProfile) => void;
setIsLoggedIn: (isLoggedIn?: boolean) => void;
setToken: (token?: string) => void;
};

Expand All @@ -23,8 +25,9 @@ type Store = State & Actions;
const useProfileStore = create(
persist<Store>(
set => ({
setPubKey: (pubKey: string) => set({ pubKey }),
setPubKey: (pubKey?: string) => set({ pubKey }),
setProfile: (profile?: TProfile) => set({ profile }),
setIsLoggedIn: (isLoggedIn?: boolean) => set({ isLoggedIn }),
setToken: (token?: string) => set({ token }),
}),
{
Expand Down
28 changes: 28 additions & 0 deletions src/utils/dayjs.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import dayjs from "dayjs";
import duration from "dayjs/plugin/duration";

dayjs.extend(duration);

const getRemaningFormattedTime = (timestamp: number) => {
if (timestamp <= 0) return "The subscription has ended.";

const now = dayjs();
const targetDate = dayjs(timestamp);

if (targetDate.isBefore(now) || targetDate.isSame(now))
return "The subscription has ended.";

const diff = dayjs.duration(targetDate.diff(now));

const years = diff.years();
const months = diff.months();
const days = diff.days();
const hours = diff.hours();
const minutes = diff.minutes();

const remaningTime = `${years} year${years > 1 ? "s" : ""} ${months} month${months > 1 ? "s" : ""} ${days} day${days > 1 ? "s" : ""} ${hours} hour${hours > 1 ? "s" : ""} ${minutes} min${minutes > 1 ? "s" : ""}`;

return `${remaningTime} remain until the subscription is finished`;
};

export { getRemaningFormattedTime };
Loading