diff --git a/system/apps/blog-e2e/src/e2e/articles-filtering.cy.ts b/system/apps/blog-e2e/src/e2e/articles-filtering.cy.ts index 990c816fe..a22bcce9d 100644 --- a/system/apps/blog-e2e/src/e2e/articles-filtering.cy.ts +++ b/system/apps/blog-e2e/src/e2e/articles-filtering.cy.ts @@ -7,6 +7,6 @@ describe('Articles filtering works when: ', () => { it('not signed in user visits your articles page and session expiration section is displayed', () => { Given('System mocked endpoint', 'getRecommendedArticles') .And('System sets page as', '/en/articles') - .Then('I not see text', 'Show your articles'); + .Then('I not see text', 'Yours', 'All') }); }); diff --git a/system/apps/blog-e2e/src/e2e/sign-in.cy.ts b/system/apps/blog-e2e/src/e2e/sign-in.cy.ts index 091b2ef59..2740365f7 100644 --- a/system/apps/blog-e2e/src/e2e/sign-in.cy.ts +++ b/system/apps/blog-e2e/src/e2e/sign-in.cy.ts @@ -25,7 +25,7 @@ describe('Sign in works when: ', () => { 'Signed in' ) .And('Im on page', '/en/articles') - .When('I click checkbox', 'Show your articles') + .When('I click tab', 'Yours') .Then('System recieved response from endpoint', 'getYourArticles') .When('I go back') .Then( diff --git a/system/apps/blog/components/articles-grid/article-tile.tsx b/system/apps/blog/components/articles-grid/article-tile.tsx index 1bd2122e2..1ac066030 100644 --- a/system/apps/blog/components/articles-grid/article-tile.tsx +++ b/system/apps/blog/components/articles-grid/article-tile.tsx @@ -26,12 +26,8 @@ const avatar_size = { }; const Container = styled.div` - background: 1px solid ${(props) => props.theme.box.outlined.bg}; - overflow: hidden; - .article-tile-flipped-container { ${column()} - padding: ${tokens.spacing[200]}; height: 100%; .detail { diff --git a/system/apps/blog/components/articles-screen/articles-screen.tsx b/system/apps/blog/components/articles-screen/articles-screen.tsx index deb7445a8..d2af96619 100644 --- a/system/apps/blog/components/articles-screen/articles-screen.tsx +++ b/system/apps/blog/components/articles-screen/articles-screen.tsx @@ -1,7 +1,6 @@ import { Box, Button, - Checkbox, Divider, Field, FiltersIcon, @@ -9,7 +8,10 @@ import { L_DOWN, Loader, M_DOWN, + M_UP, Popover, + Tab, + Tabs, VIEWPORT, column, tokens, @@ -27,7 +29,7 @@ import { InfoSection } from '../info-section'; import { ScrollState, useScroll } from '@system/figa-hooks'; import { Lang } from '@system/blog-api-models'; import type { ArticlesStore } from '../../store-factories/articles'; -import { auth_store_selectors } from '../../store/auth'; +import { SignedInOnly } from '../../core'; const Placeholder = styled.div` background: ${(props) => props.theme.box.filled.bg}; @@ -80,14 +82,14 @@ const Container = styled.div` .articles-content { ${column()} - & > .h6 { - margin-bottom: ${tokens.spacing[250]}; + & > .b1 { + margin: 0 0 ${tokens.spacing[150]} 0; } .articles-screen-tiles { display: grid; - grid-template-columns: 1fr 1fr 1fr; - gap: ${tokens.spacing[250]}; + grid-template-columns: 32.5% 32.5% 32.5%; + gap: ${tokens.spacing[300]} 2.5%; & > * { height: 400px; @@ -97,21 +99,24 @@ const Container = styled.div` @media ${L_DOWN} { .articles-content .articles-screen-tiles { - grid-template-columns: 1fr 1fr; + grid-template-columns: 49% 49%; + gap: ${tokens.spacing[300]} 2%; } } @media (max-width: 940px) { .articles-content .articles-screen-tiles { - grid-template-columns: 1fr; + grid-template-columns: 100%; + gap: ${tokens.spacing[200]}; } } @media (max-width: 740px) { - grid-template-columns: 1fr; + grid-template-columns: 100%; .articles-content .articles-screen-tiles { - grid-template-columns: 1fr 1fr; + grid-template-columns: 49% 49%; + gap: ${tokens.spacing[300]} 2%; } .articles-filters { @@ -125,7 +130,16 @@ const Container = styled.div` @media ${M_DOWN} { .articles-content .articles-screen-tiles { - grid-template-columns: 1fr; + grid-template-columns: 100%; + gap: ${tokens.spacing[300]}; + } + } + + .tabs { + margin: 0 0 ${tokens.spacing[200]} 0; + + @media ${M_UP} { + max-width: 280px; } } `; @@ -141,8 +155,21 @@ const Filters = styled.div` .divider div { width: 100%; + height: ${tokens.spacing[12]}; background: ${(props) => props.theme.box.outlined.borderColor}; } + + .articles-screen-filters-content { + padding: ${tokens.spacing[250]}; + + & > *:not(:last-child) { + margin-bottom: ${tokens.spacing[200]}; + } + + & > *:last-child { + margin-top: ${tokens.spacing[450]}; + } + } `; const makeUrl = (lang: Lang, article: ArticlesStore.Article): string => { @@ -194,7 +221,6 @@ const PopoverTrigger = ({ }; const ArticlesScreen = (props: ArticlesScreenProps) => { - const authorized = auth_store_selectors.useIsAuthorized(); const { selectors, actions } = props; const state = selectors.useState(); const lang = useLang(); @@ -214,6 +240,17 @@ const ArticlesScreen = (props: ArticlesScreenProps) => { [state] ); + const filtersChanged = useMemo(() => { + if (state.is === 'idle') { + return false; + } + + const { CurrentPage, yours, ...initialParams } = state.initialParams; + const { CurrentPage: cp, yours: y, ...params } = state.params; + + return !isEqual(initialParams, params); + }, [state]); + const filters = ( @@ -229,31 +266,23 @@ const ArticlesScreen = (props: ArticlesScreenProps) => { - +
actions.change({ Search })} /> - - actions.change({ Status })} - /> - - {authorized && ( - - actions.change({ yours: !selectors.safeState().params.yours }) - } - /> - )} + + + + actions.change({ Status })} + /> + + + { Share - +
); @@ -309,7 +338,23 @@ const ArticlesScreen = (props: ArticlesScreenProps) => { return ( <> - Results ({state.articles.length}) + + + actions.change({ yours: false })} + > + All + + actions.change({ yours: true })} + > + Yours + + + + Results ({state.articles.length})
{state.articles.map((article) => ( {
); - }, [state, lang, actions.reset]); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [state, lang]); return ( - + Articles {filters} diff --git a/system/apps/blog/components/main-layout/main-layout.tsx b/system/apps/blog/components/main-layout/main-layout.tsx index 1cb83296d..04a82f444 100644 --- a/system/apps/blog/components/main-layout/main-layout.tsx +++ b/system/apps/blog/components/main-layout/main-layout.tsx @@ -19,9 +19,6 @@ import { ArticlesSearchIcon, BottomNavItem, PlusCircleIcon, - useThemeProvider, - SunIcon, - HalfMoonIcon, TopNavItem, column, } from '@system/figa-ui'; @@ -81,7 +78,6 @@ const LogoWrapper = styled.div` const MainLayout = ({ children, sidebar, offPadding }: MainLayoutProps) => { const lang = useLang(); - const theme = useThemeProvider(); const pathname = usePathname(); const [, { toTop }] = useScrollTo(); @@ -112,13 +108,6 @@ const MainLayout = ({ children, sidebar, offPadding }: MainLayoutProps) => { Create - - theme.setTheme(theme.key === 'dark' ? 'light' : 'dark') - } - > - Theme {theme.key === 'dark' ? : } - } bottomNav={ @@ -144,13 +133,6 @@ const MainLayout = ({ children, sidebar, offPadding }: MainLayoutProps) => { active={pathname === `/${lang}/articles-creator`} /> - : } - text="Theme" - onClick={() => - theme.setTheme(theme.key === 'dark' ? 'light' : 'dark') - } - /> } sidebar={sidebar} diff --git a/system/apps/blog/components/main-layout/user-section.tsx b/system/apps/blog/components/main-layout/user-section.tsx index dbcd0d11c..d8a2a9960 100644 --- a/system/apps/blog/components/main-layout/user-section.tsx +++ b/system/apps/blog/components/main-layout/user-section.tsx @@ -1,4 +1,11 @@ -import { Box, TopNavItem } from '@system/figa-ui'; +import { + Box, + Button, + HalfMoonIcon, + SunIcon, + TopNavItem, + useThemeProvider, +} from '@system/figa-ui'; import { Link } from '../link'; import { useLang } from '../../dk'; import { useAuthStore } from '../../store/auth'; @@ -9,22 +16,47 @@ const UserSection = () => { const { is } = useAuthStore(); const pathname = usePathname(); const lang = useLang(); + const theme = useThemeProvider(); if (is === 'idle') { return ( - + Sign Up Sign In + ); } if (is === 'authorized') { - return ; + return ( + + + + + ); } return ( - + Sign Up @@ -35,6 +67,15 @@ const UserSection = () => { Sign In + ); }; diff --git a/system/apps/blog/store-factories/articles/create-articles-store.ts b/system/apps/blog/store-factories/articles/create-articles-store.ts index 6e8fe7a16..9b09d65aa 100644 --- a/system/apps/blog/store-factories/articles/create-articles-store.ts +++ b/system/apps/blog/store-factories/articles/create-articles-store.ts @@ -222,7 +222,16 @@ const createArticlesStore = () => { initialParams: params, }); }, - change: (params) => change.next(params), + change: (params) => { + const state = selectors.state(); + + if (state.is === 'changing_fail') { + actions.reset(); + return; + } + + change.next(params); + }, reset: () => { const state = selectors.state(); diff --git a/system/apps/blog/store/auth/actions.ts b/system/apps/blog/store/auth/actions.ts index 820e0b42c..4fa6890d5 100644 --- a/system/apps/blog/store/auth/actions.ts +++ b/system/apps/blog/store/auth/actions.ts @@ -1,6 +1,8 @@ import { type AuthStore } from './defs'; import { useAuthStore } from './store'; import { authStorage } from './core'; +import { articles_store_actions } from '../articles'; +import { sign_in_store_actions } from '../sign-in'; const { setState } = useAuthStore; @@ -26,6 +28,8 @@ const auth_store_actions: AuthStore.Actions = { unauthorize: () => { authStorage.set('user', null); useAuthStore.setState({ is: 'unauthorized', user: null }); + articles_store_actions.reset(); + sign_in_store_actions.reset(); }, }; diff --git a/system/apps/blog/store/sign-out/actions.ts b/system/apps/blog/store/sign-out/actions.ts index 3761ddfc4..238080b8c 100644 --- a/system/apps/blog/store/sign-out/actions.ts +++ b/system/apps/blog/store/sign-out/actions.ts @@ -2,7 +2,6 @@ import { getError, signOut } from '@system/blog-api'; import { type SignOutStore } from './defs'; import { useSignOutStore } from './store'; import { auth_store_actions } from '../auth'; -import { sign_in_store_actions } from '../sign-in'; const { setState } = useSignOutStore; @@ -18,7 +17,6 @@ const sign_out_store_actions: SignOutStore.Actions = { await signOut(); auth_store_actions.unauthorize(); - sign_in_store_actions.reset(); set({ is: 'ok' }); } catch (error: unknown) { diff --git a/system/apps/blog/store/sign-out/store.test.ts b/system/apps/blog/store/sign-out/store.test.ts index 00be5c365..b41375711 100644 --- a/system/apps/blog/store/sign-out/store.test.ts +++ b/system/apps/blog/store/sign-out/store.test.ts @@ -4,13 +4,11 @@ import { signOut, getError } from '@system/blog-api'; import { storeFixture } from '../test-utils'; import { mockResponseError } from '@system/blog-api-mocks'; import { auth_store_actions } from '../auth'; -import { sign_in_store_actions } from '../sign-in'; import type { SignOutStore } from './defs'; import { sign_out_store_actions } from './actions'; jest.mock('@system/blog-api'); jest.mock('../auth'); -jest.mock('../sign-in'); describe('Allows to sign out user when: ', () => { afterEach(() => { @@ -22,7 +20,6 @@ describe('Allows to sign out user when: ', () => { (signOut as jest.Mock).mockImplementation(() => Promise.resolve()); (auth_store_actions.unauthorize as jest.Mock).mockImplementation(jest.fn()); - (sign_in_store_actions.reset as jest.Mock).mockImplementation(jest.fn()); expect(result.current.is).toBe('idle'); @@ -37,7 +34,6 @@ describe('Allows to sign out user when: ', () => { }); expect(auth_store_actions.unauthorize).toHaveBeenCalledTimes(1); - expect(sign_in_store_actions.reset).toHaveBeenCalledTimes(1); expect(result.current.is).toBe('ok'); restore(); @@ -64,7 +60,6 @@ describe('Allows to sign out user when: ', () => { }); expect(auth_store_actions.unauthorize).not.toHaveBeenCalled(); - expect(sign_in_store_actions.reset).not.toHaveBeenCalled(); expect(result.current.is).toBe('fail'); expect((result.current as SignOutStore.Fail).error).toEqual( mockResponseError() diff --git a/system/libs/figa-ui/src/lib/theme-provider/light-theme.ts b/system/libs/figa-ui/src/lib/theme-provider/light-theme.ts index 03c022f1d..d2899110d 100644 --- a/system/libs/figa-ui/src/lib/theme-provider/light-theme.ts +++ b/system/libs/figa-ui/src/lib/theme-provider/light-theme.ts @@ -20,11 +20,11 @@ const light: Theme = { }, }, checkbox: { - borderColor: tokens.common.white, + borderColor: tokens.common.black, checked: { bg: tokens.primary[50], borderColor: tokens.primary[50], - color: tokens.common.white, + color: tokens.common.black, }, }, radio: {