Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: galxe quests UI #643

Merged
merged 8 commits into from
Feb 10, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -228,8 +228,8 @@ const AllFiles = () => {
>
<DropdownMenuTrigger asChild>
<Button
className="absolute -top-12 right-0 flex gap-2 self-end px-6"
size="sm"
className="absolute -top-12 right-0 flex gap-2 self-end px-5"
size="xs"
>
<PlusIcon className="h-4 w-4" /> {t('vectorFs.actions.addNew')}
</Button>
Expand Down
12 changes: 6 additions & 6 deletions apps/shinkai-desktop/src/pages/analytics-settings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { CheckIcon, XIcon } from 'lucide-react';

import { analyticsBulletPoints } from '../constants/analytics';
import { useSettings } from '../store/settings';
import { SubpageLayout } from './layout/simple-layout';
import { SimpleLayout } from './layout/simple-layout';

const AnalyticsSettingsPage = () => {
const { t, Trans } = useTranslation();
Expand All @@ -13,9 +13,9 @@ const AnalyticsSettingsPage = () => {
const acceptAnalytics = useSettings((state) => state.acceptAnalytics);

return (
<SubpageLayout title="Analytics">
<SimpleLayout classname="max-w-xl" title="Analytics">
<div className="flex flex-col justify-between space-y-8">
<p className="font-clash text-xl font-medium">{t('analytics.title')}</p>
<p>{t('analytics.title')}</p>
<div className="mt-10 flex flex-1 flex-col gap-10 text-sm text-gray-50">
<ul className="text-gray-80 space-y-5">
{analyticsBulletPoints().map((item) => (
Expand Down Expand Up @@ -54,7 +54,7 @@ const AnalyticsSettingsPage = () => {
onClick={() => {
denyAnalytics();
}}
size="lg"
size="sm"
>
{t('common.optOut')}
</Button>
Expand All @@ -64,14 +64,14 @@ const AnalyticsSettingsPage = () => {
onClick={() => {
acceptAnalytics();
}}
size="lg"
size="sm"
>
{t('common.optIn')}
</Button>
)}
</div>
</div>
</SubpageLayout>
</SimpleLayout>
);
};

Expand Down
10 changes: 5 additions & 5 deletions apps/shinkai-desktop/src/pages/export-connection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import { useEffect, useState } from 'react';
import { useForm } from 'react-hook-form';

import { useAuth } from '../store/auth';
import { SubpageLayout } from './layout/simple-layout';
import { SimpleLayout, SubpageLayout } from './layout/simple-layout';

export const ExportConnection = () => {
const { t } = useTranslation();
Expand Down Expand Up @@ -75,8 +75,8 @@ export const ExportConnection = () => {
}
};
return (
<SubpageLayout title={t('exportConnection.label')}>
<div className="flex grow flex-col space-y-2">
<SimpleLayout classname="max-w-xl" title={t('exportConnection.label')}>
<div className="flex grow flex-col space-y-4">
<Form {...form}>
<form
className="flex flex-col justify-between space-y-8"
Expand Down Expand Up @@ -106,7 +106,7 @@ export const ExportConnection = () => {
)}
/>
</div>
<Button className="w-full" type="submit">
<Button className="w-full" size="sm" type="submit">
{t('exportConnection.generateFile')}
</Button>
</form>
Expand Down Expand Up @@ -135,6 +135,6 @@ export const ExportConnection = () => {
</div>
)}
</div>
</SubpageLayout>
</SimpleLayout>
);
};
166 changes: 160 additions & 6 deletions apps/shinkai-desktop/src/pages/galxe-validation.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,170 @@
import { useTranslation } from '@shinkai_network/shinkai-i18n';
import { QuestNames } from '@shinkai_network/shinkai-message-ts/api/quests/types';
import { useUpdateQuestsStatus } from '@shinkai_network/shinkai-node-state/v2/mutations/updateQuestsStatus/useUpdateQuestsStatus';
import { useGetQuestsStatus } from '@shinkai_network/shinkai-node-state/v2/queries/getQuestsStatus/useGetQuestsStatus';
import { Button, Skeleton } from '@shinkai_network/shinkai-ui';
import {
Card,
CardDescription,
CardHeader,
CardTitle,
} from '@shinkai_network/shinkai-ui';
import { Check, CircleIcon, RefreshCw } from 'lucide-react';
import { useMemo } from 'react';

import { GalxeSusbcriptions } from './galxe-subscriptions';
import { SubpageLayout } from './layout/simple-layout';
import { useAuth } from '../store/auth';
import { SimpleLayout } from './layout/simple-layout';

const questStatusInfoMap: Record<
QuestNames,
{ name: string; description: string }
> = {
[QuestNames.InstalledApp]: {
name: 'App Installation',
description: 'Install Shinkai Desktop App.',
},
[QuestNames.CreateIdentity]: {
name: 'Create Your Shinkai Identity',
description:
'Get started by creating your unique identity on Shinkai. This is your first step to becoming part of the community.',
},
[QuestNames.DownloadFromStore]: {
name: 'First Store Download',
description:
'Download your first file from the Shinkai store. Explore the available resources and tools.',
},
[QuestNames.ComeBack2Days]: {
name: 'Daily Explorer 2 Days',
description:
'Show your commitment by returning to Shinkai for 2 consecutive days. Build a habit of regular engagement.',
},
[QuestNames.ComeBack4Days]: {
name: 'Daily Explorer 4 Days',
description:
'Show your commitment by returning to Shinkai for 4 consecutive days. Build a habit of regular engagement.',
},
[QuestNames.ComeBack7Days]: {
name: 'Daily Explorer 7 Days',
description:
'Show your commitment by returning to Shinkai for 7 consecutive days. Build a habit of regular engagement.',
},
[QuestNames.CreateTool]: {
name: 'Tool Creator',
description:
'Create and publish your first tool on Shinkai. Share your creativity with the community.',
},
[QuestNames.SubmitAndGetApprovalForTool]: {
name: 'Submit and Get Approval for Tool',
description:
'Submit your tool for review and get it approved by the Shinkai team. Ensure your creation meets our quality standards.',
},
[QuestNames.SubmitAndGetApprovalFor2Tool]: {
name: 'Submit and Get Approval for 2 Tools',
description:
'Submit your tool for review and get it approved by the Shinkai team. Ensure your creation meets our quality standards.',
},
[QuestNames.SubmitAndGetApprovalFor3Tool]: {
name: 'Submit and Get Approval for 3 Tools',
description:
'Submit your tool for review and get it approved by the Shinkai team. Ensure your creation meets our quality standards.',
},
[QuestNames.FeaturedInRanking]: {
name: 'Featured in Ranking',
description: 'Get featured in the Shinkai ranking.',
},
[QuestNames.WriteHonestReview]: {
name: 'Honest Reviewer',
description:
'Write a detailed and honest review about your experience with Shinkai. Help others make informed decisions.',
},
[QuestNames.Write5HonestReview]: {
name: 'Community Contributor',
description:
'Help improve Shinkai by providing constructive feedback. Your input shapes the future of the platform.',
},
[QuestNames.Write10HonestReview]: {
name: 'Community Contributor',
description:
'Help improve Shinkai by providing constructive feedback. Your input shapes the future of the platform.',
},
[QuestNames.UseRAG3Days]: {
name: 'RAG Explorer',
description:
'Experience the power of Retrieval-Augmented Generation (RAG) by using it for 3 days. Discover how it enhances your workflow.',
},
};
export const GalxeValidation = () => {
const { t } = useTranslation();
const auth = useAuth((state) => state.auth);

const { data, isPending, isSuccess } = useGetQuestsStatus({
nodeAddress: auth?.node_address ?? '',
token: auth?.api_v2_key ?? '',
});

const { mutate: updateQuestsStatus, isPending: isQuestsStatusUpdating } =
useUpdateQuestsStatus();

const quests = useMemo(() => {
return data?.data?.quests.map((quest) => ({
key: quest.name,
name: questStatusInfoMap[quest.name].name,
description: questStatusInfoMap[quest.name].description,
progress: quest.status ? 100 : 0,
}));
}, [data]);

return (
<SubpageLayout title={t('galxe.label')}>
<div className="flex grow flex-col space-y-2">
<GalxeSusbcriptions />
<SimpleLayout
classname="max-w-4xl"
headerRightElement={
<Button
disabled={isQuestsStatusUpdating}
isLoading={isQuestsStatusUpdating}
onClick={() =>
updateQuestsStatus({
nodeAddress: auth?.node_address ?? '',
token: auth?.api_v2_key ?? '',
})
}
size="xs"
>
{isQuestsStatusUpdating ? null : <RefreshCw className="h-4 w-4" />}
{isQuestsStatusUpdating ? 'Syncing...' : 'Sync Quests'}
</Button>
}
title={t('galxe.label')}
>
<div className="space-y-4 py-2 pb-10">
{isPending &&
Array.from({ length: 10 }).map((_, index) => (
<Skeleton className="h-20 w-full" key={index} />
))}
{isSuccess &&
quests?.map((quest, index) => (
<Card className="m-0 p-3 px-4" key={index}>
<CardHeader className="flex flex-row items-start gap-2.5 space-y-0 p-0">
<span className="pt-1">
{quest.progress === 100 ? (
<div className="flex size-5 items-center justify-center rounded-full bg-green-600 p-0.5">
<Check className="text-white" />
</div>
) : (
<CircleIcon className="size-5 text-green-400" />
)}
</span>
<div className="m-0 flex flex-1 flex-col gap-1">
<CardTitle className="flex items-center gap-2 p-0 text-base font-semibold">
{quest.name}
</CardTitle>
<CardDescription className="text-gray-80 p-0 text-sm">
{quest.description}
</CardDescription>
</div>
</CardHeader>
</Card>
))}
</div>
</SubpageLayout>
</SimpleLayout>
);
};
7 changes: 3 additions & 4 deletions apps/shinkai-desktop/src/pages/layout/settings-layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -159,12 +159,11 @@ export function MainNav() {
<img alt="galxe icon" className="h-4 w-4" src={galxeIcon} />
</div>
),
disabled: true,
},
].filter(Boolean) as NavigationLink[];

return (
<aside className="flex max-w-[250px] flex-1 shrink-0 flex-col gap-2 overflow-y-auto overflow-x-hidden border-r border-gray-400 px-2 py-6 pt-9">
<aside className="flex max-w-[250px] flex-1 shrink-0 flex-col gap-2 overflow-x-hidden border-r border-gray-400 px-2 py-6 pt-9">
<div className="flex flex-col gap-1.5">
{navigationLinks.map((item) => {
if (item.disabled) {
Expand Down Expand Up @@ -225,9 +224,9 @@ const SettingsLayout = () => {
const auth = useAuth((state) => state.auth);

return (
<div className={cn('flex min-h-screen flex-1', !!auth && '')}>
<div className={cn('flex h-screen overflow-hidden', !!auth && '')}>
<MainNav />
<div className={cn('flex-1 overflow-hidden')}>
<div className={cn('flex-1 overflow-y-auto')}>
<Outlet />
</div>
</div>
Expand Down
2 changes: 1 addition & 1 deletion apps/shinkai-desktop/src/pages/prompt-library.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ export const PromptLibrary = () => {
);
}}
>
<Button rounded="lg" size="xs">
<Button size="xs">
<PlusIcon className="h-5 w-5" />
New Prompt
</Button>
Expand Down
6 changes: 3 additions & 3 deletions apps/shinkai-desktop/src/pages/public-keys.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import {
import { useForm } from 'react-hook-form';

import { useAuth } from '../store/auth';
import { SubpageLayout } from './layout/simple-layout';
import { SimpleLayout } from './layout/simple-layout';

export const PublicKeys = () => {
const { t } = useTranslation();
Expand All @@ -32,7 +32,7 @@ export const PublicKeys = () => {
});

return (
<SubpageLayout title={t('settings.publicKeys.label')}>
<SimpleLayout classname="max-w-xl" title={t('settings.publicKeys.label')}>
<div className="flex grow flex-col space-y-2">
<Form {...form}>
<form className="flex flex-col justify-between space-y-8">
Expand Down Expand Up @@ -214,6 +214,6 @@ export const PublicKeys = () => {
</form>
</Form>
</div>
</SubpageLayout>
</SimpleLayout>
);
};
12 changes: 6 additions & 6 deletions apps/shinkai-desktop/src/pages/settings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,10 @@ import { useForm, useWatch } from 'react-hook-form';
import { toast } from 'sonner';
import { z } from 'zod';

import { useShinkaiNodeGetOllamaVersionQuery, useShinkaiNodeRespawnMutation } from '../lib/shinkai-node-manager/shinkai-node-manager-client';
import {
useShinkaiNodeGetOllamaVersionQuery,
useShinkaiNodeRespawnMutation,
} from '../lib/shinkai-node-manager/shinkai-node-manager-client';
import { isHostingShinkaiNode } from '../lib/shinkai-node-manager/shinkai-node-manager-windows-utils';
import { SetupData, useAuth } from '../store/auth';
import { useSettings } from '../store/settings';
Expand Down Expand Up @@ -197,7 +200,7 @@ const SettingsPage = () => {
auth?.shinkai_identity ?? '',
);
return (
<SimpleLayout classname="max-w-lg" title={t('settings.layout.general')}>
<SimpleLayout classname="max-w-xl" title={t('settings.layout.general')}>
<p className="mb-3">{t('settings.description')}</p>
<div className="flex flex-col space-y-8 pr-2.5">
<div className="flex flex-col space-y-8">
Expand Down Expand Up @@ -409,10 +412,7 @@ const SettingsPage = () => {
disabled
name="ollamaVersion"
render={({ field }) => (
<TextField
field={field}
label={t('ollama.version')}
/>
<TextField field={field} label={t('ollama.version')} />
)}
/>
<FormField
Expand Down
Loading