Skip to content
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
13 changes: 11 additions & 2 deletions app/[locale]/(user)/components/Content.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { SearchInput, Spinner, Tag, Text } from 'opub-ui';
import { GraphQL } from '@/lib/api';
import { cn } from '@/lib/utils';
import Styles from '../page.module.scss';
import { useTourTrigger } from '@/hooks/use-tour-trigger';

const statsInfo: any = graphql(`
query StatsList {
Expand All @@ -34,6 +35,10 @@ const statsInfo: any = graphql(`

export const Content = () => {
const router = useRouter();

// Enable tour for first-time users
useTourTrigger(true, 1500);

const Stats: { data: any; isLoading: any } = useQuery([`statsDetails`], () =>
GraphQL(statsInfo, {}, [])
);
Expand Down Expand Up @@ -104,7 +109,11 @@ export const Content = () => {
) : (
<div className="flex flex-wrap items-center gap-4 md:gap-0 lg:gap-0 ">
{Metrics.map((item, index) => (
<Link key={`${item.label}_${index}`} href={item.link}>
<Link
key={`${item.label}_${index}`}
href={item.link}
data-tour={index === 0 ? 'datasets-link' : index === 1 ? 'usecases-link' : index === 2 ? 'publishers-link' : undefined}
>
<div
key={index}
className="flex flex-col border-x-[1px] border-solid border-tertiaryAccent px-4"
Expand All @@ -123,7 +132,7 @@ export const Content = () => {
))}
</div>
)}
<div className="w-full">
<div className="w-full" data-tour="search-bar">
<SearchInput
className={cn(Styles.Search)}
onSubmit={handleSearch}
Expand Down
12 changes: 8 additions & 4 deletions app/[locale]/(user)/components/ListingComponent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import { fetchData } from '@/fetch';
import { cn, formatDate } from '@/lib/utils';
import Filter from '../datasets/components/FIlter/Filter';
import Styles from '../datasets/dataset.module.scss';
import { useTourTrigger } from '@/hooks/use-tour-trigger';

// Helper function to strip markdown and HTML tags for card preview
const stripMarkdown = (markdown: string): string => {
Expand Down Expand Up @@ -256,6 +257,8 @@ const ListingComponent: React.FC<ListingProps> = ({
redirectionURL,
lockedFilters = {},
}) => {
useTourTrigger(true, 1500);

const [facets, setFacets] = useState<{
results: any[];
total: number;
Expand Down Expand Up @@ -397,7 +400,7 @@ const ListingComponent: React.FC<ListingProps> = ({

<div className="mt-5 lg:mt-10">
<div className="row mb-16 flex gap-5 ">
<div className="hidden min-w-64 max-w-64 lg:block">
<div className="hidden min-w-64 max-w-64 lg:block" data-tour="filters">
<Filter
options={filterOptions}
setSelectedOptions={handleFilterChange}
Expand All @@ -408,7 +411,7 @@ const ListingComponent: React.FC<ListingProps> = ({

<div className="flex w-full flex-col gap-4 px-2">
<div className="flex flex-wrap items-center justify-between gap-5 rounded-2 py-2 lg:flex-nowrap">
<div className="w-full md:block">
<div className="w-full md:block" data-tour="search">
<SearchInput
key={queryParams.query}
label="Search"
Expand Down Expand Up @@ -468,7 +471,7 @@ const ListingComponent: React.FC<ListingProps> = ({
/>
</Button>
</div>
<div className="flex items-center gap-2">
<div className="flex items-center gap-2" data-tour="sort">
<Select
label=""
labelInline
Expand Down Expand Up @@ -541,7 +544,7 @@ const ListingComponent: React.FC<ListingProps> = ({
onPageSizeChange={handlePageSizeChange}
view={view}
>
{datasetDetails.map((item: any) => {
{datasetDetails.map((item: any, index: number) => {
const image = item.is_individual_dataset
? item?.user?.profile_picture
? `${process.env.NEXT_PUBLIC_BACKEND_URL}/${item.user.profile_picture}`
Expand Down Expand Up @@ -654,6 +657,7 @@ const ListingComponent: React.FC<ListingProps> = ({
}
iconColor="warning"
href={`${redirectionURL}/${item.id}`}
data-tour={index === 0 && type === 'dataset' ? 'dataset-card' : index === 0 && type === 'usecase' ? 'usecase-card' : undefined}
/>
);
})}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import Metadata from './components/Metadata';
import PrimaryData from './components/PrimaryData';
import Resources from './components/Resources';
import SimilarDatasets from './components/SimilarDatasets';
import { useTourTrigger } from '@/hooks/use-tour-trigger';

const datasetQuery: any = graphql(`
query getDataset($datasetId: UUID!) {
Expand Down Expand Up @@ -84,6 +85,9 @@ export default function DatasetDetailsPage({
}: {
datasetId: string;
}) {
// Enable tour for first-time users
useTourTrigger(true, 1500);

const Datasetdetails: { data: any; isLoading: any } = useQuery(
[`details_${datasetId}`],
() => GraphQL(datasetQuery, {}, { datasetId: datasetId })
Expand Down Expand Up @@ -114,7 +118,7 @@ export default function DatasetDetailsPage({
]}
/>
<div className="flex">
<div className="w-full gap-10 border-r-2 border-solid border-greyExtralight p-6 lg:w-3/4 lg:p-10">
<div className="w-full gap-10 border-r-2 border-solid border-greyExtralight p-6 lg:w-3/4 lg:p-10" data-tour="dataset-info">
{Datasetdetails.isLoading ? (
<div className=" mt-8 flex justify-center">
<Spinner />
Expand All @@ -125,9 +129,9 @@ export default function DatasetDetailsPage({
isLoading={Datasetdetails.isLoading}
/>
)}
<Details />
<Resources />
<SimilarDatasets />
<Details data-tour="preview" />
<Resources data-tour="download-button" />
<SimilarDatasets data-tour="related-datasets" />
</div>
<div className=" hidden w-1/4 gap-10 px-7 py-10 lg:block">
{Datasetdetails.isLoading ? (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { ActionBar } from './components/action-bar';
import { Content } from './components/content';
import { Navigation } from './components/navigate-org-datasets';
import { formatDate } from '@/lib/utils';
import { useTourTrigger } from '@/hooks/use-tour-trigger';

const allDatasetsQueryDoc: any = graphql(`
query allDatasetsQuery($filters: DatasetFilter, $order: DatasetOrder) {
Expand Down Expand Up @@ -69,6 +70,8 @@ export default function DatasetPage({
}: {
params: { entityType: string; entitySlug: string };
}) {
useTourTrigger(true, 1500);

const router = useRouter();

const [navigationTab, setNavigationTab] = useQueryState('tab', parseAsString);
Expand Down Expand Up @@ -252,6 +255,7 @@ export default function DatasetPage({
<Navigation
setNavigationTab={setNavigationTab}
options={navigationOptions}
data-tour="sidebar"
/>

{AllDatasetsQuery.data?.datasets.length > 0 ? (
Expand All @@ -264,13 +268,15 @@ export default function DatasetPage({
content: 'Add New Dataset',
onAction: () => CreateDatasetMutation.mutate(),
}}
data-tour="create-dataset"
/>

<DataTable
columns={datasetsListColumns}
rows={generateTableData(AllDatasetsQuery.data.datasets)}
hideSelection
hideViewSelector
data-tour="my-datasets"
/>
</div>
) : AllDatasetsQuery.isLoading ? (
Expand Down
7 changes: 6 additions & 1 deletion app/[locale]/dashboard/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,12 @@ import BreadCrumbs from '@/components/BreadCrumbs';
import { Icons } from '@/components/icons';
import { Loading } from '@/components/loading';
import { useDashboardStore } from '@/config/store';
import { useTourTrigger } from '@/hooks/use-tour-trigger';

const UserDashboard = () => {
// Enable tour for first-time users
useTourTrigger(true, 1500);

const { userDetails } = useDashboardStore();
const list = [
{
Expand Down Expand Up @@ -43,12 +47,13 @@ const UserDashboard = () => {
<Text variant="headingXl"> User Dashboard</Text>
</div>
<div className="flex-1 ">
<div className="flex flex-wrap items-center gap-6 md:flex-nowrap lg:flex-nowrap">
<div className="flex flex-wrap items-center gap-6 md:flex-nowrap lg:flex-nowrap" data-tour="sidebar">
{list.map((item, index) => (
<Link
key={index}
href={item.path}
className=" flex max-h-56 min-h-56 w-full flex-col items-center justify-center gap-3 rounded-4 bg-greyExtralight p-4 "
data-tour={index === 0 ? 'my-datasets' : undefined}
>
<Icon source={item.icon} size={60} color="highlight" />
<Text variant="headingLg">{item.label}</Text>
Expand Down
75 changes: 75 additions & 0 deletions components/Tour/TourButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
'use client';

import React from 'react';
import { useManualTour } from '@/hooks/use-tour-trigger';
import { HelpCircle } from 'lucide-react';

interface TourButtonProps {
variant?: 'icon' | 'text' | 'both';
className?: string;
label?: string;
}

/**
* Button component to manually trigger the tour for current page
* Can be placed in header, footer, or anywhere on the page
*/
export function TourButton({
variant = 'both',
className = '',
label = 'Take a tour'
}: TourButtonProps) {
const { startTour, hasTour, isTourRunning } = useManualTour();

// Don't render if no tour available for current page
if (!hasTour) {
return null;
}

// Don't render if tour is already running
if (isTourRunning) {
return null;
}

const baseClasses = 'inline-flex items-center gap-2 rounded-md transition-all duration-200 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-actionPrimaryBasicDefault';

const variantClasses = {
icon: 'p-2 hover:bg-actionSecondaryBasicHovered',
text: 'px-4 py-2 text-sm font-medium text-textMedium hover:text-textDefault hover:bg-actionSecondaryBasicHovered',
both: 'px-4 py-2 text-sm font-medium bg-actionSecondaryBasicDefault hover:bg-actionSecondaryBasicHovered text-textDefault',
};

return (
<button
onClick={startTour}
className={`${baseClasses} ${variantClasses[variant]} ${className}`}
aria-label={label}
title={label}
>
<HelpCircle className="w-4 h-4" />
{(variant === 'text' || variant === 'both') && <span>{label}</span>}
</button>
);
}

/**
* Floating action button for tour - positioned fixed on screen
*/
export function FloatingTourButton() {
const { startTour, hasTour, isTourRunning } = useManualTour();

if (!hasTour || isTourRunning) {
return null;
}

return (
<button
onClick={startTour}
className="fixed bottom-6 right-6 z-50 flex items-center justify-center w-14 h-14 rounded-full bg-actionPrimaryBasicDefault text-textOnBGDefault shadow-lg hover:bg-actionPrimaryBasicHovered transition-all duration-200 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-actionPrimaryBasicDefault"
aria-label="Take a tour"
title="Take a tour"
>
<HelpCircle className="w-6 h-6" />
</button>
);
}
Loading