Skip to content

Commit

Permalink
Merge branch 'main' into budget-component
Browse files Browse the repository at this point in the history
  • Loading branch information
wisnie authored Oct 23, 2022
2 parents e5fc799 + bf5ca93 commit 9eaac0f
Show file tree
Hide file tree
Showing 16 changed files with 259 additions and 14 deletions.
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
# My local circle
[![Netlify Status](https://api.netlify.com/api/v1/badges/643b7640-740f-4db3-b3f3-ea179b2ad3e8/deploy-status)](https://app.netlify.com/sites/localcircle/deploys)

# My Local Circle

Aplikacja została stworzona, aby zwiększyć wpływ społeczności lokalnej (mieszkańcy bloku, studenci, uczniowie) na decyzje dot. realizowanych projektów (np. budowa parku, zbiórka na wycieczkę), a także proponować własne inicjatywy. Jako uczestnik społeczności możesz np. tworzyć zbiórki, głosować na ciekawe pomysły, a także monitorować przebieg obecnych inwestycji. Wspieramy też interfejs w języku ukraińskim, wykorzystując prostą autorską bibliotekę do mapowania danych.

Expand Down
36 changes: 29 additions & 7 deletions components/composited/BudgetsPage/BudgetsPage.tsx
Original file line number Diff line number Diff line change
@@ -1,23 +1,45 @@
import { useBudgets } from '../../../hooks/useBudgets';
import { useUser } from '../../../hooks/useUser';
import { formatDate } from '../../../utils/formatDate';
import { Community } from '../../../validators/Community';
import { BudgetItem } from '../../generic/BudgetItem/BudgetItem';
import { Heading } from '../../generic/Heading/Heading';
import { SmallCommunityAddIcon } from '../../generic/Icons/SmallCommunityAddIcon';
import { LinkWithIcon } from '../../generic/LinkWithIcon/LinkWithIcon';

export type BudgetsPageProps = {
community: Community;
};

export const BudgetsPage = ({ community }: BudgetsPageProps) => {
const { data: user } = useUser();
const { data } = useBudgets(community.id as number);

return (
<section>
<Heading
className="mb-4 sm:col-end-2 sm:mb-8"
as="h1"
content="Budżety społeczności"
variant="base"
displayDecorationBorder={true}
/>
<div className="flex items-baseline justify-between mb-8 pb-4 border-b border-dashed border-gray-400">
<Heading as="h1" content={`Budżety społeczności - ${community.name}`} variant="base" />
<LinkWithIcon
icon={<SmallCommunityAddIcon className="fill-white" />}
content="Nowy"
variant="primary"
href="/communities/[communitySlug]/budgets/new"
/>
</div>
<ul className="flex flex-col gap-y-6 sm:grid sm:grid-cols-2 sm:gap-x-10 sm:gap-y-8 lg:gap-x-24 lg:gap-y-10">
{data?.map((budget) => (
<li key={`${budget.slug}${budget.communityId}`}>
<BudgetItem
title={budget.name}
communityName={community.name}
slug={budget.slug}
description={budget.description}
authored={budget.coordinator === user?.id}
estimatedRealisationDate={formatDate(budget.estimatedRealisationDate)}
/>
</li>
))}
</ul>
</section>
);
};
13 changes: 13 additions & 0 deletions components/composited/HomePage/CoverImage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { ReactNode } from 'react';
import { clsx as cx } from 'clsx';

type CoverImageProps = {
children: ReactNode;
className?: string;
};

export const CoverImage = ({ children, className }: CoverImageProps) => {
return (
<div className={cx('h-fit border-2 shadow rounded lg:rounded-lg', className)}>{children}</div>
);
};
22 changes: 22 additions & 0 deletions components/composited/HomePage/HomeFeature.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { ReactNode } from 'react';

type HomeFeatureProps = {
title: string;
description: string;
// Icon
children: ReactNode;
};

export const HomeFeature = ({ title, description, children }: HomeFeatureProps) => {
return (
<article className="flex gap-2">
{children}
<div className="ml-2">
<h3 className="mb-2 text-lg font-semibold text-gray-700 lg:text-2xl lg:leading-9">
{title}
</h3>
<p className="text-base text-gray-500 lg:text-xl">{description}</p>
</div>
</article>
);
};
55 changes: 55 additions & 0 deletions components/composited/HomePage/HomeFeatureList.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import { FavoriteIcon } from '../../generic/Icons/FavoriteIcon';
import { PeopleIcon } from '../../generic/Icons/PeopleIcon';
import { ProjectIcon } from '../../generic/Icons/ProjectIcon';
import { TimelineIcon } from '../../generic/Icons/TimelineIcon';
import { HomeFeature } from './HomeFeature';

export const HomeFeatureList = () => {
return (
<ul className="sm:w-1/2 flex flex-col gap-y-8 lg:gap-y-16 lg:mt-16 xl:mt-24">
<HomeFeature
title="Własne społeczności"
description="Utwórz własną społeczność, zarządzaj nią i miej kontrolę nad czynionymi przez członków zmianami."
>
<PeopleIcon
width={40}
height={40}
fill="fill-blue-800"
className="shrink-0 p-1 rounded bg-blue-200 lg:w-14 lg:h-14"
/>
</HomeFeature>
<HomeFeature
title="Tworzenie budżetów kwartalnych"
description="Twoje wykresy będą dopasowane pod Ciebie. Projektuj co tylko chcesz, czekają na ciebie różne rodzaje budżetów."
>
<TimelineIcon
width={40}
height={40}
fill="fill-blue-800"
className="shrink-0 p-1 rounded bg-blue-200 lg:w-14 lg:h-14"
/>
</HomeFeature>
<HomeFeature
title="Głosowanie na projekty"
description="Głosuj za projektami innych i obserwuj ich rozwój. Zgłaszaj też własne propozycje."
>
<ProjectIcon
width={40}
height={40}
fill="fill-blue-800"
className="shrink-0 p-1 rounded bg-blue-200 lg:w-14 lg:h-14"
/>
</HomeFeature>
<HomeFeature
title="Realizacja pomysłów"
description="Zaproponuj ciekawe rozwiązanie i obserwuj, jak projekty otrzymują poparcie innych członków."
>
<FavoriteIcon
width={40}
height={40}
className="fill-blue-800 shrink-0 p-1 rounded bg-blue-200 lg:w-14 lg:h-14"
/>
</HomeFeature>
</ul>
);
};
44 changes: 44 additions & 0 deletions components/composited/HomePage/HomePage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import Image from 'next/image';
import { CoverImage } from './CoverImage';
import { HomeFeatureList } from './HomeFeatureList';

export const HomePage = () => {
return (
<section className="relative sm:grid sm:grid-cols-2 sm:gap-x-14">
<div>
<header className="pb-12">
<h1 className="mb-2 pb-2 text-2xl leading-8 text-gray-800 font-bold text-center sm:text-start lg:text-3xl lg:leading-10">
Organizacja funduszy jest prosta i przyjemna
</h1>
<p className="text-lg leading-8 text-gray-500 text-center sm:text-start lg:text-xl lg:leading-8">
Uniwersalne podejście do pracy z Twoją lokalną społecznością i współpraca przy
podejmowaniu finansowych decyzji.
</p>
</header>
<h2 className="mt-6 mb-2 text-gray-800 text-xl font-bold lg:text-2xl lg:mt-12">
Przeglądaj budżety online
</h2>
<p className="text-base leading-7 text-gray-500 lg:text-lg">
Twórz społeczności, budżety i proponuj projekty innym członkom. Aktualizuj ich przebieg i
bądż na bieżąco. To wszystko (i więcej) w jednym miejscu. Ułatwienie pracy dla Ciebie i
twojej grupy.
</p>
</div>
<CoverImage className="mt-12 sm:mt-0 lg:w-96">
<img className="rounded lg:rounded-lg" src="/home-cover.png" alt="Preview of budget page" />
</CoverImage>

<div className="mt-16 col-span-2 sm:mt-16 lg:mt-0 sm:flex sm:flex-row-reverse sm:gap-14 sm:justify-between lg:gap-0">
<HomeFeatureList />

<CoverImage className="w-full mt-16 sm:mt-0 sm:w-1/2 lg:w-80 lg:mt-16 xl:w-96 xl:absolute xl:left-0 xl:bottom-56">
<img
className="rounded lg:rounded-lg"
src="/home-cover-secondary.png"
alt="Preview of project"
/>
</CoverImage>
</div>
</section>
);
};
6 changes: 3 additions & 3 deletions components/generic/Breadcrumbs/Breadcrumbs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,13 @@ type BreadcrumbsProps = {
export const Breadcrumbs = ({ community, budget, className }: BreadcrumbsProps) => {
return (
<div className={cx('flex gap-1', className)}>
<span className="text-sm leading-5 font-normal text-blue-800 focus:underline hover:underline sm:text-base">
<span className="text-sm leading-5 font-normal text-blue-800 focus:underline hover:underline lg:text-base">
<Link href={`/communities/${community.slug}`}>
<a>{community.name}</a>
</Link>
</span>
<span className="text-sm leading-5 font-normal text-gray-700">/</span>
<span className="text-sm leading-5 font-semibold text-blue-800 focus:underline hover:underline sm:text-base">
<span className="text-sm leading-5 font-normal text-gray-700 lg:text-base">/</span>
<span className="text-sm leading-5 font-semibold text-blue-800 lg:text-base focus:underline hover:underline">
<Link href={`/communities/${community.slug}/budgets/${budget.slug}`}>
<a>{budget.name}</a>
</Link>
Expand Down
45 changes: 45 additions & 0 deletions components/generic/BudgetItem/BudgetItem.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { Fragment } from 'react';
import { Badge } from '../Badge/Badge';
import { Breadcrumbs } from '../Breadcrumbs/Breadcrumbs';

type BudgetItemProps = {
title: string;
slug: string;
communityName: string;
description: string;
authored: boolean;
estimatedRealisationDate: string;
};

export const BudgetItem = ({
title,
communityName,
slug,
description,
authored,
estimatedRealisationDate,
}: BudgetItemProps) => {
const [communitySlug, budgetSlug] = slug.split('/');

return (
<Fragment>
<div className="flex items-center gap-4 mb-2">
<Breadcrumbs
community={{
name: communityName,
slug: communitySlug,
}}
budget={{
name: title,
slug: budgetSlug,
}}
/>
{authored && <Badge color="amber" textContent="Twoje podanie" />}
</div>
<p className="text-xs leading-5 text-gray-700 mb-3 lg:text-sm lg:leading-6">{description}</p>
<span className="block text-xs leading-5 text-gray-500 pb-2 border-b border-gray-300 sm:pb-4 lg:text-sm lg:leading-6">
Przewidywane zakończenie: {estimatedRealisationDate}
</span>
</Fragment>
);
};
34 changes: 34 additions & 0 deletions components/generic/Icons/PeopleIcon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { clsx as cx } from 'clsx';
import { DEFAULT_HEIGHT, DEFAULT_WIDTH } from './constants';

type PeopleIconProps = {
width?: number;
height?: number;
className?: string;
fill?: string;
};

export const PeopleIcon = ({
width = DEFAULT_WIDTH,
height = DEFAULT_HEIGHT,
className,
fill = 'fill-gray-600',
}: PeopleIconProps) => {
return (
<svg
className={cx(className, fill)}
xmlns="http://www.w3.org/2000/svg"
width={width}
height={height}
viewBox="0 0 24 24"
aria-hidden={true}
focusable={false}
>
<path d="M6.32,13.01c0.96,0.02,1.85,0.5,2.45,1.34C9.5,15.38,10.71,16,12,16c1.29,0,2.5-0.62,3.23-1.66 c0.6-0.84,1.49-1.32,2.45-1.34C16.96,11.78,14.08,11,12,11C9.93,11,7.04,11.78,6.32,13.01z" />
<path d="M4,13L4,13c1.66,0,3-1.34,3-3c0-1.66-1.34-3-3-3s-3,1.34-3,3C1,11.66,2.34,13,4,13z" />
<path d="M20,13L20,13c1.66,0,3-1.34,3-3c0-1.66-1.34-3-3-3s-3,1.34-3,3C17,11.66,18.34,13,20,13z" />
<path d="M12,10c1.66,0,3-1.34,3-3c0-1.66-1.34-3-3-3S9,5.34,9,7C9,8.66,10.34,10,12,10z" />
<path d="M21,14h-3.27c-0.77,0-1.35,0.45-1.68,0.92C16.01,14.98,14.69,17,12,17c-1.43,0-3.03-0.64-4.05-2.08 C7.56,14.37,6.95,14,6.27,14L3,14c-1.1,0-2,0.9-2,2v3c0,0.55,0.45,1,1,1h5c0.55,0,1-0.45,1-1v-1.26c1.15,0.8,2.54,1.26,4,1.26 s2.85-0.46,4-1.26V19c0,0.55,0.45,1,1,1h5c0.55,0,1-0.45,1-1v-3C23,14.9,22.1,14,21,14z" />
</svg>
);
};
4 changes: 3 additions & 1 deletion components/generic/Icons/ProjectIcon.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,18 @@ type ProjectIconProps = {
width?: number;
height?: number;
className?: string;
fill?: string;
};

export const ProjectIcon = ({
width = DEFAULT_WIDTH,
height = DEFAULT_HEIGHT,
className,
fill = 'fill-gray-600',
}: ProjectIconProps) => {
return (
<svg
className={cx('fill-gray-600', className)}
className={cx(className, fill)}
xmlns="http://www.w3.org/2000/svg"
width={width}
height={height}
Expand Down
4 changes: 3 additions & 1 deletion components/generic/Icons/TimelineIcon.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,18 @@ type TimelineIconProps = {
width?: number;
height?: number;
className?: string;
fill?: string;
};

export const TimelineIcon = ({
width = SMALL_WIDTH,
height = SMALL_HEIGHT,
className,
fill = 'fill-gray-600',
}: TimelineIconProps) => {
return (
<svg
className={cx('fill-gray-600', className)}
className={cx(fill, className)}
xmlns="http://www.w3.org/2000/svg"
width={width}
height={height}
Expand Down
2 changes: 2 additions & 0 deletions pages/index.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import type { NextPage } from 'next';
import Head from 'next/head';
import { HomePage } from '../components/composited/HomePage/HomePage';

import { MainLayout } from '../components/generic/MainLayout/MainLayout';

Expand All @@ -9,6 +10,7 @@ const Home: NextPage = () => {
<Head>
<title>Strona główna - My local circle</title>
</Head>
<HomePage />
</MainLayout>
);
};
Expand Down
Binary file added public/home-cover-secondary.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/home-cover.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions utils/formatDate.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export const formatDate = (dateInput: string | Date) => {
return new Date(dateInput).toLocaleDateString('pl-PL', { dateStyle: 'long' });
};
1 change: 0 additions & 1 deletion utils/str.ts

This file was deleted.

0 comments on commit 9eaac0f

Please sign in to comment.