Skip to content

Commit

Permalink
feat: new backend dashboard - done free version [wip][ref Codeinwp/ne…
Browse files Browse the repository at this point in the history
  • Loading branch information
abaicus committed Jan 8, 2025
1 parent d5d23ab commit c0d64fb
Show file tree
Hide file tree
Showing 21 changed files with 724 additions and 455 deletions.
40 changes: 17 additions & 23 deletions assets/apps/dashboard/src/Components/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,26 @@ import TabsContent from './TabsContent';
import Sidebar from './Sidebar';
import Loading from './Loading';
import Snackbar from './Snackbar';
import Container from '../Layout/Container';
import { fetchOptions } from '../utils/rest';

import { withDispatch, withSelect } from '@wordpress/data';
import { compose } from '@wordpress/compose';
import { useDispatch, useSelect } from '@wordpress/data';
import { useState, useEffect } from '@wordpress/element';
import Deal from './Deal';

Check failure on line 12 in assets/apps/dashboard/src/Components/App.js

View workflow job for this annotation

GitHub Actions / npm (14.x)

'Deal' is defined but never used
import Container from '../Layout/Container';

const App = ({ setSettings, toast, currentTab, setTab }) => {
const App = () => {
const [loading, setLoading] = useState(true);

const { setSettings, setTab } = useDispatch('neve-dashboard');

const { toast, currentTab } = useSelect((select) => {
const { getToast, getTab } = select('neve-dashboard');
return {
toast: getToast(),
currentTab: getTab(),
};
});

useEffect(() => {
fetchOptions().then((r) => {
setSettings(r);
Expand All @@ -24,21 +34,20 @@ const App = ({ setSettings, toast, currentTab, setTab }) => {
if (loading) {
return <Loading />;
}

return (
<div className="antialiased grow flex flex-col gap-6 h-full">
<Header />

{/*<Deal />*/}
{'starter-sites' !== currentTab && <Notifications />}

<Container className="flex flex-col md:flex-row gap-6 h-full grow">
<Container className="flex flex-col lg:flex-row gap-6 h-full grow">
<div className="grow">
<TabsContent currentTab={currentTab} setTab={setTab} />
</div>

{'starter-sites' !== currentTab && (
<div className="shrink-0 md:w-[350px]">
<div className="shrink-0 lg:w-[435px]">
<Sidebar />
</div>
)}
Expand All @@ -49,19 +58,4 @@ const App = ({ setSettings, toast, currentTab, setTab }) => {
);
};

export default compose(
withDispatch((dispatch) => {
const { setSettings, setTab } = dispatch('neve-dashboard');
return {
setSettings: (object) => setSettings(object),
setTab: (tab) => setTab(tab),
};
}),
withSelect((select) => {
const { getToast, getTab } = select('neve-dashboard');
return {
toast: getToast(),
currentTab: getTab(),
};
})
)(App);
export default App;
255 changes: 156 additions & 99 deletions assets/apps/dashboard/src/Components/Content/Changelog.js
Original file line number Diff line number Diff line change
@@ -1,113 +1,170 @@
/* global neveDash */
import Accordion from '../Accordion';
import classnames from 'classnames';

import cn from 'classnames';
import { Clock, Crown, Rocket, Bug, Zap, CheckCircle } from 'lucide-react';
import { __ } from '@wordpress/i18n';
import { Fragment, useState } from '@wordpress/element';
import { useState } from '@wordpress/element';

import Card from '../../Layout/Card';
import Button from '../Common/Button';
import Pill from '../Common/Pill';

const TAB_CHOICES = {
FREE: 'free',
PRO: 'pro',
};

const CHANGE_TYPES = {
features: {
icon: <Rocket className="size-4 text-green-600 mr-2" />,
label: __('Features', 'neve'),
},
fixes: {
icon: <Bug className="size-4 text-red-600 mr-2" />,
label: __('Bug Fixes', 'neve'),
},
tweaks: {
icon: <Zap className="size-4 text-blue-600 mr-2" />,
label: __('Tweaks', 'neve'),
},
};

const TabButton = ({ active, onClick, children }) => {
return (
<button
onClick={onClick}
className={cn(
`px-4 py-2 text-sm font-medium rounded-lg transition-colors duration-150`,
{
'bg-blue-100 text-blue-700': active,
'text-gray-600 hover:text-gray-900 hover:bg-gray-100':
!active,
}
)}
>
{children}
</button>
);
};

const ChangelogEntry = ({ data }) => {
const { version, tweaks, fixes, features, date } = data;

const renderChangeList = (type, items) => {
if (!items?.length) return null;

const { icon, label } = CHANGE_TYPES[type];

return (
<div key={version + type}>
<div className="flex items-center mb-2">
{icon}
<span className="text-sm font-medium text-gray-700">
{label}
</span>
</div>
<ul className="space-y-2 ml-6">
{items.map((item, index) => {
return (
<li
key={index}
className="text-sm text-gray-600 flex items-start"
>
<CheckCircle className="w-3.5 h-3.5 text-gray-400 mr-2 mt-0.5 flex-shrink-0" />
<span
dangerouslySetInnerHTML={{ __html: item }}
/>
</li>
);
})}
</ul>
</div>
);
};

return (
<div className="border-b border-gray-200 last:border-0">
<div className="p-6">
<div className="flex items-center justify-between mb-4">
<div className="flex items-center space-x-3">
<h3 className="text-base font-semibold text-gray-900">
{__('Version', 'neve')} {version}
</h3>
<Pill type="primary" className={'ml-auto'}>
{date}
</Pill>
</div>
</div>
<div className="space-y-3">
{Object.entries({ features, fixes, tweaks }).map(
([type, items]) => renderChangeList(type, items)
)}
</div>
</div>
</div>
);
};
const Changelog = () => {
const { changelog, changelogPro } = neveDash;
const [showForPro, setShowForPro] = useState(false);

const [shown, setShown] = useState(4);
const [activeTab, setActiveTab] = useState(TAB_CHOICES.FREE);
const changelogData =
activeTab === TAB_CHOICES.FREE ? changelog : changelogPro;

return (
<div className="card">
<div className="grid gap-5">
{changelogPro && (
<div className="changelog-tabs">
<span>{__('Show changelog for', 'neve')}</span>
<a
href="#changelog-neve"
className={classnames([{ active: !showForPro }])}
onClick={() => {
setShowForPro(false);
}}
>
Neve
</a>
<a
href="#show-for-pro"
className={classnames([{ active: showForPro }])}
onClick={() => {
setShowForPro(true);
}}
<Card>
<div className="flex items-center justify-between">
<div className="flex items-center space-x-2">
<Clock className="size-4 text-gray-400" />
<span className="text-sm font-medium text-gray-900">
{__('Recent Updates', 'neve')}
</span>
</div>
<div className="flex space-x-2">
<TabButton
active={activeTab === TAB_CHOICES.FREE}
onClick={() => setActiveTab(TAB_CHOICES.FREE)}
>
{__('Free Version', 'neve')}
</TabButton>
<TabButton
active={activeTab === TAB_CHOICES.PRO}
onClick={() => setActiveTab(TAB_CHOICES.PRO)}
>
<div className="flex items-center space-x-1">
<Crown className="size-4 text-yellow-500" />
<span>{__('Pro Version', 'neve')}</span>
</div>
</TabButton>
</div>
</div>
</Card>
)}

<Card className="!p-0">
{changelogData.slice(0, shown).map((entry) => {
const { version, tweaks, fixes, features } = entry;

if ((!tweaks && !fixes && !features) || !version) {
return null;
}

return <ChangelogEntry key={version} data={entry} />;
})}
</Card>

{changelogData.length > shown && (
<div className="text-center my-8 mx-auto">
<Button
className="text-lg"
onClick={() => setShown(shown + 4)}
>
Neve Pro
</a>
{__('Load More', 'neve')}
</Button>
</div>
)}
{(showForPro ? changelogPro : changelog).map((entry, index) => {
const { date, version, tweaks, fixes, features } = entry;
if (!tweaks && !fixes && !features) {
return null;
}
const title = (
<Fragment>
<span className="version">v{version}</span> -{' '}
<span className="date">{date}</span>
</Fragment>
);

return (
<Accordion key={index} isOpen={0 === index} title={title}>
{features && (
<div className="features changelog-category">
<div className="label-wrap">
<span className="label success">
{__('Features', 'neve')}
</span>
</div>
<ul className="entries">
{features.map((feature, indexFeature) => (
<li
key={indexFeature}
dangerouslySetInnerHTML={{
__html: feature,
}}
/>
))}
</ul>
</div>
)}
{fixes && (
<div className="bugs changelog-category">
<div className="label-wrap">
<span className="label error">
{__('Bug Fixes', 'neve')}
</span>
</div>
<ul className="entries">
{fixes.map((fix, indexFixes) => (
<li
key={indexFixes}
dangerouslySetInnerHTML={{
__html: fix,
}}
/>
))}
</ul>
</div>
)}
{tweaks && (
<div className="tweaks changelog-category">
<div className="label-wrap">
<span className="label info">
{__('Tweaks', 'neve')}
</span>
</div>
<ul className="entries">
{tweaks.map((tweak, indexTweak) => (
<li
key={indexTweak}
dangerouslySetInnerHTML={{
__html: tweak,
}}
/>
))}
</ul>
</div>
)}
</Accordion>
);
})}
</div>
);
};
Expand Down
Loading

0 comments on commit c0d64fb

Please sign in to comment.