Skip to content

Commit

Permalink
feat(components): first commit
Browse files Browse the repository at this point in the history
  • Loading branch information
Jiri Kolarik committed Feb 4, 2022
0 parents commit 26703f3
Show file tree
Hide file tree
Showing 106 changed files with 76,521 additions and 0 deletions.
27 changes: 27 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
name: Release
on:
push:
branches:
- master
jobs:
release:
name: Release
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
with:
fetch-depth: 0
- name: Setup Node.js
uses: actions/setup-node@v2
with:
node-version: "lts/*"
- name: Install dependencies
run: npm ci
- name: Test
run: npm run build
- name: Release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
NPM_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: npx semantic-release
25 changes: 25 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

# dependencies
/node_modules
/.pnp
.pnp.js

# testing
/coverage

# production
/build
/dist
/**/dist

# misc
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local

npm-debug.log*
yarn-debug.log*
yarn-error.log*
187 changes: 187 additions & 0 deletions .legacy/avatar/avatar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,187 @@
import { captureEvent } from "@sentry/react";
import { Slider } from "baseui/slider";
import { useSnackbar } from "baseui/snackbar";
import { useField, useFormikContext } from "formik";
import { useRef, useState } from "react";
import AvatarEditor from "react-avatar-editor";
import Dropzone from "react-dropzone";
import * as Icons from "react-feather";
import { useTranslation } from "react-i18next";
import { useStyletron } from "styletron-react";
import { borderRadius } from ".././utils/css";
import Button, { ButtonAppearance } from "../button/button";
import { upload } from "../form/image-uploader-field-form";

const { REACT_APP_API: API = "" } = process.env;
const prefix = process.env.NODE_ENV !== "production" ? "_dev/" : "";

const imageUploadUrl = (scope: string) =>
`${API}/upload/image?scope=${prefix}${scope}`;

export default function AvatarField(props: { name: string }) {
const [submitting, setSubmitting] = useState(false);
const [editMode, setEditMode] = useState(false);
const [img, setImg] = useState<any>();
const { submitForm } = useFormikContext();
const editor = useRef<AvatarEditor | null>(null);
const [{ value }, , { setValue }] = useField(props.name);
const [css] = useStyletron();
const [scale, setScale] = useState([1]);
const [t] = useTranslation();
const { enqueue } = useSnackbar();

const onSend = async () => {
try {
if (editor.current) {
setSubmitting(true);
const payload = new FormData();

const canvas = editor.current.getImage().toDataURL();
const response = await fetch(canvas);
const blob = await response.blob();

payload.append("file", blob);

const {
data: { url },
} = await upload(imageUploadUrl("account"), payload);

if (url) {
setValue(url);
setEditMode(false);
submitForm();
} else {
throw "URL not specified";
}
}
} catch (error: any) {
setSubmitting(false);
enqueue({
startEnhancer: () => <Icons.AlertTriangle />,
message: t("exp.save.error"),
});
captureEvent(error);
}
};

if (editMode) {
return (
<div
className={css({
display: "flex",
justifyContent: "center",
alignItems: "center",
})}
>
<div>
<AvatarEditor
ref={editor}
width={180}
height={180}
image={img}
border={20}
borderRadius={180}
style={{
background: "white",
}}
scale={scale[0]}
/>
<Slider
min={1}
max={2}
step={0.05}
value={scale}
onChange={({ value: scaleValue }) =>
scaleValue && setScale(scaleValue)
}
/>
<div
className={css({
display: "flex",
gap: "0.5rem",
})}
>
<Button
onClick={() => setEditMode(false)}
appearance={ButtonAppearance.secondary}
>
{t("exp.cancel")}
</Button>
<Button
isLoading={submitting}
disabled={submitting}
onClick={onSend}
appearance={ButtonAppearance.primary}
style={{
flexGrow: 1,
}}
>
{t("exp.submit")}
</Button>
</div>
</div>
</div>
);
}

return (
<div
className={css({
display: "flex",
justifyContent: "center",
alignItems: "center",
height: "200px",
})}
>
<Dropzone
multiple={false}
accept="image/*"
onDrop={([item]) => {
setImg(item);
setEditMode(true);
}}
>
{({ getRootProps, getInputProps }) => (
<div
{...getRootProps()}
className={css({
position: "relative",
display: "flex",
border: "black 2px dotted",
height: "200px",
width: "200px",
...borderRadius("100%"),
})}
>
<input {...getInputProps()} />
<img
src={value}
className={css({
borderRadius: "100%",
width: "100%",
height: "100%",
})}
/>
<div
className={css({
position: "absolute",
bottom: 0,
left: 0,
right: 0,
padding: "0.5rem",
background: "var(--black-80)",
color: "white",
display: "flex",
justifyContent: "center",
alignItems: "center",
textAlign: "center",
})}
>
{t("avatar.click-or-drop-to-upload")}
</div>
</div>
)}
</Dropzone>
</div>
);
}
150 changes: 150 additions & 0 deletions .legacy/calendar/calendar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
import {
END_DATE,
FocusedInput,
OnDatesChangeProps,
START_DATE,
useDatepicker,
} from "@datepicker-react/hooks";
import { endOfMonth, startOfMonth } from "date-fns/esm";
import React, { ReactNode, useEffect, useState } from "react";
import { StyleObject, useStyletron } from "styletron-react";
import CalendarMonth from "./month";
import CalendarContext, { DayOverrides } from "./provider";

interface Interval {
start?: Date;
end?: Date;
}

export interface CalendarProps {
date: Interval;
onChange?: (
{ start, end }: Interval,
focusedInput?: typeof START_DATE | typeof END_DATE | null
) => void;
onVisibleMonthsRangeChange?: ({ start, end }: Interval) => void;
unavailableDates?: Date[];
minBookingDays?: number;
overrides?: {
Day?: {
style: (params: DayOverrides) => StyleObject;
};
};
isDateBlocked?: (day: Date) => boolean;
isDateUnselectable?: (day: Date) => boolean;
numberOfMonths?: number;
dayRenderer?: (params: { date: Date }) => ReactNode;
initialVisibleMonth?: Date;
}

export default function Calendar(props: CalendarProps) {
const [focus, setFocus] = useState<FocusedInput>(START_DATE);
const [css] = useStyletron();

function handleDateChange(params: OnDatesChangeProps) {
setFocus(params.focusedInput || START_DATE);
const end = focus === START_DATE ? undefined : params.endDate;

props.onChange &&
props.onChange(
{
start: params.startDate || undefined,
end: end || undefined,
},
params.focusedInput
);
}

const startDate = props.date.start || null;
const endDate = props.date.end || null;
const minBookingDays = props.minBookingDays || 1;

const {
firstDayOfWeek,
activeMonths,
isDateSelected,
isDateHovered,
isFirstOrLastSelectedDate,
isDateFocused,
isDateBlocked,
focusedDate,
onDateHover,
onDateSelect,
onDateFocus,
goToPreviousMonths,
goToNextMonths,
onResetDates,
} = useDatepicker({
initialVisibleMonth: props.initialVisibleMonth,
isDateBlocked: props.isDateBlocked,
startDate,
endDate,
focusedInput: focus,
onDatesChange: handleDateChange,
numberOfMonths: props.numberOfMonths || 1,
unavailableDates: props.unavailableDates,
minBookingDays,
firstDayOfWeek: 1,
minBookingDate: new Date(),
});

const { onVisibleMonthsRangeChange } = props;
useEffect(() => {
if (onVisibleMonthsRangeChange) {
const nrOfMonths = activeMonths.length;
onVisibleMonthsRangeChange({
start: startOfMonth(activeMonths[0].date),
end: endOfMonth(activeMonths[nrOfMonths - 1].date),
});
}
}, [activeMonths]);

const isDateUnselectable = props.isDateUnselectable
? props.isDateUnselectable
: () => false;

return (
<CalendarContext.Provider
value={{
startDate,
endDate,
focusedDate,
isDateFocused,
isDateSelected,
isDateHovered,
isDateBlocked,
isFirstOrLastSelectedDate,
onDateFocus,
onDateSelect,
onDateHover,
onResetDates,
overrides: props.overrides,
dayRenderer: props.dayRenderer,
goToPreviousMonths,
goToNextMonths,
minBookingDays,
isDateUnselectable,
}}
>
<div
className={css({
display: "grid",
gridTemplateColumns: `repeat(${activeMonths.length}, 1fr)`,
gridGap: "0 2rem",
paddingRight: "1px",
})}
>
{activeMonths.map((month, i) => (
<CalendarMonth
key={`${month.year}-${month.month}`}
year={month.year}
month={month.month}
firstDayOfWeek={firstDayOfWeek}
showLeftArrow={i === 0}
showRightArrow={activeMonths.length - 1 === i}
/>
))}
</div>
</CalendarContext.Provider>
);
}
Loading

0 comments on commit 26703f3

Please sign in to comment.