Skip to content

Commit

Permalink
feature(website): support one-time donations (#623)
Browse files Browse the repository at this point in the history
  • Loading branch information
mkue authored Nov 13, 2023
1 parent 18ddde9 commit 7af0a31
Show file tree
Hide file tree
Showing 39 changed files with 551 additions and 256 deletions.
5 changes: 4 additions & 1 deletion shared/locales/de/website-home.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@
"title-2": "aus der Armut helfen?",
"title-3": "",
"income-text": "Gib dein monatliches Einkommen ein und schau, was du bewirken kannst.",
"button-text": "Beitrag berechnen"
"button-text": "Beitrag berechnen",
"privacy-commitment": "Wir verpflichten uns zum Datenschutz",
"tax-deductible": "Dein Beitrag ist in der Schweiz steuerbefreit",
"one-time-donation": "Make a one-time donation"
},
"section-2": {
"title-1": "Was würde sich in deinem Alltag ändern, ",
Expand Down
43 changes: 38 additions & 5 deletions shared/locales/de/website-me.json
Original file line number Diff line number Diff line change
@@ -1,19 +1,52 @@
{
"tabs": {
"contact-details": "Kontaktangaben",
"contributions": "Zuwendungen"
"sections": {
"account": {
"title": "My Account",
"personal-info": "Personal Info",
"security": "Security"
},
"contributions": {
"title": "My Contributions",
"payments": "Payments",
"subscriptions": "Subscriptions"
}
},
"contributions": {
"amount": "Betrag",
"amount": "Amount",
"date": "Date",
"source": "Source",
"total": "Total",
"amount-currency": "{{ amount, currency }}",
"date": "Datum"
"sources": {
"benevity": "Benevity",
"cash": "Cash",
"stripe": "Stripe",
"wire-transfer": "Wire Transfer"
}
},
"subscriptions": {
"amount": "Amount",
"date": "Date",
"source": "Source",
"total": "Total",
"amount-currency": "{{ amount, currency }}",
"interval": "Interval",
"interval-1": "Monatlich",
"interval-3": "Quartalsweise",
"interval-12": "Jährlich",
"status": {
"active": "Aktiv",
"canceled": "Beendet",
"paused": "Pausiert"
}
},
"login": {
"title": "Melde dich an",
"email": "E-Mail",
"invalid-email": "Ungültige E-Mail-Adresse",
"password": "Passwort",
"forgot-password": "Passwort vergessen?",
"sign-in-with-google": "Mit Google anmelden",
"required-field": "Dieses Feld ist erforderlich",
"submit-button": "Anmelden",
"unknown-user": "Es gibt keinen Benutzer mit dieser E-Mail-Adresse",
Expand Down
6 changes: 5 additions & 1 deletion shared/locales/en/website-home.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,11 @@
"title-2": "lift out of poverty ",
"title-3": "with 1% of your income?",
"income-text": "Enter your monthly income and calculate your impact.",
"button-text": "Show my Impact"
"amount": "Amount",
"button-text": "Show my Impact",
"privacy-commitment": "Our commitment to privacy",
"tax-deductible": "Contributions are tax-deductible in Switzerland",
"one-time-donation": "Make a one-time donation"
},
"section-2": {
"title-1": "What would change ",
Expand Down
1 change: 1 addition & 0 deletions shared/locales/en/website-me.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
"invalid-email": "Invalid email address",
"password": "Password",
"forgot-password": "Forgot password?",
"sign-in-with-google": "Sign in with Google",
"required-field": "This field is required",
"submit-button": "Sign in",
"unknown-user": "This user does not exist",
Expand Down
13 changes: 10 additions & 3 deletions ui/src/components/button.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { IconType } from '@icons-pack/react-simple-icons/types';
import { Slot } from '@radix-ui/react-slot';
import { cva, type VariantProps } from 'class-variance-authority';
import * as React from 'react';
Expand All @@ -18,7 +19,7 @@ const buttonVariants = cva(
size: {
default: 'h-10 px-4 py-2',
sm: 'h-9 rounded-md px-3',
lg: 'h-16 rounded-md px-8 font-semibold',
lg: 'h-16 rounded-md px-8 font-semibold text-lg',
icon: 'h-10 w-10',
},
},
Expand All @@ -33,12 +34,18 @@ export interface ButtonProps
extends React.ButtonHTMLAttributes<HTMLButtonElement>,
VariantProps<typeof buttonVariants> {
asChild?: boolean;
Icon?: IconType;
}

const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
({ className, variant, size, asChild = false, ...props }, ref) => {
({ className, variant, size, asChild = false, Icon, children, ...props }, ref) => {
const Comp = asChild ? Slot : 'button';
return <Comp className={cn(buttonVariants({ variant, size, className }))} ref={ref} {...props} />;
return (
<Comp className={cn(buttonVariants({ variant, size, className }))} ref={ref} {...props}>
{Icon && <Icon className={cn('h-4 w-4', { 'mr-2': size !== 'icon' })} />}
{children}
</Comp>
);
},
);
Button.displayName = 'Button';
Expand Down
13 changes: 10 additions & 3 deletions ui/src/components/form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import * as LabelPrimitive from '@radix-ui/react-label';
import { Slot } from '@radix-ui/react-slot';
import * as React from 'react';
import { Controller, ControllerProps, FieldPath, FieldValues, FormProvider, useFormContext } from 'react-hook-form';

import { cn } from '../lib/utils';
import { Label } from './label';

Expand Down Expand Up @@ -67,7 +66,7 @@ const FormItem = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivEl

return (
<FormItemContext.Provider value={{ id }}>
<div ref={ref} className={cn('space-y-2', className)} {...props} />
<div ref={ref} className={cn('space-y-1', className)} {...props} />
</FormItemContext.Provider>
);
},
Expand Down Expand Up @@ -120,7 +119,15 @@ const FormMessage = React.forwardRef<HTMLParagraphElement, React.HTMLAttributes<
}

return (
<p ref={ref} id={formMessageId} className={cn('text-destructive text-sm font-medium', className)} {...props}>
<p
ref={ref}
id={formMessageId}
className={cn(
'text-destructive-foreground bg-destructive ml-1 rounded px-2 py-1 text-sm font-medium',
className,
)}
{...props}
>
{body}
</p>
);
Expand Down
2 changes: 1 addition & 1 deletion ui/src/components/input.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ const Input = React.forwardRef<HTMLInputElement, InputProps>(({ className, type,
<input
type={type}
className={cn(
'border-input bg-popover ring-offset-background placeholder:text-muted-foreground focus-visible:ring-ring flex h-10 w-full rounded-md border px-3 py-2 text-sm file:border-0 file:bg-transparent file:text-sm file:font-medium focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50',
'border-input bg-popover text-popover-foreground ring-offset-background placeholder:text-popover-foreground focus-visible:ring-ring flex h-10 w-full rounded-md border px-3 py-2 text-sm file:border-0 file:bg-transparent file:text-sm file:font-medium focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50',
className,
)}
ref={ref}
Expand Down
4 changes: 2 additions & 2 deletions ui/src/components/select.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ const SelectTrigger = React.forwardRef<
<SelectPrimitive.Trigger
ref={ref}
className={cn(
'border-input bg-popover ring-offset-background placeholder:text-muted-foreground focus:ring-ring flex h-10 w-full items-center justify-between rounded-md border px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50',
'border-input bg-popover text-popover-foreground ring-offset-background focus:ring-ring flex h-10 w-full items-center justify-between rounded-md border px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50',
className,
)}
{...props}
Expand Down Expand Up @@ -76,7 +76,7 @@ const SelectItem = React.forwardRef<
<SelectPrimitive.Item
ref={ref}
className={cn(
'focus:bg-accent focus:text-accent-foreground relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50',
'focus:bg-popover focus:text-popover-foreground relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50',
className,
)}
{...props}
Expand Down
30 changes: 3 additions & 27 deletions ui/src/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
--card-foreground: hsl(20 14.3% 4.1%);

--popover: hsl(0 100% 100%);
--popover-foreground: hsl(20 14.3% 4.1%);
--popover-foreground: hsl(0, 0%, 40%);

--primary: hsl(216, 54%, 55%);
--primary-foreground: hsl(60 9.1% 97.8%);
Expand Down Expand Up @@ -46,32 +46,8 @@
--background: hsl(216, 54%, 55%);
--foreground: hsl(60 9.1% 97.8%);

--card: hsl(0 0% 100%);
--card-foreground: hsl(20 14.3% 4.1%);

--popover: hsl(216, 54%, 55%);
--popover-foreground: hsl(60 9.1% 97.8%);

--primary: hsl(60 9.1% 97.8%);
--primary-foreground: hsl(216, 54%, 55%);

--secondary: hsl(8, 89%, 62%);
--secondary-foreground: hsl(240, 2%, 21%);

--muted: hsl(60 4.8% 95.9%);
--muted-foreground: hsl(25 5.3% 44.7%);

--accent: hsl(216, 54%, 60%);
--accent-foreground: hsl(60 9.1% 97.8%);

--destructive: hsl(0, 75%, 42%);
--destructive-foreground: hsl(60 9.1% 97.8%);

--border: hsl(20 5.9% 90%);
--input: hsl(20 5.9% 90%);
--ring: hsl(216, 54%, 55%);

--radius: 0.5rem;
--primary: hsl(48, 100%, 49%);
--primary-foreground: hsl(0, 0%, 20%);
}
}

Expand Down
42 changes: 32 additions & 10 deletions website/src/app/[lang]/[region]/(website)/(home)/section-1-form.tsx
Original file line number Diff line number Diff line change
@@ -1,24 +1,30 @@
'use client';

import { DefaultParams } from '@/app/[lang]/[region]';
import { CurrencySelector } from '@/components/ui/currency-selector';
import { websiteCurrencies } from '@/i18n';
import { EyeSlashIcon } from '@heroicons/react/24/outline';
import { CheckIcon } from '@heroicons/react/24/solid';
import { zodResolver } from '@hookform/resolvers/zod';
import { Button, Form, FormControl, FormField, FormItem, Input, Typography } from '@socialincome/ui';
import Link from 'next/link';
import { useRouter } from 'next/navigation';
import { useForm } from 'react-hook-form';
import * as z from 'zod';

interface Section1InputProps {
type Section1InputProps = {
translations: {
text: string;
// amount: string;
amount: string;
submit: string;
currency: string;
privacyCommitment: string;
taxDeductible: string;
oneTimeDonation: string;
};
}
} & DefaultParams;

// TODO: i18n
export default function Section1Form({ translations }: Section1InputProps) {
export default function Section1Form({ translations, lang, region }: Section1InputProps) {
const router = useRouter();

const formSchema = z.object({
Expand All @@ -36,29 +42,45 @@ export default function Section1Form({ translations }: Section1InputProps) {
};

return (
<div className="flex flex-col space-y-8 text-center sm:text-left">
<div className="flex flex-col space-y-8 sm:text-left">
<Typography size="2xl">{translations.text}</Typography>
<Form {...form}>
<form onSubmit={form.handleSubmit(onSubmit)} className="flex flex-col space-y-8">
<div className="flex flex-col space-y-4 sm:flex-row sm:space-x-4 sm:space-y-0 md:items-center">
<form onSubmit={form.handleSubmit(onSubmit)} className="flex flex-col space-y-2">
<div className="mb-2 flex flex-col space-y-4 sm:flex-row sm:space-x-4 sm:space-y-0 md:items-center">
<FormField
control={form.control}
name="amount"
render={({ field }) => (
<FormItem className="sm:basis-2/3">
<FormControl>
<Input className="h-16 text-lg" placeholder="Amount" {...field} />
<Input className="h-16 text-lg" placeholder={translations.amount} {...field} />
</FormControl>
</FormItem>
)}
/>
<CurrencySelector className="h-16 sm:flex-1" currencies={websiteCurrencies} fontSize="lg" />
<CurrencySelector className="h-16 w-full sm:flex-1" currencies={websiteCurrencies} fontSize="lg" />
</div>
<Button size="lg" type="submit" variant="default" className="text-lg">
{translations.submit}
</Button>
<Link href={`/${lang}/${region}/privacy`} className="inline-flex items-center pt-2 hover:underline">
<EyeSlashIcon className="mr-2 h-4 w-4" />
<Typography size="sm">{translations.privacyCommitment}</Typography>
</Link>
{region === 'ch' && (
<div className="inline-flex items-center">
<CheckIcon className="mr-2 h-4 w-4" />
<Typography size="sm">{translations.taxDeductible}</Typography>
</div>
)}
</form>
</Form>
<div className="flex flex-row">
<div className="flex-1" />
<Link href={`/${lang}/${region}/donate/one-time`}>
<Button variant="link">{translations.oneTimeDonation}</Button>
</Link>
</div>
</div>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export default async function Section1({ params }: DefaultPageProps) {
return (
<BaseContainer
backgroundColor="bg-blue-50"
className="grid min-h-[calc(100vh-theme(spacing.20))] grid-cols-1 content-center items-center gap-y-8 lg:grid-cols-2"
className="min-h-screen-navbar grid grid-cols-1 content-center items-center gap-y-8 lg:grid-cols-2"
>
<div className="mx-auto max-w-3xl">
<Typography size="5xl" weight="bold" lineHeight="tight">
Expand All @@ -25,10 +25,16 @@ export default async function Section1({ params }: DefaultPageProps) {
</div>
<div className="mx-auto max-w-2xl">
<Section1Form
lang={params.lang}
region={params.region}
translations={{
text: translator.t('section-1.income-text'),
currency: translator.t('currency'),
amount: translator.t('section-1.amount'),
submit: translator.t('section-1.button-text'),
privacyCommitment: translator.t('section-1.privacy-commitment'),
taxDeductible: translator.t('section-1.tax-deductible'),
oneTimeDonation: translator.t('section-1.one-time-donation'),
}}
/>
</div>
Expand Down

This file was deleted.

Loading

0 comments on commit 7af0a31

Please sign in to comment.