├── .env.example ├── .eslintignore ├── .eslintrc.js ├── .gitignore ├── .husky ├── .gitignore └── pre-commit ├── .prettierignore ├── .prettierrc ├── .storybook ├── main.js └── preview.js ├── .vscode ├── extensions.json └── settings.json ├── LICENSE ├── README.md ├── code-stages ├── chapter-02 │ └── src │ │ ├── components │ │ └── .gitkeep │ │ ├── config │ │ ├── constants.ts │ │ └── theme.ts │ │ ├── features │ │ ├── auth │ │ │ ├── api │ │ │ │ └── .gitkeep │ │ │ ├── components │ │ │ │ └── .gitkeep │ │ │ ├── index.ts │ │ │ ├── pages │ │ │ │ └── .gitkeep │ │ │ └── types │ │ │ │ └── index.ts │ │ ├── jobs │ │ │ ├── api │ │ │ │ └── .gitkeep │ │ │ ├── components │ │ │ │ └── .gitkeep │ │ │ ├── index.ts │ │ │ ├── pages │ │ │ │ └── .gitkeep │ │ │ └── types │ │ │ │ └── index.ts │ │ └── organizations │ │ │ ├── api │ │ │ └── .gitkeep │ │ │ ├── index.ts │ │ │ ├── pages │ │ │ └── .gitkeep │ │ │ └── types │ │ │ └── index.ts │ │ ├── layouts │ │ └── .gitkeep │ │ ├── lib │ │ └── .gitkeep │ │ ├── pages │ │ ├── _app.tsx │ │ └── index.tsx │ │ ├── providers │ │ └── app.tsx │ │ ├── stores │ │ └── .gitkeep │ │ ├── testing │ │ └── .gitkeep │ │ ├── types │ │ └── index.ts │ │ └── utils │ │ ├── format.ts │ │ └── uid.ts ├── chapter-03-start │ └── src │ │ ├── components │ │ ├── button │ │ │ ├── button.tsx │ │ │ └── index.ts │ │ ├── form │ │ │ ├── index.ts │ │ │ └── input-field.tsx │ │ └── link │ │ │ ├── index.ts │ │ │ └── link.tsx │ │ ├── config │ │ ├── constants.ts │ │ └── theme.ts │ │ ├── features │ │ ├── auth │ │ │ ├── api │ │ │ │ └── .gitkeep │ │ │ ├── components │ │ │ │ └── .gitkeep │ │ │ ├── index.ts │ │ │ ├── pages │ │ │ │ └── .gitkeep │ │ │ └── types │ │ │ │ └── index.ts │ │ ├── jobs │ │ │ ├── api │ │ │ │ └── .gitkeep │ │ │ ├── components │ │ │ │ └── .gitkeep │ │ │ ├── index.ts │ │ │ ├── pages │ │ │ │ └── .gitkeep │ │ │ └── types │ │ │ │ └── index.ts │ │ └── organizations │ │ │ ├── api │ │ │ └── .gitkeep │ │ │ ├── index.ts │ │ │ ├── pages │ │ │ └── .gitkeep │ │ │ └── types │ │ │ └── index.ts │ │ ├── layouts │ │ └── .gitkeep │ │ ├── lib │ │ └── .gitkeep │ │ ├── pages │ │ ├── _app.tsx │ │ └── index.tsx │ │ ├── providers │ │ └── app.tsx │ │ ├── stores │ │ └── .gitkeep │ │ ├── testing │ │ └── .gitkeep │ │ ├── types │ │ └── index.ts │ │ └── utils │ │ ├── format.ts │ │ └── uid.ts ├── chapter-03 │ └── src │ │ ├── components │ │ ├── button │ │ │ ├── button.stories.tsx │ │ │ ├── button.tsx │ │ │ └── index.ts │ │ ├── form │ │ │ ├── index.ts │ │ │ ├── input-field.stories.tsx │ │ │ └── input-field.tsx │ │ └── link │ │ │ ├── index.ts │ │ │ ├── link.stories.tsx │ │ │ └── link.tsx │ │ ├── config │ │ ├── constants.ts │ │ └── theme.ts │ │ ├── features │ │ ├── auth │ │ │ ├── api │ │ │ │ └── .gitkeep │ │ │ ├── components │ │ │ │ └── .gitkeep │ │ │ ├── index.ts │ │ │ ├── pages │ │ │ │ └── .gitkeep │ │ │ └── types │ │ │ │ └── index.ts │ │ ├── jobs │ │ │ ├── api │ │ │ │ └── .gitkeep │ │ │ ├── components │ │ │ │ └── .gitkeep │ │ │ ├── index.ts │ │ │ ├── pages │ │ │ │ └── .gitkeep │ │ │ └── types │ │ │ │ └── index.ts │ │ └── organizations │ │ │ ├── api │ │ │ └── .gitkeep │ │ │ ├── index.ts │ │ │ ├── pages │ │ │ └── .gitkeep │ │ │ └── types │ │ │ └── index.ts │ │ ├── layouts │ │ └── .gitkeep │ │ ├── lib │ │ └── .gitkeep │ │ ├── pages │ │ ├── _app.tsx │ │ └── index.tsx │ │ ├── providers │ │ └── app.tsx │ │ ├── stores │ │ └── .gitkeep │ │ ├── testing │ │ └── .gitkeep │ │ ├── types │ │ └── index.ts │ │ └── utils │ │ ├── format.ts │ │ └── uid.ts ├── chapter-04-start │ └── src │ │ ├── components │ │ ├── button │ │ │ ├── button.stories.tsx │ │ │ ├── button.tsx │ │ │ └── index.ts │ │ ├── content │ │ │ ├── content.stories.tsx │ │ │ ├── content.tsx │ │ │ └── index.ts │ │ ├── data-table │ │ │ ├── data-table.stories.tsx │ │ │ ├── data-table.tsx │ │ │ └── index.ts │ │ ├── form │ │ │ ├── index.ts │ │ │ ├── input-field.stories.tsx │ │ │ └── input-field.tsx │ │ ├── info-card │ │ │ ├── index.ts │ │ │ ├── info-card.stories.tsx │ │ │ └── info-card.tsx │ │ ├── link │ │ │ ├── index.ts │ │ │ ├── link.stories.tsx │ │ │ └── link.tsx │ │ ├── loading │ │ │ ├── index.ts │ │ │ ├── loading.stories.tsx │ │ │ └── loading.tsx │ │ ├── not-found │ │ │ ├── index.ts │ │ │ ├── not-found.stories.tsx │ │ │ └── not-found.tsx │ │ └── seo │ │ │ ├── index.ts │ │ │ └── seo.tsx │ │ ├── config │ │ ├── constants.ts │ │ └── theme.ts │ │ ├── features │ │ ├── auth │ │ │ ├── api │ │ │ │ └── .gitkeep │ │ │ ├── components │ │ │ │ └── .gitkeep │ │ │ ├── index.ts │ │ │ └── types │ │ │ │ └── index.ts │ │ ├── jobs │ │ │ ├── api │ │ │ │ └── .gitkeep │ │ │ ├── components │ │ │ │ ├── create-job-form │ │ │ │ │ ├── create-job-form.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── dashboard-job-info │ │ │ │ │ ├── dashboard-job-info.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── jobs-list │ │ │ │ │ ├── index.ts │ │ │ │ │ └── jobs-list.tsx │ │ │ │ └── public-job-info │ │ │ │ │ ├── index.ts │ │ │ │ │ └── public-job-info.tsx │ │ │ ├── index.ts │ │ │ └── types │ │ │ │ └── index.ts │ │ └── organizations │ │ │ ├── api │ │ │ └── .gitkeep │ │ │ ├── components │ │ │ └── organization-info │ │ │ │ ├── index.ts │ │ │ │ └── organization-info.tsx │ │ │ ├── index.ts │ │ │ └── types │ │ │ └── index.ts │ │ ├── layouts │ │ ├── dashboard-layout.tsx │ │ └── public-layout.tsx │ │ ├── lib │ │ └── .gitkeep │ │ ├── pages │ │ ├── _app.tsx │ │ └── index.tsx │ │ ├── providers │ │ └── app.tsx │ │ ├── stores │ │ └── .gitkeep │ │ ├── testing │ │ └── test-data.ts │ │ ├── types │ │ └── index.ts │ │ └── utils │ │ ├── format.ts │ │ └── uid.ts ├── chapter-04 │ └── src │ │ ├── components │ │ ├── button │ │ │ ├── button.stories.tsx │ │ │ ├── button.tsx │ │ │ └── index.ts │ │ ├── content │ │ │ ├── content.stories.tsx │ │ │ ├── content.tsx │ │ │ └── index.ts │ │ ├── data-table │ │ │ ├── data-table.stories.tsx │ │ │ ├── data-table.tsx │ │ │ └── index.ts │ │ ├── form │ │ │ ├── index.ts │ │ │ ├── input-field.stories.tsx │ │ │ └── input-field.tsx │ │ ├── info-card │ │ │ ├── index.ts │ │ │ ├── info-card.stories.tsx │ │ │ └── info-card.tsx │ │ ├── link │ │ │ ├── index.ts │ │ │ ├── link.stories.tsx │ │ │ └── link.tsx │ │ ├── loading │ │ │ ├── index.ts │ │ │ ├── loading.stories.tsx │ │ │ └── loading.tsx │ │ ├── not-found │ │ │ ├── index.ts │ │ │ ├── not-found.stories.tsx │ │ │ └── not-found.tsx │ │ └── seo │ │ │ ├── index.ts │ │ │ └── seo.tsx │ │ ├── config │ │ ├── constants.ts │ │ └── theme.ts │ │ ├── features │ │ ├── auth │ │ │ ├── api │ │ │ │ └── .gitkeep │ │ │ ├── components │ │ │ │ └── .gitkeep │ │ │ ├── index.ts │ │ │ └── types │ │ │ │ └── index.ts │ │ ├── jobs │ │ │ ├── api │ │ │ │ └── .gitkeep │ │ │ ├── components │ │ │ │ ├── create-job-form │ │ │ │ │ ├── create-job-form.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── dashboard-job-info │ │ │ │ │ ├── dashboard-job-info.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── jobs-list │ │ │ │ │ ├── index.ts │ │ │ │ │ └── jobs-list.tsx │ │ │ │ └── public-job-info │ │ │ │ │ ├── index.ts │ │ │ │ │ └── public-job-info.tsx │ │ │ ├── index.ts │ │ │ └── types │ │ │ │ └── index.ts │ │ └── organizations │ │ │ ├── api │ │ │ └── .gitkeep │ │ │ ├── components │ │ │ └── organization-info │ │ │ │ ├── index.ts │ │ │ │ └── organization-info.tsx │ │ │ ├── index.ts │ │ │ └── types │ │ │ └── index.ts │ │ ├── layouts │ │ ├── dashboard-layout.tsx │ │ └── public-layout.tsx │ │ ├── lib │ │ └── .gitkeep │ │ ├── pages │ │ ├── 404.tsx │ │ ├── _app.tsx │ │ ├── dashboard │ │ │ └── jobs │ │ │ │ ├── [jobId].tsx │ │ │ │ ├── create.tsx │ │ │ │ └── index.tsx │ │ ├── index.tsx │ │ └── organizations │ │ │ └── [organizationId] │ │ │ ├── index.tsx │ │ │ └── jobs │ │ │ └── [jobId].tsx │ │ ├── providers │ │ └── app.tsx │ │ ├── stores │ │ └── .gitkeep │ │ ├── testing │ │ └── test-data.ts │ │ ├── types │ │ └── index.ts │ │ └── utils │ │ ├── format.ts │ │ └── uid.ts ├── chapter-05-start │ └── src │ │ ├── components │ │ ├── button │ │ │ ├── button.stories.tsx │ │ │ ├── button.tsx │ │ │ └── index.ts │ │ ├── content │ │ │ ├── content.stories.tsx │ │ │ ├── content.tsx │ │ │ └── index.ts │ │ ├── data-table │ │ │ ├── data-table.stories.tsx │ │ │ ├── data-table.tsx │ │ │ └── index.ts │ │ ├── form │ │ │ ├── index.ts │ │ │ ├── input-field.stories.tsx │ │ │ └── input-field.tsx │ │ ├── info-card │ │ │ ├── index.ts │ │ │ ├── info-card.stories.tsx │ │ │ └── info-card.tsx │ │ ├── link │ │ │ ├── index.ts │ │ │ ├── link.stories.tsx │ │ │ └── link.tsx │ │ ├── loading │ │ │ ├── index.ts │ │ │ ├── loading.stories.tsx │ │ │ └── loading.tsx │ │ ├── not-found │ │ │ ├── index.ts │ │ │ ├── not-found.stories.tsx │ │ │ └── not-found.tsx │ │ └── seo │ │ │ ├── index.ts │ │ │ └── seo.tsx │ │ ├── config │ │ ├── constants.ts │ │ └── theme.ts │ │ ├── features │ │ ├── auth │ │ │ ├── api │ │ │ │ └── .gitkeep │ │ │ ├── components │ │ │ │ └── .gitkeep │ │ │ ├── index.ts │ │ │ └── types │ │ │ │ └── index.ts │ │ ├── jobs │ │ │ ├── api │ │ │ │ └── .gitkeep │ │ │ ├── components │ │ │ │ ├── create-job-form │ │ │ │ │ ├── create-job-form.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── dashboard-job-info │ │ │ │ │ ├── dashboard-job-info.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── jobs-list │ │ │ │ │ ├── index.ts │ │ │ │ │ └── jobs-list.tsx │ │ │ │ └── public-job-info │ │ │ │ │ ├── index.ts │ │ │ │ │ └── public-job-info.tsx │ │ │ ├── index.ts │ │ │ └── types │ │ │ │ └── index.ts │ │ └── organizations │ │ │ ├── api │ │ │ └── .gitkeep │ │ │ ├── components │ │ │ └── organization-info │ │ │ │ ├── index.ts │ │ │ │ └── organization-info.tsx │ │ │ ├── index.ts │ │ │ └── types │ │ │ └── index.ts │ │ ├── layouts │ │ ├── dashboard-layout.tsx │ │ └── public-layout.tsx │ │ ├── pages │ │ ├── 404.tsx │ │ ├── _app.tsx │ │ ├── dashboard │ │ │ └── jobs │ │ │ │ ├── [jobId].tsx │ │ │ │ ├── create.tsx │ │ │ │ └── index.tsx │ │ ├── index.tsx │ │ └── organizations │ │ │ └── [organizationId] │ │ │ ├── index.tsx │ │ │ └── jobs │ │ │ └── [jobId].tsx │ │ ├── providers │ │ └── app.tsx │ │ ├── stores │ │ └── .gitkeep │ │ ├── testing │ │ ├── mocks │ │ │ ├── browser.ts │ │ │ ├── db.ts │ │ │ ├── handlers │ │ │ │ ├── auth.ts │ │ │ │ ├── index.ts │ │ │ │ ├── jobs.ts │ │ │ │ └── organizations.ts │ │ │ ├── index.ts │ │ │ ├── initialize.ts │ │ │ ├── seed-db.ts │ │ │ ├── server.ts │ │ │ └── utils.ts │ │ └── test-data.ts │ │ ├── types │ │ └── index.ts │ │ └── utils │ │ ├── format.ts │ │ └── uid.ts ├── chapter-05 │ └── src │ │ ├── components │ │ ├── button │ │ │ ├── button.stories.tsx │ │ │ ├── button.tsx │ │ │ └── index.ts │ │ ├── content │ │ │ ├── content.stories.tsx │ │ │ ├── content.tsx │ │ │ └── index.ts │ │ ├── data-table │ │ │ ├── data-table.stories.tsx │ │ │ ├── data-table.tsx │ │ │ └── index.ts │ │ ├── form │ │ │ ├── index.ts │ │ │ ├── input-field.stories.tsx │ │ │ └── input-field.tsx │ │ ├── info-card │ │ │ ├── index.ts │ │ │ ├── info-card.stories.tsx │ │ │ └── info-card.tsx │ │ ├── link │ │ │ ├── index.ts │ │ │ ├── link.stories.tsx │ │ │ └── link.tsx │ │ ├── loading │ │ │ ├── index.ts │ │ │ ├── loading.stories.tsx │ │ │ └── loading.tsx │ │ ├── not-found │ │ │ ├── index.ts │ │ │ ├── not-found.stories.tsx │ │ │ └── not-found.tsx │ │ └── seo │ │ │ ├── index.ts │ │ │ └── seo.tsx │ │ ├── config │ │ ├── constants.ts │ │ └── theme.ts │ │ ├── features │ │ ├── auth │ │ │ ├── api │ │ │ │ └── .gitkeep │ │ │ ├── components │ │ │ │ └── .gitkeep │ │ │ ├── index.ts │ │ │ └── types │ │ │ │ └── index.ts │ │ ├── jobs │ │ │ ├── api │ │ │ │ └── .gitkeep │ │ │ ├── components │ │ │ │ ├── create-job-form │ │ │ │ │ ├── create-job-form.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── dashboard-job-info │ │ │ │ │ ├── dashboard-job-info.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── jobs-list │ │ │ │ │ ├── index.ts │ │ │ │ │ └── jobs-list.tsx │ │ │ │ └── public-job-info │ │ │ │ │ ├── index.ts │ │ │ │ │ └── public-job-info.tsx │ │ │ ├── index.ts │ │ │ └── types │ │ │ │ └── index.ts │ │ └── organizations │ │ │ ├── api │ │ │ └── .gitkeep │ │ │ ├── components │ │ │ └── organization-info │ │ │ │ ├── index.ts │ │ │ │ └── organization-info.tsx │ │ │ ├── index.ts │ │ │ └── types │ │ │ └── index.ts │ │ ├── layouts │ │ ├── dashboard-layout.tsx │ │ └── public-layout.tsx │ │ ├── lib │ │ └── msw.tsx │ │ ├── pages │ │ ├── 404.tsx │ │ ├── _app.tsx │ │ ├── dashboard │ │ │ └── jobs │ │ │ │ ├── [jobId].tsx │ │ │ │ ├── create.tsx │ │ │ │ └── index.tsx │ │ ├── index.tsx │ │ └── organizations │ │ │ └── [organizationId] │ │ │ ├── index.tsx │ │ │ └── jobs │ │ │ └── [jobId].tsx │ │ ├── providers │ │ └── app.tsx │ │ ├── stores │ │ └── .gitkeep │ │ ├── testing │ │ ├── mocks │ │ │ ├── browser.ts │ │ │ ├── db.ts │ │ │ ├── handlers │ │ │ │ ├── auth.ts │ │ │ │ ├── index.ts │ │ │ │ ├── jobs.ts │ │ │ │ └── organizations.ts │ │ │ ├── index.ts │ │ │ ├── initialize.ts │ │ │ ├── seed-db.ts │ │ │ ├── server.ts │ │ │ └── utils.ts │ │ └── test-data.ts │ │ ├── types │ │ └── index.ts │ │ └── utils │ │ ├── format.ts │ │ └── uid.ts ├── chapter-06-start │ └── src │ │ ├── components │ │ ├── button │ │ │ ├── button.stories.tsx │ │ │ ├── button.tsx │ │ │ └── index.ts │ │ ├── content │ │ │ ├── content.stories.tsx │ │ │ ├── content.tsx │ │ │ └── index.ts │ │ ├── data-table │ │ │ ├── data-table.stories.tsx │ │ │ ├── data-table.tsx │ │ │ └── index.ts │ │ ├── form │ │ │ ├── index.ts │ │ │ ├── input-field.stories.tsx │ │ │ └── input-field.tsx │ │ ├── info-card │ │ │ ├── index.ts │ │ │ ├── info-card.stories.tsx │ │ │ └── info-card.tsx │ │ ├── link │ │ │ ├── index.ts │ │ │ ├── link.stories.tsx │ │ │ └── link.tsx │ │ ├── loading │ │ │ ├── index.ts │ │ │ ├── loading.stories.tsx │ │ │ └── loading.tsx │ │ ├── not-found │ │ │ ├── index.ts │ │ │ ├── not-found.stories.tsx │ │ │ └── not-found.tsx │ │ └── seo │ │ │ ├── index.ts │ │ │ └── seo.tsx │ │ ├── config │ │ ├── constants.ts │ │ └── theme.ts │ │ ├── features │ │ ├── auth │ │ │ ├── api │ │ │ │ └── .gitkeep │ │ │ ├── components │ │ │ │ └── .gitkeep │ │ │ ├── index.ts │ │ │ └── types │ │ │ │ └── index.ts │ │ ├── jobs │ │ │ ├── api │ │ │ │ └── .gitkeep │ │ │ ├── components │ │ │ │ ├── create-job-form │ │ │ │ │ ├── create-job-form.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── dashboard-job-info │ │ │ │ │ ├── dashboard-job-info.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── jobs-list │ │ │ │ │ ├── index.ts │ │ │ │ │ └── jobs-list.tsx │ │ │ │ └── public-job-info │ │ │ │ │ ├── index.ts │ │ │ │ │ └── public-job-info.tsx │ │ │ ├── index.ts │ │ │ └── types │ │ │ │ └── index.ts │ │ └── organizations │ │ │ ├── api │ │ │ └── .gitkeep │ │ │ ├── components │ │ │ └── organization-info │ │ │ │ ├── index.ts │ │ │ │ └── organization-info.tsx │ │ │ ├── index.ts │ │ │ └── types │ │ │ └── index.ts │ │ ├── layouts │ │ ├── dashboard-layout.tsx │ │ └── public-layout.tsx │ │ ├── lib │ │ └── msw.tsx │ │ ├── pages │ │ ├── 404.tsx │ │ ├── _app.tsx │ │ ├── dashboard │ │ │ └── jobs │ │ │ │ ├── [jobId].tsx │ │ │ │ ├── create.tsx │ │ │ │ └── index.tsx │ │ ├── index.tsx │ │ └── organizations │ │ │ └── [organizationId] │ │ │ ├── index.tsx │ │ │ └── jobs │ │ │ └── [jobId].tsx │ │ ├── providers │ │ └── app.tsx │ │ ├── stores │ │ └── .gitkeep │ │ ├── testing │ │ ├── mocks │ │ │ ├── browser.ts │ │ │ ├── db.ts │ │ │ ├── handlers │ │ │ │ ├── auth.ts │ │ │ │ ├── index.ts │ │ │ │ ├── jobs.ts │ │ │ │ └── organizations.ts │ │ │ ├── index.ts │ │ │ ├── initialize.ts │ │ │ ├── seed-db.ts │ │ │ ├── server.ts │ │ │ └── utils.ts │ │ └── test-data.ts │ │ ├── types │ │ └── index.ts │ │ └── utils │ │ ├── format.ts │ │ └── uid.ts ├── chapter-06 │ └── src │ │ ├── components │ │ ├── button │ │ │ ├── button.stories.tsx │ │ │ ├── button.tsx │ │ │ └── index.ts │ │ ├── content │ │ │ ├── content.stories.tsx │ │ │ ├── content.tsx │ │ │ └── index.ts │ │ ├── data-table │ │ │ ├── data-table.stories.tsx │ │ │ ├── data-table.tsx │ │ │ └── index.ts │ │ ├── form │ │ │ ├── index.ts │ │ │ ├── input-field.stories.tsx │ │ │ └── input-field.tsx │ │ ├── info-card │ │ │ ├── index.ts │ │ │ ├── info-card.stories.tsx │ │ │ └── info-card.tsx │ │ ├── link │ │ │ ├── index.ts │ │ │ ├── link.stories.tsx │ │ │ └── link.tsx │ │ ├── loading │ │ │ ├── index.ts │ │ │ ├── loading.stories.tsx │ │ │ └── loading.tsx │ │ ├── not-found │ │ │ ├── index.ts │ │ │ ├── not-found.stories.tsx │ │ │ └── not-found.tsx │ │ └── seo │ │ │ ├── index.ts │ │ │ └── seo.tsx │ │ ├── config │ │ ├── constants.ts │ │ └── theme.ts │ │ ├── features │ │ ├── auth │ │ │ ├── api │ │ │ │ └── .gitkeep │ │ │ ├── components │ │ │ │ └── .gitkeep │ │ │ ├── index.ts │ │ │ └── types │ │ │ │ └── index.ts │ │ ├── jobs │ │ │ ├── api │ │ │ │ ├── create-job.ts │ │ │ │ ├── get-job.ts │ │ │ │ └── get-jobs.ts │ │ │ ├── components │ │ │ │ ├── create-job-form │ │ │ │ │ ├── create-job-form.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── dashboard-job-info │ │ │ │ │ ├── dashboard-job-info.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── jobs-list │ │ │ │ │ ├── index.ts │ │ │ │ │ └── jobs-list.tsx │ │ │ │ └── public-job-info │ │ │ │ │ ├── index.ts │ │ │ │ │ └── public-job-info.tsx │ │ │ ├── index.ts │ │ │ └── types │ │ │ │ └── index.ts │ │ └── organizations │ │ │ ├── api │ │ │ └── get-organization.ts │ │ │ ├── components │ │ │ └── organization-info │ │ │ │ ├── index.ts │ │ │ │ └── organization-info.tsx │ │ │ ├── index.ts │ │ │ └── types │ │ │ └── index.ts │ │ ├── layouts │ │ ├── dashboard-layout.tsx │ │ └── public-layout.tsx │ │ ├── lib │ │ ├── api-client.ts │ │ ├── msw.tsx │ │ └── react-query.ts │ │ ├── pages │ │ ├── 404.tsx │ │ ├── _app.tsx │ │ ├── dashboard │ │ │ └── jobs │ │ │ │ ├── [jobId].tsx │ │ │ │ ├── create.tsx │ │ │ │ └── index.tsx │ │ ├── index.tsx │ │ └── organizations │ │ │ └── [organizationId] │ │ │ ├── index.tsx │ │ │ └── jobs │ │ │ └── [jobId].tsx │ │ ├── providers │ │ └── app.tsx │ │ ├── stores │ │ └── .gitkeep │ │ ├── testing │ │ ├── mocks │ │ │ ├── browser.ts │ │ │ ├── db.ts │ │ │ ├── handlers │ │ │ │ ├── auth.ts │ │ │ │ ├── index.ts │ │ │ │ ├── jobs.ts │ │ │ │ └── organizations.ts │ │ │ ├── index.ts │ │ │ ├── initialize.ts │ │ │ ├── seed-db.ts │ │ │ ├── server.ts │ │ │ └── utils.ts │ │ └── test-data.ts │ │ ├── types │ │ └── index.ts │ │ └── utils │ │ ├── format.ts │ │ └── uid.ts ├── chapter-07-start │ └── src │ │ ├── components │ │ ├── button │ │ │ ├── button.stories.tsx │ │ │ ├── button.tsx │ │ │ └── index.ts │ │ ├── content │ │ │ ├── content.stories.tsx │ │ │ ├── content.tsx │ │ │ └── index.ts │ │ ├── data-table │ │ │ ├── data-table.stories.tsx │ │ │ ├── data-table.tsx │ │ │ └── index.ts │ │ ├── form │ │ │ ├── index.ts │ │ │ ├── input-field.stories.tsx │ │ │ └── input-field.tsx │ │ ├── info-card │ │ │ ├── index.ts │ │ │ ├── info-card.stories.tsx │ │ │ └── info-card.tsx │ │ ├── link │ │ │ ├── index.ts │ │ │ ├── link.stories.tsx │ │ │ └── link.tsx │ │ ├── loading │ │ │ ├── index.ts │ │ │ ├── loading.stories.tsx │ │ │ └── loading.tsx │ │ ├── not-found │ │ │ ├── index.ts │ │ │ ├── not-found.stories.tsx │ │ │ └── not-found.tsx │ │ ├── notifications │ │ │ ├── index.ts │ │ │ └── notifications.tsx │ │ └── seo │ │ │ ├── index.ts │ │ │ └── seo.tsx │ │ ├── config │ │ ├── constants.ts │ │ └── theme.ts │ │ ├── features │ │ ├── auth │ │ │ ├── api │ │ │ │ └── .gitkeep │ │ │ ├── components │ │ │ │ ├── login-form │ │ │ │ │ ├── index.ts │ │ │ │ │ └── login-form.tsx │ │ │ │ └── protected │ │ │ │ │ ├── index.ts │ │ │ │ │ └── protected.tsx │ │ │ ├── index.ts │ │ │ └── types │ │ │ │ └── index.ts │ │ ├── jobs │ │ │ ├── api │ │ │ │ ├── create-job.ts │ │ │ │ ├── get-job.ts │ │ │ │ └── get-jobs.ts │ │ │ ├── components │ │ │ │ ├── create-job-form │ │ │ │ │ ├── create-job-form.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── dashboard-job-info │ │ │ │ │ ├── dashboard-job-info.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── jobs-list │ │ │ │ │ ├── index.ts │ │ │ │ │ └── jobs-list.tsx │ │ │ │ └── public-job-info │ │ │ │ │ ├── index.ts │ │ │ │ │ └── public-job-info.tsx │ │ │ ├── index.ts │ │ │ └── types │ │ │ │ └── index.ts │ │ └── organizations │ │ │ ├── api │ │ │ └── get-organization.ts │ │ │ ├── components │ │ │ └── organization-info │ │ │ │ ├── index.ts │ │ │ │ └── organization-info.tsx │ │ │ ├── index.ts │ │ │ └── types │ │ │ └── index.ts │ │ ├── layouts │ │ ├── auth-layout.tsx │ │ ├── dashboard-layout.tsx │ │ └── public-layout.tsx │ │ ├── lib │ │ ├── api-client.ts │ │ ├── msw.tsx │ │ └── react-query.ts │ │ ├── pages │ │ ├── 404.tsx │ │ ├── _app.tsx │ │ ├── auth │ │ │ └── login.tsx │ │ ├── dashboard │ │ │ └── jobs │ │ │ │ ├── [jobId].tsx │ │ │ │ ├── create.tsx │ │ │ │ └── index.tsx │ │ ├── index.tsx │ │ └── organizations │ │ │ └── [organizationId] │ │ │ ├── index.tsx │ │ │ └── jobs │ │ │ └── [jobId].tsx │ │ ├── providers │ │ └── app.tsx │ │ ├── stores │ │ └── notifications │ │ │ ├── index.ts │ │ │ └── notifications.ts │ │ ├── testing │ │ ├── mocks │ │ │ ├── browser.ts │ │ │ ├── db.ts │ │ │ ├── handlers │ │ │ │ ├── auth.ts │ │ │ │ ├── index.ts │ │ │ │ ├── jobs.ts │ │ │ │ └── organizations.ts │ │ │ ├── index.ts │ │ │ ├── initialize.ts │ │ │ ├── seed-db.ts │ │ │ ├── server.ts │ │ │ └── utils.ts │ │ └── test-data.ts │ │ ├── types │ │ └── index.ts │ │ └── utils │ │ ├── format.ts │ │ └── uid.ts ├── chapter-07 │ └── src │ │ ├── components │ │ ├── button │ │ │ ├── button.stories.tsx │ │ │ ├── button.tsx │ │ │ └── index.ts │ │ ├── content │ │ │ ├── content.stories.tsx │ │ │ ├── content.tsx │ │ │ └── index.ts │ │ ├── data-table │ │ │ ├── data-table.stories.tsx │ │ │ ├── data-table.tsx │ │ │ └── index.ts │ │ ├── form │ │ │ ├── index.ts │ │ │ ├── input-field.stories.tsx │ │ │ └── input-field.tsx │ │ ├── info-card │ │ │ ├── index.ts │ │ │ ├── info-card.stories.tsx │ │ │ └── info-card.tsx │ │ ├── link │ │ │ ├── index.ts │ │ │ ├── link.stories.tsx │ │ │ └── link.tsx │ │ ├── loading │ │ │ ├── index.ts │ │ │ ├── loading.stories.tsx │ │ │ └── loading.tsx │ │ ├── not-found │ │ │ ├── index.ts │ │ │ ├── not-found.stories.tsx │ │ │ └── not-found.tsx │ │ ├── notifications │ │ │ ├── index.ts │ │ │ └── notifications.tsx │ │ └── seo │ │ │ ├── index.ts │ │ │ └── seo.tsx │ │ ├── config │ │ ├── constants.ts │ │ └── theme.ts │ │ ├── features │ │ ├── auth │ │ │ ├── api │ │ │ │ ├── get-auth-user.ts │ │ │ │ ├── login.ts │ │ │ │ └── logout.ts │ │ │ ├── components │ │ │ │ ├── login-form │ │ │ │ │ ├── index.ts │ │ │ │ │ └── login-form.tsx │ │ │ │ └── protected │ │ │ │ │ ├── index.ts │ │ │ │ │ └── protected.tsx │ │ │ ├── index.ts │ │ │ └── types │ │ │ │ └── index.ts │ │ ├── jobs │ │ │ ├── api │ │ │ │ ├── create-job.ts │ │ │ │ ├── get-job.ts │ │ │ │ └── get-jobs.ts │ │ │ ├── components │ │ │ │ ├── create-job-form │ │ │ │ │ ├── create-job-form.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── dashboard-job-info │ │ │ │ │ ├── dashboard-job-info.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── jobs-list │ │ │ │ │ ├── index.ts │ │ │ │ │ └── jobs-list.tsx │ │ │ │ └── public-job-info │ │ │ │ │ ├── index.ts │ │ │ │ │ └── public-job-info.tsx │ │ │ ├── index.ts │ │ │ └── types │ │ │ │ └── index.ts │ │ └── organizations │ │ │ ├── api │ │ │ └── get-organization.ts │ │ │ ├── components │ │ │ └── organization-info │ │ │ │ ├── index.ts │ │ │ │ └── organization-info.tsx │ │ │ ├── index.ts │ │ │ └── types │ │ │ └── index.ts │ │ ├── layouts │ │ ├── auth-layout.tsx │ │ ├── dashboard-layout.tsx │ │ └── public-layout.tsx │ │ ├── lib │ │ ├── api-client.ts │ │ ├── msw.tsx │ │ └── react-query.ts │ │ ├── pages │ │ ├── 404.tsx │ │ ├── _app.tsx │ │ ├── auth │ │ │ └── login.tsx │ │ ├── dashboard │ │ │ └── jobs │ │ │ │ ├── [jobId].tsx │ │ │ │ ├── create.tsx │ │ │ │ └── index.tsx │ │ ├── index.tsx │ │ └── organizations │ │ │ └── [organizationId] │ │ │ ├── index.tsx │ │ │ └── jobs │ │ │ └── [jobId].tsx │ │ ├── providers │ │ └── app.tsx │ │ ├── stores │ │ └── notifications │ │ │ ├── index.ts │ │ │ └── notifications.ts │ │ ├── testing │ │ ├── mocks │ │ │ ├── browser.ts │ │ │ ├── db.ts │ │ │ ├── handlers │ │ │ │ ├── auth.ts │ │ │ │ ├── index.ts │ │ │ │ ├── jobs.ts │ │ │ │ └── organizations.ts │ │ │ ├── index.ts │ │ │ ├── initialize.ts │ │ │ ├── seed-db.ts │ │ │ ├── server.ts │ │ │ └── utils.ts │ │ └── test-data.ts │ │ ├── types │ │ └── index.ts │ │ └── utils │ │ ├── format.ts │ │ └── uid.ts ├── chapter-08-start │ ├── cypress.config.ts │ ├── cypress │ │ ├── e2e │ │ │ ├── dashboard.cy.ts │ │ │ └── public.cy.ts │ │ ├── fixtures │ │ │ └── example.json │ │ ├── plugins │ │ │ └── index.ts │ │ ├── support │ │ │ ├── commands.ts │ │ │ └── e2e.ts │ │ └── tsconfig.json │ ├── jest.config.js │ └── src │ │ ├── __tests__ │ │ ├── dashboard-create-job-page.test.tsx │ │ ├── dashboard-job-page.test.tsx │ │ ├── dashboard-jobs-page.test.tsx │ │ ├── login-page.test.tsx │ │ ├── public-job-page.test.tsx │ │ └── public-organization-page.test.tsx │ │ ├── components │ │ ├── button │ │ │ ├── button.stories.tsx │ │ │ ├── button.tsx │ │ │ └── index.ts │ │ ├── content │ │ │ ├── content.stories.tsx │ │ │ ├── content.tsx │ │ │ └── index.ts │ │ ├── data-table │ │ │ ├── data-table.stories.tsx │ │ │ ├── data-table.tsx │ │ │ └── index.ts │ │ ├── form │ │ │ ├── index.ts │ │ │ ├── input-field.stories.tsx │ │ │ └── input-field.tsx │ │ ├── info-card │ │ │ ├── index.ts │ │ │ ├── info-card.stories.tsx │ │ │ └── info-card.tsx │ │ ├── link │ │ │ ├── index.ts │ │ │ ├── link.stories.tsx │ │ │ └── link.tsx │ │ ├── loading │ │ │ ├── index.ts │ │ │ ├── loading.stories.tsx │ │ │ └── loading.tsx │ │ ├── not-found │ │ │ ├── index.ts │ │ │ ├── not-found.stories.tsx │ │ │ └── not-found.tsx │ │ ├── notifications │ │ │ ├── index.ts │ │ │ ├── notifications.stories.tsx │ │ │ └── notifications.tsx │ │ └── seo │ │ │ ├── index.ts │ │ │ └── seo.tsx │ │ ├── config │ │ ├── constants.ts │ │ └── theme.ts │ │ ├── features │ │ ├── auth │ │ │ ├── api │ │ │ │ ├── get-auth-user.ts │ │ │ │ ├── login.ts │ │ │ │ └── logout.ts │ │ │ ├── components │ │ │ │ ├── login-form │ │ │ │ │ ├── index.ts │ │ │ │ │ └── login-form.tsx │ │ │ │ └── protected │ │ │ │ │ ├── index.ts │ │ │ │ │ └── protected.tsx │ │ │ ├── index.ts │ │ │ └── types │ │ │ │ └── index.ts │ │ ├── jobs │ │ │ ├── api │ │ │ │ ├── create-job.ts │ │ │ │ ├── get-job.ts │ │ │ │ └── get-jobs.ts │ │ │ ├── components │ │ │ │ ├── create-job-form │ │ │ │ │ ├── create-job-form.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── dashboard-job-info │ │ │ │ │ ├── dashboard-job-info.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── jobs-list │ │ │ │ │ ├── index.ts │ │ │ │ │ └── jobs-list.tsx │ │ │ │ └── public-job-info │ │ │ │ │ ├── index.ts │ │ │ │ │ └── public-job-info.tsx │ │ │ ├── index.ts │ │ │ └── types │ │ │ │ └── index.ts │ │ └── organizations │ │ │ ├── api │ │ │ └── get-organization.ts │ │ │ ├── components │ │ │ └── organization-info │ │ │ │ ├── index.ts │ │ │ │ └── organization-info.tsx │ │ │ ├── index.ts │ │ │ └── types │ │ │ └── index.ts │ │ ├── layouts │ │ ├── auth-layout.tsx │ │ ├── dashboard-layout.tsx │ │ └── public-layout.tsx │ │ ├── lib │ │ ├── api-client.ts │ │ ├── msw.tsx │ │ └── react-query.ts │ │ ├── pages │ │ ├── 404.tsx │ │ ├── _app.tsx │ │ ├── auth │ │ │ └── login.tsx │ │ ├── dashboard │ │ │ └── jobs │ │ │ │ ├── [jobId].tsx │ │ │ │ ├── create.tsx │ │ │ │ └── index.tsx │ │ ├── index.tsx │ │ └── organizations │ │ │ └── [organizationId] │ │ │ ├── index.tsx │ │ │ └── jobs │ │ │ └── [jobId].tsx │ │ ├── providers │ │ └── app.tsx │ │ ├── stores │ │ └── notifications │ │ │ ├── __tests__ │ │ │ └── notifications.test.ts │ │ │ ├── index.ts │ │ │ └── notifications.ts │ │ ├── testing │ │ ├── mocks │ │ │ ├── browser.ts │ │ │ ├── db.ts │ │ │ ├── handlers │ │ │ │ ├── auth.ts │ │ │ │ ├── index.ts │ │ │ │ ├── jobs.ts │ │ │ │ └── organizations.ts │ │ │ ├── index.ts │ │ │ ├── initialize.ts │ │ │ ├── seed-db.ts │ │ │ ├── server.ts │ │ │ └── utils.ts │ │ ├── setup-tests.ts │ │ ├── test-data.ts │ │ └── test-utils.ts │ │ ├── types │ │ └── index.ts │ │ └── utils │ │ ├── format.ts │ │ └── uid.ts ├── chapter-08 │ ├── cypress.config.ts │ ├── cypress │ │ ├── e2e │ │ │ ├── dashboard.cy.ts │ │ │ └── public.cy.ts │ │ ├── fixtures │ │ │ └── example.json │ │ ├── plugins │ │ │ └── index.ts │ │ ├── support │ │ │ ├── commands.ts │ │ │ └── e2e.ts │ │ └── tsconfig.json │ ├── jest.config.js │ └── src │ │ ├── __tests__ │ │ ├── dashboard-create-job-page.test.tsx │ │ ├── dashboard-job-page.test.tsx │ │ ├── dashboard-jobs-page.test.tsx │ │ ├── login-page.test.tsx │ │ ├── public-job-page.test.tsx │ │ └── public-organization-page.test.tsx │ │ ├── components │ │ ├── button │ │ │ ├── button.stories.tsx │ │ │ ├── button.tsx │ │ │ └── index.ts │ │ ├── content │ │ │ ├── content.stories.tsx │ │ │ ├── content.tsx │ │ │ └── index.ts │ │ ├── data-table │ │ │ ├── data-table.stories.tsx │ │ │ ├── data-table.tsx │ │ │ └── index.ts │ │ ├── form │ │ │ ├── index.ts │ │ │ ├── input-field.stories.tsx │ │ │ └── input-field.tsx │ │ ├── info-card │ │ │ ├── index.ts │ │ │ ├── info-card.stories.tsx │ │ │ └── info-card.tsx │ │ ├── link │ │ │ ├── index.ts │ │ │ ├── link.stories.tsx │ │ │ └── link.tsx │ │ ├── loading │ │ │ ├── index.ts │ │ │ ├── loading.stories.tsx │ │ │ └── loading.tsx │ │ ├── not-found │ │ │ ├── index.ts │ │ │ ├── not-found.stories.tsx │ │ │ └── not-found.tsx │ │ ├── notifications │ │ │ ├── index.ts │ │ │ ├── notifications.stories.tsx │ │ │ └── notifications.tsx │ │ └── seo │ │ │ ├── index.ts │ │ │ └── seo.tsx │ │ ├── config │ │ ├── constants.ts │ │ └── theme.ts │ │ ├── features │ │ ├── auth │ │ │ ├── api │ │ │ │ ├── get-auth-user.ts │ │ │ │ ├── login.ts │ │ │ │ └── logout.ts │ │ │ ├── components │ │ │ │ ├── login-form │ │ │ │ │ ├── index.ts │ │ │ │ │ └── login-form.tsx │ │ │ │ └── protected │ │ │ │ │ ├── index.ts │ │ │ │ │ └── protected.tsx │ │ │ ├── index.ts │ │ │ └── types │ │ │ │ └── index.ts │ │ ├── jobs │ │ │ ├── api │ │ │ │ ├── create-job.ts │ │ │ │ ├── get-job.ts │ │ │ │ └── get-jobs.ts │ │ │ ├── components │ │ │ │ ├── create-job-form │ │ │ │ │ ├── create-job-form.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── dashboard-job-info │ │ │ │ │ ├── dashboard-job-info.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── jobs-list │ │ │ │ │ ├── index.ts │ │ │ │ │ └── jobs-list.tsx │ │ │ │ └── public-job-info │ │ │ │ │ ├── index.ts │ │ │ │ │ └── public-job-info.tsx │ │ │ ├── index.ts │ │ │ └── types │ │ │ │ └── index.ts │ │ └── organizations │ │ │ ├── api │ │ │ └── get-organization.ts │ │ │ ├── components │ │ │ └── organization-info │ │ │ │ ├── index.ts │ │ │ │ └── organization-info.tsx │ │ │ ├── index.ts │ │ │ └── types │ │ │ └── index.ts │ │ ├── layouts │ │ ├── auth-layout.tsx │ │ ├── dashboard-layout.tsx │ │ └── public-layout.tsx │ │ ├── lib │ │ ├── api-client.ts │ │ ├── msw.tsx │ │ └── react-query.ts │ │ ├── pages │ │ ├── 404.tsx │ │ ├── _app.tsx │ │ ├── auth │ │ │ └── login.tsx │ │ ├── dashboard │ │ │ └── jobs │ │ │ │ ├── [jobId].tsx │ │ │ │ ├── create.tsx │ │ │ │ └── index.tsx │ │ ├── index.tsx │ │ └── organizations │ │ │ └── [organizationId] │ │ │ ├── index.tsx │ │ │ └── jobs │ │ │ └── [jobId].tsx │ │ ├── providers │ │ └── app.tsx │ │ ├── stores │ │ └── notifications │ │ │ ├── __tests__ │ │ │ └── notifications.test.ts │ │ │ ├── index.ts │ │ │ └── notifications.ts │ │ ├── testing │ │ ├── mocks │ │ │ ├── browser.ts │ │ │ ├── db.ts │ │ │ ├── handlers │ │ │ │ ├── auth.ts │ │ │ │ ├── index.ts │ │ │ │ ├── jobs.ts │ │ │ │ └── organizations.ts │ │ │ ├── index.ts │ │ │ ├── initialize.ts │ │ │ ├── seed-db.ts │ │ │ ├── server.ts │ │ │ └── utils.ts │ │ ├── setup-tests.ts │ │ ├── test-data.ts │ │ └── test-utils.ts │ │ ├── types │ │ └── index.ts │ │ └── utils │ │ ├── format.ts │ │ └── uid.ts ├── chapter-09-start │ ├── cypress.config.ts │ ├── cypress │ │ ├── e2e │ │ │ ├── dashboard.cy.ts │ │ │ └── public.cy.ts │ │ ├── fixtures │ │ │ └── example.json │ │ ├── plugins │ │ │ └── index.ts │ │ ├── support │ │ │ ├── commands.ts │ │ │ └── e2e.ts │ │ └── tsconfig.json │ ├── jest.config.js │ └── src │ │ ├── __tests__ │ │ ├── dashboard-create-job-page.test.tsx │ │ ├── dashboard-job-page.test.tsx │ │ ├── dashboard-jobs-page.test.tsx │ │ ├── login-page.test.tsx │ │ ├── public-job-page.test.tsx │ │ └── public-organization-page.test.tsx │ │ ├── components │ │ ├── button │ │ │ ├── button.stories.tsx │ │ │ ├── button.tsx │ │ │ └── index.ts │ │ ├── content │ │ │ ├── content.stories.tsx │ │ │ ├── content.tsx │ │ │ └── index.ts │ │ ├── data-table │ │ │ ├── data-table.stories.tsx │ │ │ ├── data-table.tsx │ │ │ └── index.ts │ │ ├── form │ │ │ ├── index.ts │ │ │ ├── input-field.stories.tsx │ │ │ └── input-field.tsx │ │ ├── info-card │ │ │ ├── index.ts │ │ │ ├── info-card.stories.tsx │ │ │ └── info-card.tsx │ │ ├── link │ │ │ ├── index.ts │ │ │ ├── link.stories.tsx │ │ │ └── link.tsx │ │ ├── loading │ │ │ ├── index.ts │ │ │ ├── loading.stories.tsx │ │ │ └── loading.tsx │ │ ├── not-found │ │ │ ├── index.ts │ │ │ ├── not-found.stories.tsx │ │ │ └── not-found.tsx │ │ ├── notifications │ │ │ ├── index.ts │ │ │ ├── notifications.stories.tsx │ │ │ └── notifications.tsx │ │ └── seo │ │ │ ├── index.ts │ │ │ └── seo.tsx │ │ ├── config │ │ ├── constants.ts │ │ └── theme.ts │ │ ├── features │ │ ├── auth │ │ │ ├── api │ │ │ │ ├── get-auth-user.ts │ │ │ │ ├── login.ts │ │ │ │ └── logout.ts │ │ │ ├── components │ │ │ │ ├── login-form │ │ │ │ │ ├── index.ts │ │ │ │ │ └── login-form.tsx │ │ │ │ └── protected │ │ │ │ │ ├── index.ts │ │ │ │ │ └── protected.tsx │ │ │ ├── index.ts │ │ │ └── types │ │ │ │ └── index.ts │ │ ├── jobs │ │ │ ├── api │ │ │ │ ├── create-job.ts │ │ │ │ ├── get-job.ts │ │ │ │ └── get-jobs.ts │ │ │ ├── components │ │ │ │ ├── create-job-form │ │ │ │ │ ├── create-job-form.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── dashboard-job-info │ │ │ │ │ ├── dashboard-job-info.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── jobs-list │ │ │ │ │ ├── index.ts │ │ │ │ │ └── jobs-list.tsx │ │ │ │ └── public-job-info │ │ │ │ │ ├── index.ts │ │ │ │ │ └── public-job-info.tsx │ │ │ ├── index.ts │ │ │ └── types │ │ │ │ └── index.ts │ │ └── organizations │ │ │ ├── api │ │ │ └── get-organization.ts │ │ │ ├── components │ │ │ └── organization-info │ │ │ │ ├── index.ts │ │ │ │ └── organization-info.tsx │ │ │ ├── index.ts │ │ │ └── types │ │ │ └── index.ts │ │ ├── layouts │ │ ├── auth-layout.tsx │ │ ├── dashboard-layout.tsx │ │ └── public-layout.tsx │ │ ├── lib │ │ ├── api-client.ts │ │ ├── msw.tsx │ │ └── react-query.ts │ │ ├── pages │ │ ├── 404.tsx │ │ ├── _app.tsx │ │ ├── auth │ │ │ └── login.tsx │ │ ├── dashboard │ │ │ └── jobs │ │ │ │ ├── [jobId].tsx │ │ │ │ ├── create.tsx │ │ │ │ └── index.tsx │ │ ├── index.tsx │ │ └── organizations │ │ │ └── [organizationId] │ │ │ ├── index.tsx │ │ │ └── jobs │ │ │ └── [jobId].tsx │ │ ├── providers │ │ └── app.tsx │ │ ├── stores │ │ └── notifications │ │ │ ├── __tests__ │ │ │ └── notifications.test.ts │ │ │ ├── index.ts │ │ │ └── notifications.ts │ │ ├── testing │ │ ├── mocks │ │ │ ├── browser.ts │ │ │ ├── db.ts │ │ │ ├── handlers │ │ │ │ ├── auth.ts │ │ │ │ ├── index.ts │ │ │ │ ├── jobs.ts │ │ │ │ └── organizations.ts │ │ │ ├── index.ts │ │ │ ├── initialize.ts │ │ │ ├── seed-db.ts │ │ │ ├── server.ts │ │ │ └── utils.ts │ │ ├── setup-tests.ts │ │ ├── test-data.ts │ │ └── test-utils.ts │ │ ├── types │ │ └── index.ts │ │ └── utils │ │ ├── format.ts │ │ └── uid.ts └── chapter-09 │ ├── .github │ └── workflows │ │ └── main.yml │ ├── cypress.config.ts │ ├── cypress │ ├── e2e │ │ ├── dashboard.cy.ts │ │ └── public.cy.ts │ ├── fixtures │ │ └── example.json │ ├── plugins │ │ └── index.ts │ ├── support │ │ ├── commands.ts │ │ └── e2e.ts │ └── tsconfig.json │ ├── jest.config.js │ ├── src │ ├── __tests__ │ │ ├── dashboard-create-job-page.test.tsx │ │ ├── dashboard-job-page.test.tsx │ │ ├── dashboard-jobs-page.test.tsx │ │ ├── login-page.test.tsx │ │ ├── public-job-page.test.tsx │ │ └── public-organization-page.test.tsx │ ├── components │ │ ├── button │ │ │ ├── button.stories.tsx │ │ │ ├── button.tsx │ │ │ └── index.ts │ │ ├── content │ │ │ ├── content.stories.tsx │ │ │ ├── content.tsx │ │ │ └── index.ts │ │ ├── data-table │ │ │ ├── data-table.stories.tsx │ │ │ ├── data-table.tsx │ │ │ └── index.ts │ │ ├── form │ │ │ ├── index.ts │ │ │ ├── input-field.stories.tsx │ │ │ └── input-field.tsx │ │ ├── info-card │ │ │ ├── index.ts │ │ │ ├── info-card.stories.tsx │ │ │ └── info-card.tsx │ │ ├── link │ │ │ ├── index.ts │ │ │ ├── link.stories.tsx │ │ │ └── link.tsx │ │ ├── loading │ │ │ ├── index.ts │ │ │ ├── loading.stories.tsx │ │ │ └── loading.tsx │ │ ├── not-found │ │ │ ├── index.ts │ │ │ ├── not-found.stories.tsx │ │ │ └── not-found.tsx │ │ ├── notifications │ │ │ ├── index.ts │ │ │ ├── notifications.stories.tsx │ │ │ └── notifications.tsx │ │ └── seo │ │ │ ├── index.ts │ │ │ └── seo.tsx │ ├── config │ │ ├── constants.ts │ │ └── theme.ts │ ├── features │ │ ├── auth │ │ │ ├── api │ │ │ │ ├── get-auth-user.ts │ │ │ │ ├── login.ts │ │ │ │ └── logout.ts │ │ │ ├── components │ │ │ │ ├── login-form │ │ │ │ │ ├── index.ts │ │ │ │ │ └── login-form.tsx │ │ │ │ └── protected │ │ │ │ │ ├── index.ts │ │ │ │ │ └── protected.tsx │ │ │ ├── index.ts │ │ │ └── types │ │ │ │ └── index.ts │ │ ├── jobs │ │ │ ├── api │ │ │ │ ├── create-job.ts │ │ │ │ ├── get-job.ts │ │ │ │ └── get-jobs.ts │ │ │ ├── components │ │ │ │ ├── create-job-form │ │ │ │ │ ├── create-job-form.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── dashboard-job-info │ │ │ │ │ ├── dashboard-job-info.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── jobs-list │ │ │ │ │ ├── index.ts │ │ │ │ │ └── jobs-list.tsx │ │ │ │ └── public-job-info │ │ │ │ │ ├── index.ts │ │ │ │ │ └── public-job-info.tsx │ │ │ ├── index.ts │ │ │ └── types │ │ │ │ └── index.ts │ │ └── organizations │ │ │ ├── api │ │ │ └── get-organization.ts │ │ │ ├── components │ │ │ └── organization-info │ │ │ │ ├── index.ts │ │ │ │ └── organization-info.tsx │ │ │ ├── index.ts │ │ │ └── types │ │ │ └── index.ts │ ├── layouts │ │ ├── auth-layout.tsx │ │ ├── dashboard-layout.tsx │ │ └── public-layout.tsx │ ├── lib │ │ ├── api-client.ts │ │ ├── msw.tsx │ │ └── react-query.ts │ ├── pages │ │ ├── 404.tsx │ │ ├── _app.tsx │ │ ├── auth │ │ │ └── login.tsx │ │ ├── dashboard │ │ │ └── jobs │ │ │ │ ├── [jobId].tsx │ │ │ │ ├── create.tsx │ │ │ │ └── index.tsx │ │ ├── index.tsx │ │ └── organizations │ │ │ └── [organizationId] │ │ │ ├── index.tsx │ │ │ └── jobs │ │ │ └── [jobId].tsx │ ├── providers │ │ └── app.tsx │ ├── stores │ │ └── notifications │ │ │ ├── __tests__ │ │ │ └── notifications.test.ts │ │ │ ├── index.ts │ │ │ └── notifications.ts │ ├── testing │ │ ├── mocks │ │ │ ├── browser.ts │ │ │ ├── db.ts │ │ │ ├── handlers │ │ │ │ ├── auth.ts │ │ │ │ ├── index.ts │ │ │ │ ├── jobs.ts │ │ │ │ └── organizations.ts │ │ │ ├── index.ts │ │ │ ├── initialize.ts │ │ │ ├── seed-db.ts │ │ │ ├── server.ts │ │ │ └── utils.ts │ │ ├── setup-tests.ts │ │ ├── test-data.ts │ │ └── test-utils.ts │ ├── types │ │ └── index.ts │ └── utils │ │ ├── format.ts │ │ └── uid.ts │ └── vercel.json ├── lint-staged.config.js ├── next-env.d.ts ├── next.config.js ├── package-lock.json ├── package.json ├── public ├── favicon.ico ├── mockServiceWorker.js └── vercel.svg ├── scripts ├── clear-stage.js ├── save-stage.js ├── switch-stage.js └── utils.js └── tsconfig.json /.env.example: -------------------------------------------------------------------------------- 1 | NEXT_PUBLIC_API_URL=https://api.jobs-app.com 2 | NEXT_PUBLIC_API_MOCKING=true 3 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | 2 | # dependencies 3 | /node_modules 4 | 5 | # testing 6 | /coverage 7 | 8 | # next.js 9 | /.next/ 10 | /out/ 11 | 12 | # production 13 | /build 14 | 15 | 16 | # others 17 | /code-stages 18 | /scripts -------------------------------------------------------------------------------- /.husky/.gitignore: -------------------------------------------------------------------------------- 1 | _ 2 | -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | . "$(dirname "$0")/_/husky.sh" 3 | 4 | npx lint-staged 5 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | 2 | # dependencies 3 | /node_modules 4 | 5 | # testing 6 | /coverage 7 | 8 | # next.js 9 | /.next/ 10 | /out/ 11 | 12 | # production 13 | /build 14 | 15 | 16 | # others 17 | # /code-stages 18 | /scripts -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "endOfLine": "auto", 3 | "singleQuote": true, 4 | "printWidth": 58, 5 | "tabWidth": 2, 6 | "trailingComma": "es5" 7 | } 8 | -------------------------------------------------------------------------------- /.storybook/preview.js: -------------------------------------------------------------------------------- 1 | import { theme } from '../src/config/theme'; 2 | 3 | export const parameters = { 4 | actions: { argTypesRegex: '^on[A-Z].*' }, 5 | controls: { 6 | matchers: { 7 | color: /(background|color)$/i, 8 | date: /Date$/, 9 | }, 10 | }, 11 | controls: { expanded: true }, 12 | chakra: { 13 | theme, 14 | }, 15 | }; 16 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "dbaeumer.vscode-eslint", 4 | "esbenp.prettier-vscode", 5 | "dsznajder.es7-react-js-snippets" 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "editor.formatOnSave": true, 3 | "editor.codeActionsOnSave": { 4 | "source.fixAll.eslint": true 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /code-stages/chapter-02/src/components/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/React-Application-Architecture-for-Production/40cd19895fa025e7c48127f187035ec451874061/code-stages/chapter-02/src/components/.gitkeep -------------------------------------------------------------------------------- /code-stages/chapter-02/src/config/theme.ts: -------------------------------------------------------------------------------- 1 | export const theme = {}; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-02/src/features/auth/api/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/React-Application-Architecture-for-Production/40cd19895fa025e7c48127f187035ec451874061/code-stages/chapter-02/src/features/auth/api/.gitkeep -------------------------------------------------------------------------------- /code-stages/chapter-02/src/features/auth/components/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/React-Application-Architecture-for-Production/40cd19895fa025e7c48127f187035ec451874061/code-stages/chapter-02/src/features/auth/components/.gitkeep -------------------------------------------------------------------------------- /code-stages/chapter-02/src/features/auth/index.ts: -------------------------------------------------------------------------------- 1 | // types: 2 | export * from './types'; 3 | -------------------------------------------------------------------------------- /code-stages/chapter-02/src/features/auth/pages/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/React-Application-Architecture-for-Production/40cd19895fa025e7c48127f187035ec451874061/code-stages/chapter-02/src/features/auth/pages/.gitkeep -------------------------------------------------------------------------------- /code-stages/chapter-02/src/features/auth/types/index.ts: -------------------------------------------------------------------------------- 1 | import { Entity } from '@/types'; 2 | 3 | export type AuthUser = Entity & { 4 | email: string; 5 | organizationId: string; 6 | }; 7 | 8 | export type LoginData = { 9 | email: string; 10 | password: string; 11 | }; 12 | -------------------------------------------------------------------------------- /code-stages/chapter-02/src/features/jobs/api/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/React-Application-Architecture-for-Production/40cd19895fa025e7c48127f187035ec451874061/code-stages/chapter-02/src/features/jobs/api/.gitkeep -------------------------------------------------------------------------------- /code-stages/chapter-02/src/features/jobs/components/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/React-Application-Architecture-for-Production/40cd19895fa025e7c48127f187035ec451874061/code-stages/chapter-02/src/features/jobs/components/.gitkeep -------------------------------------------------------------------------------- /code-stages/chapter-02/src/features/jobs/index.ts: -------------------------------------------------------------------------------- 1 | // types: 2 | export * from './types'; 3 | -------------------------------------------------------------------------------- /code-stages/chapter-02/src/features/jobs/pages/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/React-Application-Architecture-for-Production/40cd19895fa025e7c48127f187035ec451874061/code-stages/chapter-02/src/features/jobs/pages/.gitkeep -------------------------------------------------------------------------------- /code-stages/chapter-02/src/features/jobs/types/index.ts: -------------------------------------------------------------------------------- 1 | import { Entity } from '@/types'; 2 | 3 | export type Job = Entity & { 4 | organizationId: string; 5 | position: string; 6 | info: string; 7 | location: string; 8 | department: string; 9 | }; 10 | 11 | export type CreateJobData = Pick< 12 | Job, 13 | 'position' | 'department' | 'location' | 'info' 14 | >; 15 | -------------------------------------------------------------------------------- /code-stages/chapter-02/src/features/organizations/api/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/React-Application-Architecture-for-Production/40cd19895fa025e7c48127f187035ec451874061/code-stages/chapter-02/src/features/organizations/api/.gitkeep -------------------------------------------------------------------------------- /code-stages/chapter-02/src/features/organizations/index.ts: -------------------------------------------------------------------------------- 1 | // types: 2 | export * from './types'; 3 | -------------------------------------------------------------------------------- /code-stages/chapter-02/src/features/organizations/pages/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/React-Application-Architecture-for-Production/40cd19895fa025e7c48127f187035ec451874061/code-stages/chapter-02/src/features/organizations/pages/.gitkeep -------------------------------------------------------------------------------- /code-stages/chapter-02/src/features/organizations/types/index.ts: -------------------------------------------------------------------------------- 1 | import { Entity } from '@/types'; 2 | 3 | export type Organization = Entity & { 4 | adminId: string; 5 | name: string; 6 | email: string; 7 | phone: string; 8 | info: string; 9 | }; 10 | -------------------------------------------------------------------------------- /code-stages/chapter-02/src/layouts/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/React-Application-Architecture-for-Production/40cd19895fa025e7c48127f187035ec451874061/code-stages/chapter-02/src/layouts/.gitkeep -------------------------------------------------------------------------------- /code-stages/chapter-02/src/lib/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/React-Application-Architecture-for-Production/40cd19895fa025e7c48127f187035ec451874061/code-stages/chapter-02/src/lib/.gitkeep -------------------------------------------------------------------------------- /code-stages/chapter-02/src/pages/_app.tsx: -------------------------------------------------------------------------------- 1 | import type { AppProps } from 'next/app'; 2 | 3 | import { AppProvider } from '@/providers/app'; 4 | 5 | const App = ({ Component, pageProps }: AppProps) => { 6 | return ( 7 | 8 | 9 | 10 | ); 11 | }; 12 | 13 | export default App; 14 | -------------------------------------------------------------------------------- /code-stages/chapter-02/src/pages/index.tsx: -------------------------------------------------------------------------------- 1 | const LandingPage = () => { 2 | return <>Landing Page; 3 | }; 4 | 5 | export default LandingPage; 6 | -------------------------------------------------------------------------------- /code-stages/chapter-02/src/providers/app.tsx: -------------------------------------------------------------------------------- 1 | import { ReactNode } from 'react'; 2 | 3 | type AppProviderProps = { 4 | children: ReactNode; 5 | }; 6 | 7 | export const AppProvider = ({ 8 | children, 9 | }: AppProviderProps) => { 10 | return <>{children}; 11 | }; 12 | -------------------------------------------------------------------------------- /code-stages/chapter-02/src/stores/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/React-Application-Architecture-for-Production/40cd19895fa025e7c48127f187035ec451874061/code-stages/chapter-02/src/stores/.gitkeep -------------------------------------------------------------------------------- /code-stages/chapter-02/src/testing/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/React-Application-Architecture-for-Production/40cd19895fa025e7c48127f187035ec451874061/code-stages/chapter-02/src/testing/.gitkeep -------------------------------------------------------------------------------- /code-stages/chapter-02/src/types/index.ts: -------------------------------------------------------------------------------- 1 | export type Entity = { 2 | id: string; 3 | createdAt: number; 4 | }; 5 | -------------------------------------------------------------------------------- /code-stages/chapter-02/src/utils/format.ts: -------------------------------------------------------------------------------- 1 | export const formatDate = (date: number | string) => { 2 | return new Date(date).toLocaleDateString('en-US', { 3 | month: 'long', 4 | year: 'numeric', 5 | day: 'numeric', 6 | }); 7 | }; 8 | -------------------------------------------------------------------------------- /code-stages/chapter-02/src/utils/uid.ts: -------------------------------------------------------------------------------- 1 | // https://gist.github.com/gordonbrander/2230317?permalink_comment_id=3443509#gistcomment-3443509 2 | export const uid = () => { 3 | return ( 4 | performance.now().toString(36) + 5 | Math.random().toString(36) 6 | ).replace(/\./g, ''); 7 | }; 8 | -------------------------------------------------------------------------------- /code-stages/chapter-03-start/src/components/button/button.tsx: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line @typescript-eslint/ban-types 2 | export type ButtonProps = {}; 3 | 4 | export const Button = () => { 5 | return <>Button; 6 | }; 7 | -------------------------------------------------------------------------------- /code-stages/chapter-03-start/src/components/button/index.ts: -------------------------------------------------------------------------------- 1 | export * from './button'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-03-start/src/components/form/index.ts: -------------------------------------------------------------------------------- 1 | export * from './input-field'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-03-start/src/components/form/input-field.tsx: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line @typescript-eslint/ban-types 2 | export type InputFieldProps = {}; 3 | 4 | export const InputField = () => { 5 | return <>InputField; 6 | }; 7 | -------------------------------------------------------------------------------- /code-stages/chapter-03-start/src/components/link/index.ts: -------------------------------------------------------------------------------- 1 | export * from './link'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-03-start/src/components/link/link.tsx: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line @typescript-eslint/ban-types 2 | export type LinkProps = {}; 3 | 4 | export const Link = () => { 5 | return <>Link; 6 | }; 7 | -------------------------------------------------------------------------------- /code-stages/chapter-03-start/src/config/theme.ts: -------------------------------------------------------------------------------- 1 | export const theme = {}; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-03-start/src/features/auth/api/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/React-Application-Architecture-for-Production/40cd19895fa025e7c48127f187035ec451874061/code-stages/chapter-03-start/src/features/auth/api/.gitkeep -------------------------------------------------------------------------------- /code-stages/chapter-03-start/src/features/auth/components/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/React-Application-Architecture-for-Production/40cd19895fa025e7c48127f187035ec451874061/code-stages/chapter-03-start/src/features/auth/components/.gitkeep -------------------------------------------------------------------------------- /code-stages/chapter-03-start/src/features/auth/index.ts: -------------------------------------------------------------------------------- 1 | // types: 2 | export * from './types'; 3 | -------------------------------------------------------------------------------- /code-stages/chapter-03-start/src/features/auth/pages/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/React-Application-Architecture-for-Production/40cd19895fa025e7c48127f187035ec451874061/code-stages/chapter-03-start/src/features/auth/pages/.gitkeep -------------------------------------------------------------------------------- /code-stages/chapter-03-start/src/features/auth/types/index.ts: -------------------------------------------------------------------------------- 1 | import { Entity } from '@/types'; 2 | 3 | export type AuthUser = Entity & { 4 | email: string; 5 | organizationId: string; 6 | }; 7 | 8 | export type LoginData = { 9 | email: string; 10 | password: string; 11 | }; 12 | -------------------------------------------------------------------------------- /code-stages/chapter-03-start/src/features/jobs/api/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/React-Application-Architecture-for-Production/40cd19895fa025e7c48127f187035ec451874061/code-stages/chapter-03-start/src/features/jobs/api/.gitkeep -------------------------------------------------------------------------------- /code-stages/chapter-03-start/src/features/jobs/components/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/React-Application-Architecture-for-Production/40cd19895fa025e7c48127f187035ec451874061/code-stages/chapter-03-start/src/features/jobs/components/.gitkeep -------------------------------------------------------------------------------- /code-stages/chapter-03-start/src/features/jobs/index.ts: -------------------------------------------------------------------------------- 1 | // types: 2 | export * from './types'; 3 | -------------------------------------------------------------------------------- /code-stages/chapter-03-start/src/features/jobs/pages/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/React-Application-Architecture-for-Production/40cd19895fa025e7c48127f187035ec451874061/code-stages/chapter-03-start/src/features/jobs/pages/.gitkeep -------------------------------------------------------------------------------- /code-stages/chapter-03-start/src/features/jobs/types/index.ts: -------------------------------------------------------------------------------- 1 | import { Entity } from '@/types'; 2 | 3 | export type Job = Entity & { 4 | organizationId: string; 5 | position: string; 6 | info: string; 7 | location: string; 8 | department: string; 9 | }; 10 | 11 | export type CreateJobData = Pick< 12 | Job, 13 | 'position' | 'department' | 'location' | 'info' 14 | >; 15 | -------------------------------------------------------------------------------- /code-stages/chapter-03-start/src/features/organizations/api/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/React-Application-Architecture-for-Production/40cd19895fa025e7c48127f187035ec451874061/code-stages/chapter-03-start/src/features/organizations/api/.gitkeep -------------------------------------------------------------------------------- /code-stages/chapter-03-start/src/features/organizations/index.ts: -------------------------------------------------------------------------------- 1 | // types: 2 | export * from './types'; 3 | -------------------------------------------------------------------------------- /code-stages/chapter-03-start/src/features/organizations/pages/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/React-Application-Architecture-for-Production/40cd19895fa025e7c48127f187035ec451874061/code-stages/chapter-03-start/src/features/organizations/pages/.gitkeep -------------------------------------------------------------------------------- /code-stages/chapter-03-start/src/features/organizations/types/index.ts: -------------------------------------------------------------------------------- 1 | import { Entity } from '@/types'; 2 | 3 | export type Organization = Entity & { 4 | adminId: string; 5 | name: string; 6 | email: string; 7 | phone: string; 8 | info: string; 9 | }; 10 | -------------------------------------------------------------------------------- /code-stages/chapter-03-start/src/layouts/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/React-Application-Architecture-for-Production/40cd19895fa025e7c48127f187035ec451874061/code-stages/chapter-03-start/src/layouts/.gitkeep -------------------------------------------------------------------------------- /code-stages/chapter-03-start/src/lib/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/React-Application-Architecture-for-Production/40cd19895fa025e7c48127f187035ec451874061/code-stages/chapter-03-start/src/lib/.gitkeep -------------------------------------------------------------------------------- /code-stages/chapter-03-start/src/pages/_app.tsx: -------------------------------------------------------------------------------- 1 | import type { AppProps } from 'next/app'; 2 | 3 | import { AppProvider } from '@/providers/app'; 4 | 5 | const App = ({ Component, pageProps }: AppProps) => { 6 | return ( 7 | 8 | 9 | 10 | ); 11 | }; 12 | 13 | export default App; 14 | -------------------------------------------------------------------------------- /code-stages/chapter-03-start/src/pages/index.tsx: -------------------------------------------------------------------------------- 1 | const LandingPage = () => { 2 | return <>Landing Page; 3 | }; 4 | 5 | export default LandingPage; 6 | -------------------------------------------------------------------------------- /code-stages/chapter-03-start/src/providers/app.tsx: -------------------------------------------------------------------------------- 1 | import { ReactNode } from 'react'; 2 | 3 | type AppProviderProps = { 4 | children: ReactNode; 5 | }; 6 | 7 | export const AppProvider = ({ 8 | children, 9 | }: AppProviderProps) => { 10 | return <>{children}; 11 | }; 12 | -------------------------------------------------------------------------------- /code-stages/chapter-03-start/src/stores/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/React-Application-Architecture-for-Production/40cd19895fa025e7c48127f187035ec451874061/code-stages/chapter-03-start/src/stores/.gitkeep -------------------------------------------------------------------------------- /code-stages/chapter-03-start/src/testing/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/React-Application-Architecture-for-Production/40cd19895fa025e7c48127f187035ec451874061/code-stages/chapter-03-start/src/testing/.gitkeep -------------------------------------------------------------------------------- /code-stages/chapter-03-start/src/types/index.ts: -------------------------------------------------------------------------------- 1 | export type Entity = { 2 | id: string; 3 | createdAt: number; 4 | }; 5 | -------------------------------------------------------------------------------- /code-stages/chapter-03-start/src/utils/format.ts: -------------------------------------------------------------------------------- 1 | export const formatDate = (date: number | string) => { 2 | return new Date(date).toLocaleDateString('en-US', { 3 | month: 'long', 4 | year: 'numeric', 5 | day: 'numeric', 6 | }); 7 | }; 8 | -------------------------------------------------------------------------------- /code-stages/chapter-03-start/src/utils/uid.ts: -------------------------------------------------------------------------------- 1 | // https://gist.github.com/gordonbrander/2230317?permalink_comment_id=3443509#gistcomment-3443509 2 | export const uid = () => { 3 | return ( 4 | performance.now().toString(36) + 5 | Math.random().toString(36) 6 | ).replace(/\./g, ''); 7 | }; 8 | -------------------------------------------------------------------------------- /code-stages/chapter-03/src/components/button/index.ts: -------------------------------------------------------------------------------- 1 | export * from './button'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-03/src/components/form/index.ts: -------------------------------------------------------------------------------- 1 | export * from './input-field'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-03/src/components/link/index.ts: -------------------------------------------------------------------------------- 1 | export * from './link'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-03/src/components/link/link.stories.tsx: -------------------------------------------------------------------------------- 1 | import { Meta, Story } from '@storybook/react'; 2 | 3 | import { Link, LinkProps } from './link'; 4 | 5 | const meta: Meta = { 6 | title: 'Components/Link', 7 | component: Link, 8 | }; 9 | 10 | export default meta; 11 | 12 | const Template: Story = (props) => ( 13 | 14 | ); 15 | 16 | export const Default = Template.bind({}); 17 | 18 | Default.args = { 19 | href: '/', 20 | children: 'Click Me', 21 | }; 22 | -------------------------------------------------------------------------------- /code-stages/chapter-03/src/config/theme.ts: -------------------------------------------------------------------------------- 1 | import { extendTheme } from '@chakra-ui/react'; 2 | 3 | const colors = { 4 | primary: '#1a365d', 5 | primaryAccent: '#ffffff', 6 | }; 7 | 8 | const styles = { 9 | global: { 10 | 'html, body': { 11 | height: '100%', 12 | bg: 'gray.50', 13 | }, 14 | 15 | '#__next': { 16 | height: '100%', 17 | bg: 'gray.50', 18 | }, 19 | }, 20 | }; 21 | 22 | export const theme = extendTheme({ colors, styles }); 23 | -------------------------------------------------------------------------------- /code-stages/chapter-03/src/features/auth/api/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/React-Application-Architecture-for-Production/40cd19895fa025e7c48127f187035ec451874061/code-stages/chapter-03/src/features/auth/api/.gitkeep -------------------------------------------------------------------------------- /code-stages/chapter-03/src/features/auth/components/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/React-Application-Architecture-for-Production/40cd19895fa025e7c48127f187035ec451874061/code-stages/chapter-03/src/features/auth/components/.gitkeep -------------------------------------------------------------------------------- /code-stages/chapter-03/src/features/auth/index.ts: -------------------------------------------------------------------------------- 1 | // types: 2 | export * from './types'; 3 | -------------------------------------------------------------------------------- /code-stages/chapter-03/src/features/auth/pages/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/React-Application-Architecture-for-Production/40cd19895fa025e7c48127f187035ec451874061/code-stages/chapter-03/src/features/auth/pages/.gitkeep -------------------------------------------------------------------------------- /code-stages/chapter-03/src/features/auth/types/index.ts: -------------------------------------------------------------------------------- 1 | import { Entity } from '@/types'; 2 | 3 | export type AuthUser = Entity & { 4 | email: string; 5 | organizationId: string; 6 | }; 7 | 8 | export type LoginData = { 9 | email: string; 10 | password: string; 11 | }; 12 | -------------------------------------------------------------------------------- /code-stages/chapter-03/src/features/jobs/api/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/React-Application-Architecture-for-Production/40cd19895fa025e7c48127f187035ec451874061/code-stages/chapter-03/src/features/jobs/api/.gitkeep -------------------------------------------------------------------------------- /code-stages/chapter-03/src/features/jobs/components/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/React-Application-Architecture-for-Production/40cd19895fa025e7c48127f187035ec451874061/code-stages/chapter-03/src/features/jobs/components/.gitkeep -------------------------------------------------------------------------------- /code-stages/chapter-03/src/features/jobs/index.ts: -------------------------------------------------------------------------------- 1 | // types: 2 | export * from './types'; 3 | -------------------------------------------------------------------------------- /code-stages/chapter-03/src/features/jobs/pages/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/React-Application-Architecture-for-Production/40cd19895fa025e7c48127f187035ec451874061/code-stages/chapter-03/src/features/jobs/pages/.gitkeep -------------------------------------------------------------------------------- /code-stages/chapter-03/src/features/jobs/types/index.ts: -------------------------------------------------------------------------------- 1 | import { Entity } from '@/types'; 2 | 3 | export type Job = Entity & { 4 | organizationId: string; 5 | position: string; 6 | info: string; 7 | location: string; 8 | department: string; 9 | }; 10 | 11 | export type CreateJobData = Pick< 12 | Job, 13 | 'position' | 'department' | 'location' | 'info' 14 | >; 15 | -------------------------------------------------------------------------------- /code-stages/chapter-03/src/features/organizations/api/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/React-Application-Architecture-for-Production/40cd19895fa025e7c48127f187035ec451874061/code-stages/chapter-03/src/features/organizations/api/.gitkeep -------------------------------------------------------------------------------- /code-stages/chapter-03/src/features/organizations/index.ts: -------------------------------------------------------------------------------- 1 | // types: 2 | export * from './types'; 3 | -------------------------------------------------------------------------------- /code-stages/chapter-03/src/features/organizations/pages/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/React-Application-Architecture-for-Production/40cd19895fa025e7c48127f187035ec451874061/code-stages/chapter-03/src/features/organizations/pages/.gitkeep -------------------------------------------------------------------------------- /code-stages/chapter-03/src/features/organizations/types/index.ts: -------------------------------------------------------------------------------- 1 | import { Entity } from '@/types'; 2 | 3 | export type Organization = Entity & { 4 | adminId: string; 5 | name: string; 6 | email: string; 7 | phone: string; 8 | info: string; 9 | }; 10 | -------------------------------------------------------------------------------- /code-stages/chapter-03/src/layouts/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/React-Application-Architecture-for-Production/40cd19895fa025e7c48127f187035ec451874061/code-stages/chapter-03/src/layouts/.gitkeep -------------------------------------------------------------------------------- /code-stages/chapter-03/src/lib/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/React-Application-Architecture-for-Production/40cd19895fa025e7c48127f187035ec451874061/code-stages/chapter-03/src/lib/.gitkeep -------------------------------------------------------------------------------- /code-stages/chapter-03/src/pages/_app.tsx: -------------------------------------------------------------------------------- 1 | import type { AppProps } from 'next/app'; 2 | 3 | import { AppProvider } from '@/providers/app'; 4 | 5 | const App = ({ Component, pageProps }: AppProps) => { 6 | return ( 7 | 8 | 9 | 10 | ); 11 | }; 12 | 13 | export default App; 14 | -------------------------------------------------------------------------------- /code-stages/chapter-03/src/stores/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/React-Application-Architecture-for-Production/40cd19895fa025e7c48127f187035ec451874061/code-stages/chapter-03/src/stores/.gitkeep -------------------------------------------------------------------------------- /code-stages/chapter-03/src/testing/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/React-Application-Architecture-for-Production/40cd19895fa025e7c48127f187035ec451874061/code-stages/chapter-03/src/testing/.gitkeep -------------------------------------------------------------------------------- /code-stages/chapter-03/src/types/index.ts: -------------------------------------------------------------------------------- 1 | export type Entity = { 2 | id: string; 3 | createdAt: number; 4 | }; 5 | -------------------------------------------------------------------------------- /code-stages/chapter-03/src/utils/format.ts: -------------------------------------------------------------------------------- 1 | export const formatDate = (date: number | string) => { 2 | return new Date(date).toLocaleDateString('en-US', { 3 | month: 'long', 4 | year: 'numeric', 5 | day: 'numeric', 6 | }); 7 | }; 8 | -------------------------------------------------------------------------------- /code-stages/chapter-03/src/utils/uid.ts: -------------------------------------------------------------------------------- 1 | // https://gist.github.com/gordonbrander/2230317?permalink_comment_id=3443509#gistcomment-3443509 2 | export const uid = () => { 3 | return ( 4 | performance.now().toString(36) + 5 | Math.random().toString(36) 6 | ).replace(/\./g, ''); 7 | }; 8 | -------------------------------------------------------------------------------- /code-stages/chapter-04-start/src/components/button/index.ts: -------------------------------------------------------------------------------- 1 | export * from './button'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-04-start/src/components/content/content.tsx: -------------------------------------------------------------------------------- 1 | import { Box } from '@chakra-ui/react'; 2 | 3 | export type ContentProps = { 4 | children: string; 5 | }; 6 | 7 | export const Content = ({ children }: ContentProps) => { 8 | return ( 9 | 10 | {children} 11 | 12 | ); 13 | }; 14 | -------------------------------------------------------------------------------- /code-stages/chapter-04-start/src/components/content/index.ts: -------------------------------------------------------------------------------- 1 | export * from './content'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-04-start/src/components/data-table/index.ts: -------------------------------------------------------------------------------- 1 | export * from './data-table'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-04-start/src/components/form/index.ts: -------------------------------------------------------------------------------- 1 | export * from './input-field'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-04-start/src/components/info-card/index.ts: -------------------------------------------------------------------------------- 1 | export * from './info-card'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-04-start/src/components/link/index.ts: -------------------------------------------------------------------------------- 1 | export * from './link'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-04-start/src/components/loading/index.ts: -------------------------------------------------------------------------------- 1 | export * from './loading'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-04-start/src/components/loading/loading.stories.tsx: -------------------------------------------------------------------------------- 1 | import { Meta, Story } from '@storybook/react'; 2 | 3 | import { Loading } from './loading'; 4 | 5 | const meta: Meta = { 6 | title: 'Components/Loading', 7 | component: Loading, 8 | }; 9 | 10 | export default meta; 11 | 12 | const Template: Story = (props) => ; 13 | 14 | export const Default = Template.bind({}); 15 | -------------------------------------------------------------------------------- /code-stages/chapter-04-start/src/components/loading/loading.tsx: -------------------------------------------------------------------------------- 1 | import { Center, Spinner } from '@chakra-ui/react'; 2 | 3 | export const Loading = () => { 4 | return ( 5 |
6 | 11 |
12 | ); 13 | }; 14 | -------------------------------------------------------------------------------- /code-stages/chapter-04-start/src/components/not-found/index.ts: -------------------------------------------------------------------------------- 1 | export * from './not-found'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-04-start/src/components/not-found/not-found.stories.tsx: -------------------------------------------------------------------------------- 1 | import { Meta, Story } from '@storybook/react'; 2 | 3 | import { NotFound } from './not-found'; 4 | 5 | const meta: Meta = { 6 | title: 'Components/NotFound', 7 | component: NotFound, 8 | }; 9 | 10 | export default meta; 11 | 12 | const Template: Story = (props) => ( 13 | 14 | ); 15 | 16 | export const Default = Template.bind({}); 17 | -------------------------------------------------------------------------------- /code-stages/chapter-04-start/src/components/not-found/not-found.tsx: -------------------------------------------------------------------------------- 1 | import { NotAllowedIcon } from '@chakra-ui/icons'; 2 | import { 3 | Center, 4 | Heading, 5 | VStack, 6 | } from '@chakra-ui/react'; 7 | 8 | export const NotFound = () => { 9 | return ( 10 |
11 | 12 | 13 | Not Found 14 | 15 |
16 | ); 17 | }; 18 | -------------------------------------------------------------------------------- /code-stages/chapter-04-start/src/components/seo/index.ts: -------------------------------------------------------------------------------- 1 | export * from './seo'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-04-start/src/components/seo/seo.tsx: -------------------------------------------------------------------------------- 1 | export const Seo = () => { 2 | return <>Seo; 3 | }; 4 | -------------------------------------------------------------------------------- /code-stages/chapter-04-start/src/config/theme.ts: -------------------------------------------------------------------------------- 1 | import { extendTheme } from '@chakra-ui/react'; 2 | 3 | const colors = { 4 | primary: '#1a365d', 5 | primaryAccent: 'white', 6 | }; 7 | 8 | const styles = { 9 | global: { 10 | 'html, body': { 11 | height: '100%', 12 | bg: 'gray.50', 13 | }, 14 | 15 | '#__next': { 16 | height: '100%', 17 | bg: 'gray.50', 18 | }, 19 | }, 20 | }; 21 | 22 | export const theme = extendTheme({ colors, styles }); 23 | -------------------------------------------------------------------------------- /code-stages/chapter-04-start/src/features/auth/api/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/React-Application-Architecture-for-Production/40cd19895fa025e7c48127f187035ec451874061/code-stages/chapter-04-start/src/features/auth/api/.gitkeep -------------------------------------------------------------------------------- /code-stages/chapter-04-start/src/features/auth/components/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/React-Application-Architecture-for-Production/40cd19895fa025e7c48127f187035ec451874061/code-stages/chapter-04-start/src/features/auth/components/.gitkeep -------------------------------------------------------------------------------- /code-stages/chapter-04-start/src/features/auth/index.ts: -------------------------------------------------------------------------------- 1 | // types: 2 | export * from './types'; 3 | -------------------------------------------------------------------------------- /code-stages/chapter-04-start/src/features/auth/types/index.ts: -------------------------------------------------------------------------------- 1 | import { Entity } from '@/types'; 2 | 3 | export type AuthUser = Entity & { 4 | email: string; 5 | organizationId: string; 6 | }; 7 | 8 | export type LoginData = { 9 | email: string; 10 | password: string; 11 | }; 12 | -------------------------------------------------------------------------------- /code-stages/chapter-04-start/src/features/jobs/api/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/React-Application-Architecture-for-Production/40cd19895fa025e7c48127f187035ec451874061/code-stages/chapter-04-start/src/features/jobs/api/.gitkeep -------------------------------------------------------------------------------- /code-stages/chapter-04-start/src/features/jobs/components/create-job-form/index.ts: -------------------------------------------------------------------------------- 1 | export * from './create-job-form'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-04-start/src/features/jobs/components/dashboard-job-info/index.ts: -------------------------------------------------------------------------------- 1 | export * from './dashboard-job-info'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-04-start/src/features/jobs/components/jobs-list/index.ts: -------------------------------------------------------------------------------- 1 | export * from './jobs-list'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-04-start/src/features/jobs/components/public-job-info/index.ts: -------------------------------------------------------------------------------- 1 | export * from './public-job-info'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-04-start/src/features/jobs/index.ts: -------------------------------------------------------------------------------- 1 | // components: 2 | export * from './components/create-job-form'; 3 | export * from './components/dashboard-job-info'; 4 | export * from './components/jobs-list'; 5 | export * from './components/public-job-info'; 6 | 7 | // types: 8 | export * from './types'; 9 | -------------------------------------------------------------------------------- /code-stages/chapter-04-start/src/features/jobs/types/index.ts: -------------------------------------------------------------------------------- 1 | import { Entity } from '@/types'; 2 | 3 | export type Job = Entity & { 4 | organizationId: string; 5 | position: string; 6 | info: string; 7 | location: string; 8 | department: string; 9 | }; 10 | 11 | export type CreateJobData = Pick< 12 | Job, 13 | 'position' | 'department' | 'location' | 'info' 14 | >; 15 | -------------------------------------------------------------------------------- /code-stages/chapter-04-start/src/features/organizations/api/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/React-Application-Architecture-for-Production/40cd19895fa025e7c48127f187035ec451874061/code-stages/chapter-04-start/src/features/organizations/api/.gitkeep -------------------------------------------------------------------------------- /code-stages/chapter-04-start/src/features/organizations/components/organization-info/index.ts: -------------------------------------------------------------------------------- 1 | export * from './organization-info'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-04-start/src/features/organizations/index.ts: -------------------------------------------------------------------------------- 1 | // components: 2 | export * from './components/organization-info'; 3 | 4 | // types: 5 | export * from './types'; 6 | -------------------------------------------------------------------------------- /code-stages/chapter-04-start/src/features/organizations/types/index.ts: -------------------------------------------------------------------------------- 1 | import { Entity } from '@/types'; 2 | 3 | export type Organization = Entity & { 4 | adminId: string; 5 | name: string; 6 | email: string; 7 | phone: string; 8 | info: string; 9 | }; 10 | -------------------------------------------------------------------------------- /code-stages/chapter-04-start/src/lib/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/React-Application-Architecture-for-Production/40cd19895fa025e7c48127f187035ec451874061/code-stages/chapter-04-start/src/lib/.gitkeep -------------------------------------------------------------------------------- /code-stages/chapter-04-start/src/pages/_app.tsx: -------------------------------------------------------------------------------- 1 | import type { AppProps } from 'next/app'; 2 | 3 | import { AppProvider } from '@/providers/app'; 4 | 5 | const App = ({ Component, pageProps }: AppProps) => { 6 | return ( 7 | 8 | 9 | 10 | ); 11 | }; 12 | 13 | export default App; 14 | -------------------------------------------------------------------------------- /code-stages/chapter-04-start/src/stores/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/React-Application-Architecture-for-Production/40cd19895fa025e7c48127f187035ec451874061/code-stages/chapter-04-start/src/stores/.gitkeep -------------------------------------------------------------------------------- /code-stages/chapter-04-start/src/types/index.ts: -------------------------------------------------------------------------------- 1 | export type Entity = { 2 | id: string; 3 | createdAt: number; 4 | }; 5 | -------------------------------------------------------------------------------- /code-stages/chapter-04-start/src/utils/format.ts: -------------------------------------------------------------------------------- 1 | export const formatDate = (date: number | string) => { 2 | return new Date(date).toLocaleDateString('en-US', { 3 | month: 'long', 4 | year: 'numeric', 5 | day: 'numeric', 6 | }); 7 | }; 8 | -------------------------------------------------------------------------------- /code-stages/chapter-04-start/src/utils/uid.ts: -------------------------------------------------------------------------------- 1 | // https://gist.github.com/gordonbrander/2230317?permalink_comment_id=3443509#gistcomment-3443509 2 | export const uid = () => { 3 | return ( 4 | performance.now().toString(36) + 5 | Math.random().toString(36) 6 | ).replace(/\./g, ''); 7 | }; 8 | -------------------------------------------------------------------------------- /code-stages/chapter-04/src/components/button/index.ts: -------------------------------------------------------------------------------- 1 | export * from './button'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-04/src/components/content/content.tsx: -------------------------------------------------------------------------------- 1 | import { Box } from '@chakra-ui/react'; 2 | 3 | export type ContentProps = { 4 | children: string; 5 | }; 6 | 7 | export const Content = ({ children }: ContentProps) => { 8 | return ( 9 | 10 | {children} 11 | 12 | ); 13 | }; 14 | -------------------------------------------------------------------------------- /code-stages/chapter-04/src/components/content/index.ts: -------------------------------------------------------------------------------- 1 | export * from './content'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-04/src/components/data-table/index.ts: -------------------------------------------------------------------------------- 1 | export * from './data-table'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-04/src/components/form/index.ts: -------------------------------------------------------------------------------- 1 | export * from './input-field'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-04/src/components/info-card/index.ts: -------------------------------------------------------------------------------- 1 | export * from './info-card'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-04/src/components/link/index.ts: -------------------------------------------------------------------------------- 1 | export * from './link'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-04/src/components/link/link.stories.tsx: -------------------------------------------------------------------------------- 1 | import { Meta, Story } from '@storybook/react'; 2 | 3 | import { Link, LinkProps } from './link'; 4 | 5 | const meta: Meta = { 6 | title: 'Components/Link', 7 | component: Link, 8 | }; 9 | 10 | export default meta; 11 | 12 | const Template: Story = (props) => ( 13 | 14 | ); 15 | 16 | export const Default = Template.bind({}); 17 | 18 | Default.args = { 19 | href: '/', 20 | children: 'Click Me', 21 | }; 22 | -------------------------------------------------------------------------------- /code-stages/chapter-04/src/components/loading/index.ts: -------------------------------------------------------------------------------- 1 | export * from './loading'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-04/src/components/loading/loading.stories.tsx: -------------------------------------------------------------------------------- 1 | import { Meta, Story } from '@storybook/react'; 2 | 3 | import { Loading } from './loading'; 4 | 5 | const meta: Meta = { 6 | title: 'Components/Loading', 7 | component: Loading, 8 | }; 9 | 10 | export default meta; 11 | 12 | const Template: Story = (props) => ; 13 | 14 | export const Default = Template.bind({}); 15 | -------------------------------------------------------------------------------- /code-stages/chapter-04/src/components/loading/loading.tsx: -------------------------------------------------------------------------------- 1 | import { Center, Spinner } from '@chakra-ui/react'; 2 | 3 | export const Loading = () => { 4 | return ( 5 |
6 | 11 |
12 | ); 13 | }; 14 | -------------------------------------------------------------------------------- /code-stages/chapter-04/src/components/not-found/index.ts: -------------------------------------------------------------------------------- 1 | export * from './not-found'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-04/src/components/not-found/not-found.stories.tsx: -------------------------------------------------------------------------------- 1 | import { Meta, Story } from '@storybook/react'; 2 | 3 | import { NotFound } from './not-found'; 4 | 5 | const meta: Meta = { 6 | title: 'Components/NotFound', 7 | component: NotFound, 8 | }; 9 | 10 | export default meta; 11 | 12 | const Template: Story = (props) => ( 13 | 14 | ); 15 | 16 | export const Default = Template.bind({}); 17 | -------------------------------------------------------------------------------- /code-stages/chapter-04/src/components/not-found/not-found.tsx: -------------------------------------------------------------------------------- 1 | import { NotAllowedIcon } from '@chakra-ui/icons'; 2 | import { 3 | Center, 4 | Heading, 5 | VStack, 6 | } from '@chakra-ui/react'; 7 | 8 | export const NotFound = () => { 9 | return ( 10 |
11 | 12 | 13 | Not Found 14 | 15 |
16 | ); 17 | }; 18 | -------------------------------------------------------------------------------- /code-stages/chapter-04/src/components/seo/index.ts: -------------------------------------------------------------------------------- 1 | export * from './seo'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-04/src/components/seo/seo.tsx: -------------------------------------------------------------------------------- 1 | import Head from 'next/head'; 2 | 3 | export type SeoProps = { 4 | title: string; 5 | }; 6 | 7 | export const Seo = ({ title }: SeoProps) => { 8 | return ( 9 | 10 | {title} 11 | 12 | ); 13 | }; 14 | -------------------------------------------------------------------------------- /code-stages/chapter-04/src/config/theme.ts: -------------------------------------------------------------------------------- 1 | import { extendTheme } from '@chakra-ui/react'; 2 | 3 | const colors = { 4 | primary: '#1a365d', 5 | primaryAccent: 'white', 6 | }; 7 | 8 | const styles = { 9 | global: { 10 | 'html, body': { 11 | height: '100%', 12 | bg: 'gray.50', 13 | }, 14 | 15 | '#__next': { 16 | height: '100%', 17 | bg: 'gray.50', 18 | }, 19 | }, 20 | }; 21 | 22 | export const theme = extendTheme({ colors, styles }); 23 | -------------------------------------------------------------------------------- /code-stages/chapter-04/src/features/auth/api/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/React-Application-Architecture-for-Production/40cd19895fa025e7c48127f187035ec451874061/code-stages/chapter-04/src/features/auth/api/.gitkeep -------------------------------------------------------------------------------- /code-stages/chapter-04/src/features/auth/components/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/React-Application-Architecture-for-Production/40cd19895fa025e7c48127f187035ec451874061/code-stages/chapter-04/src/features/auth/components/.gitkeep -------------------------------------------------------------------------------- /code-stages/chapter-04/src/features/auth/index.ts: -------------------------------------------------------------------------------- 1 | // types: 2 | export * from './types'; 3 | -------------------------------------------------------------------------------- /code-stages/chapter-04/src/features/auth/types/index.ts: -------------------------------------------------------------------------------- 1 | import { Entity } from '@/types'; 2 | 3 | export type AuthUser = Entity & { 4 | email: string; 5 | organizationId: string; 6 | }; 7 | 8 | export type LoginData = { 9 | email: string; 10 | password: string; 11 | }; 12 | -------------------------------------------------------------------------------- /code-stages/chapter-04/src/features/jobs/api/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/React-Application-Architecture-for-Production/40cd19895fa025e7c48127f187035ec451874061/code-stages/chapter-04/src/features/jobs/api/.gitkeep -------------------------------------------------------------------------------- /code-stages/chapter-04/src/features/jobs/components/create-job-form/index.ts: -------------------------------------------------------------------------------- 1 | export * from './create-job-form'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-04/src/features/jobs/components/dashboard-job-info/index.ts: -------------------------------------------------------------------------------- 1 | export * from './dashboard-job-info'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-04/src/features/jobs/components/jobs-list/index.ts: -------------------------------------------------------------------------------- 1 | export * from './jobs-list'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-04/src/features/jobs/components/public-job-info/index.ts: -------------------------------------------------------------------------------- 1 | export * from './public-job-info'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-04/src/features/jobs/index.ts: -------------------------------------------------------------------------------- 1 | // components: 2 | export * from './components/create-job-form'; 3 | export * from './components/dashboard-job-info'; 4 | export * from './components/jobs-list'; 5 | export * from './components/public-job-info'; 6 | 7 | // types: 8 | export * from './types'; 9 | -------------------------------------------------------------------------------- /code-stages/chapter-04/src/features/jobs/types/index.ts: -------------------------------------------------------------------------------- 1 | import { Entity } from '@/types'; 2 | 3 | export type Job = Entity & { 4 | organizationId: string; 5 | position: string; 6 | info: string; 7 | location: string; 8 | department: string; 9 | }; 10 | 11 | export type CreateJobData = Pick< 12 | Job, 13 | 'position' | 'department' | 'location' | 'info' 14 | >; 15 | -------------------------------------------------------------------------------- /code-stages/chapter-04/src/features/organizations/api/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/React-Application-Architecture-for-Production/40cd19895fa025e7c48127f187035ec451874061/code-stages/chapter-04/src/features/organizations/api/.gitkeep -------------------------------------------------------------------------------- /code-stages/chapter-04/src/features/organizations/components/organization-info/index.ts: -------------------------------------------------------------------------------- 1 | export * from './organization-info'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-04/src/features/organizations/index.ts: -------------------------------------------------------------------------------- 1 | // components: 2 | export * from './components/organization-info'; 3 | 4 | // types: 5 | export * from './types'; 6 | -------------------------------------------------------------------------------- /code-stages/chapter-04/src/features/organizations/types/index.ts: -------------------------------------------------------------------------------- 1 | import { Entity } from '@/types'; 2 | 3 | export type Organization = Entity & { 4 | adminId: string; 5 | name: string; 6 | email: string; 7 | phone: string; 8 | info: string; 9 | }; 10 | -------------------------------------------------------------------------------- /code-stages/chapter-04/src/lib/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/React-Application-Architecture-for-Production/40cd19895fa025e7c48127f187035ec451874061/code-stages/chapter-04/src/lib/.gitkeep -------------------------------------------------------------------------------- /code-stages/chapter-04/src/pages/404.tsx: -------------------------------------------------------------------------------- 1 | import { Center } from '@chakra-ui/react'; 2 | 3 | import { Link } from '@/components/link'; 4 | import { NotFound } from '@/components/not-found'; 5 | 6 | const NotFoundPage = () => { 7 | return ( 8 | <> 9 | 10 |
11 | Home 12 |
13 | 14 | ); 15 | }; 16 | 17 | export default NotFoundPage; 18 | -------------------------------------------------------------------------------- /code-stages/chapter-04/src/stores/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/React-Application-Architecture-for-Production/40cd19895fa025e7c48127f187035ec451874061/code-stages/chapter-04/src/stores/.gitkeep -------------------------------------------------------------------------------- /code-stages/chapter-04/src/types/index.ts: -------------------------------------------------------------------------------- 1 | export type Entity = { 2 | id: string; 3 | createdAt: number; 4 | }; 5 | -------------------------------------------------------------------------------- /code-stages/chapter-04/src/utils/format.ts: -------------------------------------------------------------------------------- 1 | export const formatDate = (date: number | string) => { 2 | return new Date(date).toLocaleDateString('en-US', { 3 | month: 'long', 4 | year: 'numeric', 5 | day: 'numeric', 6 | }); 7 | }; 8 | -------------------------------------------------------------------------------- /code-stages/chapter-04/src/utils/uid.ts: -------------------------------------------------------------------------------- 1 | // https://gist.github.com/gordonbrander/2230317?permalink_comment_id=3443509#gistcomment-3443509 2 | export const uid = () => { 3 | return ( 4 | performance.now().toString(36) + 5 | Math.random().toString(36) 6 | ).replace(/\./g, ''); 7 | }; 8 | -------------------------------------------------------------------------------- /code-stages/chapter-05-start/src/components/button/index.ts: -------------------------------------------------------------------------------- 1 | export * from './button'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-05-start/src/components/content/content.tsx: -------------------------------------------------------------------------------- 1 | import { Box } from '@chakra-ui/react'; 2 | 3 | export type ContentProps = { 4 | children: string; 5 | }; 6 | 7 | export const Content = ({ children }: ContentProps) => { 8 | return ( 9 | 10 | {children} 11 | 12 | ); 13 | }; 14 | -------------------------------------------------------------------------------- /code-stages/chapter-05-start/src/components/content/index.ts: -------------------------------------------------------------------------------- 1 | export * from './content'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-05-start/src/components/data-table/index.ts: -------------------------------------------------------------------------------- 1 | export * from './data-table'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-05-start/src/components/form/index.ts: -------------------------------------------------------------------------------- 1 | export * from './input-field'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-05-start/src/components/info-card/index.ts: -------------------------------------------------------------------------------- 1 | export * from './info-card'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-05-start/src/components/link/index.ts: -------------------------------------------------------------------------------- 1 | export * from './link'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-05-start/src/components/loading/index.ts: -------------------------------------------------------------------------------- 1 | export * from './loading'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-05-start/src/components/loading/loading.stories.tsx: -------------------------------------------------------------------------------- 1 | import { Meta, Story } from '@storybook/react'; 2 | 3 | import { Loading } from './loading'; 4 | 5 | const meta: Meta = { 6 | title: 'Components/Loading', 7 | component: Loading, 8 | }; 9 | 10 | export default meta; 11 | 12 | const Template: Story = (props) => ; 13 | 14 | export const Default = Template.bind({}); 15 | -------------------------------------------------------------------------------- /code-stages/chapter-05-start/src/components/loading/loading.tsx: -------------------------------------------------------------------------------- 1 | import { Center, Spinner } from '@chakra-ui/react'; 2 | 3 | export const Loading = () => { 4 | return ( 5 |
6 | 11 |
12 | ); 13 | }; 14 | -------------------------------------------------------------------------------- /code-stages/chapter-05-start/src/components/not-found/index.ts: -------------------------------------------------------------------------------- 1 | export * from './not-found'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-05-start/src/components/not-found/not-found.stories.tsx: -------------------------------------------------------------------------------- 1 | import { Meta, Story } from '@storybook/react'; 2 | 3 | import { NotFound } from './not-found'; 4 | 5 | const meta: Meta = { 6 | title: 'Components/NotFound', 7 | component: NotFound, 8 | }; 9 | 10 | export default meta; 11 | 12 | const Template: Story = (props) => ( 13 | 14 | ); 15 | 16 | export const Default = Template.bind({}); 17 | -------------------------------------------------------------------------------- /code-stages/chapter-05-start/src/components/not-found/not-found.tsx: -------------------------------------------------------------------------------- 1 | import { NotAllowedIcon } from '@chakra-ui/icons'; 2 | import { 3 | Center, 4 | Heading, 5 | VStack, 6 | } from '@chakra-ui/react'; 7 | 8 | export const NotFound = () => { 9 | return ( 10 |
11 | 12 | 13 | Not Found 14 | 15 |
16 | ); 17 | }; 18 | -------------------------------------------------------------------------------- /code-stages/chapter-05-start/src/components/seo/index.ts: -------------------------------------------------------------------------------- 1 | export * from './seo'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-05-start/src/components/seo/seo.tsx: -------------------------------------------------------------------------------- 1 | import Head from 'next/head'; 2 | 3 | export type SeoProps = { 4 | title: string; 5 | }; 6 | 7 | export const Seo = ({ title }: SeoProps) => { 8 | return ( 9 | 10 | {title} 11 | 12 | ); 13 | }; 14 | -------------------------------------------------------------------------------- /code-stages/chapter-05-start/src/config/theme.ts: -------------------------------------------------------------------------------- 1 | import { extendTheme } from '@chakra-ui/react'; 2 | 3 | const colors = { 4 | primary: '#1a365d', 5 | primaryAccent: 'white', 6 | }; 7 | 8 | const styles = { 9 | global: { 10 | 'html, body': { 11 | height: '100%', 12 | bg: 'gray.50', 13 | }, 14 | 15 | '#__next': { 16 | height: '100%', 17 | bg: 'gray.50', 18 | }, 19 | }, 20 | }; 21 | 22 | export const theme = extendTheme({ colors, styles }); 23 | -------------------------------------------------------------------------------- /code-stages/chapter-05-start/src/features/auth/api/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/React-Application-Architecture-for-Production/40cd19895fa025e7c48127f187035ec451874061/code-stages/chapter-05-start/src/features/auth/api/.gitkeep -------------------------------------------------------------------------------- /code-stages/chapter-05-start/src/features/auth/components/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/React-Application-Architecture-for-Production/40cd19895fa025e7c48127f187035ec451874061/code-stages/chapter-05-start/src/features/auth/components/.gitkeep -------------------------------------------------------------------------------- /code-stages/chapter-05-start/src/features/auth/index.ts: -------------------------------------------------------------------------------- 1 | // types: 2 | export * from './types'; 3 | -------------------------------------------------------------------------------- /code-stages/chapter-05-start/src/features/auth/types/index.ts: -------------------------------------------------------------------------------- 1 | import { Entity } from '@/types'; 2 | 3 | export type AuthUser = Entity & { 4 | email: string; 5 | organizationId: string; 6 | }; 7 | 8 | export type LoginData = { 9 | email: string; 10 | password: string; 11 | }; 12 | -------------------------------------------------------------------------------- /code-stages/chapter-05-start/src/features/jobs/api/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/React-Application-Architecture-for-Production/40cd19895fa025e7c48127f187035ec451874061/code-stages/chapter-05-start/src/features/jobs/api/.gitkeep -------------------------------------------------------------------------------- /code-stages/chapter-05-start/src/features/jobs/components/create-job-form/index.ts: -------------------------------------------------------------------------------- 1 | export * from './create-job-form'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-05-start/src/features/jobs/components/dashboard-job-info/index.ts: -------------------------------------------------------------------------------- 1 | export * from './dashboard-job-info'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-05-start/src/features/jobs/components/jobs-list/index.ts: -------------------------------------------------------------------------------- 1 | export * from './jobs-list'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-05-start/src/features/jobs/components/public-job-info/index.ts: -------------------------------------------------------------------------------- 1 | export * from './public-job-info'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-05-start/src/features/jobs/index.ts: -------------------------------------------------------------------------------- 1 | // components: 2 | export * from './components/create-job-form'; 3 | export * from './components/dashboard-job-info'; 4 | export * from './components/jobs-list'; 5 | export * from './components/public-job-info'; 6 | 7 | // types: 8 | export * from './types'; 9 | -------------------------------------------------------------------------------- /code-stages/chapter-05-start/src/features/jobs/types/index.ts: -------------------------------------------------------------------------------- 1 | import { Entity } from '@/types'; 2 | 3 | export type Job = Entity & { 4 | organizationId: string; 5 | position: string; 6 | info: string; 7 | location: string; 8 | department: string; 9 | }; 10 | 11 | export type CreateJobData = Pick< 12 | Job, 13 | 'position' | 'department' | 'location' | 'info' 14 | >; 15 | -------------------------------------------------------------------------------- /code-stages/chapter-05-start/src/features/organizations/api/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/React-Application-Architecture-for-Production/40cd19895fa025e7c48127f187035ec451874061/code-stages/chapter-05-start/src/features/organizations/api/.gitkeep -------------------------------------------------------------------------------- /code-stages/chapter-05-start/src/features/organizations/components/organization-info/index.ts: -------------------------------------------------------------------------------- 1 | export * from './organization-info'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-05-start/src/features/organizations/index.ts: -------------------------------------------------------------------------------- 1 | // components: 2 | export * from './components/organization-info'; 3 | 4 | // types: 5 | export * from './types'; 6 | -------------------------------------------------------------------------------- /code-stages/chapter-05-start/src/features/organizations/types/index.ts: -------------------------------------------------------------------------------- 1 | import { Entity } from '@/types'; 2 | 3 | export type Organization = Entity & { 4 | adminId: string; 5 | name: string; 6 | email: string; 7 | phone: string; 8 | info: string; 9 | }; 10 | -------------------------------------------------------------------------------- /code-stages/chapter-05-start/src/pages/404.tsx: -------------------------------------------------------------------------------- 1 | import { Center } from '@chakra-ui/react'; 2 | 3 | import { Link } from '@/components/link'; 4 | import { NotFound } from '@/components/not-found'; 5 | 6 | const NotFoundPage = () => { 7 | return ( 8 | <> 9 | 10 |
11 | Home 12 |
13 | 14 | ); 15 | }; 16 | 17 | export default NotFoundPage; 18 | -------------------------------------------------------------------------------- /code-stages/chapter-05-start/src/stores/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/React-Application-Architecture-for-Production/40cd19895fa025e7c48127f187035ec451874061/code-stages/chapter-05-start/src/stores/.gitkeep -------------------------------------------------------------------------------- /code-stages/chapter-05-start/src/testing/mocks/browser.ts: -------------------------------------------------------------------------------- 1 | export const worker = {}; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-05-start/src/testing/mocks/db.ts: -------------------------------------------------------------------------------- 1 | export const db = {}; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-05-start/src/testing/mocks/handlers/auth.ts: -------------------------------------------------------------------------------- 1 | export const authHandlers = []; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-05-start/src/testing/mocks/handlers/index.ts: -------------------------------------------------------------------------------- 1 | export const handlers = []; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-05-start/src/testing/mocks/handlers/jobs.ts: -------------------------------------------------------------------------------- 1 | export const jobsHandlers = []; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-05-start/src/testing/mocks/handlers/organizations.ts: -------------------------------------------------------------------------------- 1 | export const organizationsHandlers = []; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-05-start/src/testing/mocks/index.ts: -------------------------------------------------------------------------------- 1 | export * from './handlers'; 2 | 3 | export * from './db'; 4 | -------------------------------------------------------------------------------- /code-stages/chapter-05-start/src/testing/mocks/initialize.ts: -------------------------------------------------------------------------------- 1 | export const initializeMocks = () => {}; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-05-start/src/testing/mocks/seed-db.ts: -------------------------------------------------------------------------------- 1 | export const seedDb = () => {}; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-05-start/src/testing/mocks/server.ts: -------------------------------------------------------------------------------- 1 | export const server = {}; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-05-start/src/types/index.ts: -------------------------------------------------------------------------------- 1 | export type Entity = { 2 | id: string; 3 | createdAt: number; 4 | }; 5 | -------------------------------------------------------------------------------- /code-stages/chapter-05-start/src/utils/format.ts: -------------------------------------------------------------------------------- 1 | export const formatDate = (date: number | string) => { 2 | return new Date(date).toLocaleDateString('en-US', { 3 | month: 'long', 4 | year: 'numeric', 5 | day: 'numeric', 6 | }); 7 | }; 8 | -------------------------------------------------------------------------------- /code-stages/chapter-05-start/src/utils/uid.ts: -------------------------------------------------------------------------------- 1 | // https://gist.github.com/gordonbrander/2230317?permalink_comment_id=3443509#gistcomment-3443509 2 | export const uid = () => { 3 | return ( 4 | performance.now().toString(36) + 5 | Math.random().toString(36) 6 | ).replace(/\./g, ''); 7 | }; 8 | -------------------------------------------------------------------------------- /code-stages/chapter-05/src/components/button/index.ts: -------------------------------------------------------------------------------- 1 | export * from './button'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-05/src/components/content/content.tsx: -------------------------------------------------------------------------------- 1 | import { Box } from '@chakra-ui/react'; 2 | 3 | export type ContentProps = { 4 | children: string; 5 | }; 6 | 7 | export const Content = ({ children }: ContentProps) => { 8 | return ( 9 | 10 | {children} 11 | 12 | ); 13 | }; 14 | -------------------------------------------------------------------------------- /code-stages/chapter-05/src/components/content/index.ts: -------------------------------------------------------------------------------- 1 | export * from './content'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-05/src/components/data-table/index.ts: -------------------------------------------------------------------------------- 1 | export * from './data-table'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-05/src/components/form/index.ts: -------------------------------------------------------------------------------- 1 | export * from './input-field'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-05/src/components/info-card/index.ts: -------------------------------------------------------------------------------- 1 | export * from './info-card'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-05/src/components/link/index.ts: -------------------------------------------------------------------------------- 1 | export * from './link'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-05/src/components/link/link.stories.tsx: -------------------------------------------------------------------------------- 1 | import { Meta, Story } from '@storybook/react'; 2 | 3 | import { Link, LinkProps } from './link'; 4 | 5 | const meta: Meta = { 6 | title: 'Components/Link', 7 | component: Link, 8 | }; 9 | 10 | export default meta; 11 | 12 | const Template: Story = (props) => ( 13 | 14 | ); 15 | 16 | export const Default = Template.bind({}); 17 | 18 | Default.args = { 19 | href: '/', 20 | children: 'Click Me', 21 | }; 22 | -------------------------------------------------------------------------------- /code-stages/chapter-05/src/components/loading/index.ts: -------------------------------------------------------------------------------- 1 | export * from './loading'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-05/src/components/loading/loading.stories.tsx: -------------------------------------------------------------------------------- 1 | import { Meta, Story } from '@storybook/react'; 2 | 3 | import { Loading } from './loading'; 4 | 5 | const meta: Meta = { 6 | title: 'Components/Loading', 7 | component: Loading, 8 | }; 9 | 10 | export default meta; 11 | 12 | const Template: Story = (props) => ; 13 | 14 | export const Default = Template.bind({}); 15 | -------------------------------------------------------------------------------- /code-stages/chapter-05/src/components/loading/loading.tsx: -------------------------------------------------------------------------------- 1 | import { Center, Spinner } from '@chakra-ui/react'; 2 | 3 | export const Loading = () => { 4 | return ( 5 |
6 | 11 |
12 | ); 13 | }; 14 | -------------------------------------------------------------------------------- /code-stages/chapter-05/src/components/not-found/index.ts: -------------------------------------------------------------------------------- 1 | export * from './not-found'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-05/src/components/not-found/not-found.stories.tsx: -------------------------------------------------------------------------------- 1 | import { Meta, Story } from '@storybook/react'; 2 | 3 | import { NotFound } from './not-found'; 4 | 5 | const meta: Meta = { 6 | title: 'Components/NotFound', 7 | component: NotFound, 8 | }; 9 | 10 | export default meta; 11 | 12 | const Template: Story = (props) => ( 13 | 14 | ); 15 | 16 | export const Default = Template.bind({}); 17 | -------------------------------------------------------------------------------- /code-stages/chapter-05/src/components/not-found/not-found.tsx: -------------------------------------------------------------------------------- 1 | import { NotAllowedIcon } from '@chakra-ui/icons'; 2 | import { 3 | Center, 4 | Heading, 5 | VStack, 6 | } from '@chakra-ui/react'; 7 | 8 | export const NotFound = () => { 9 | return ( 10 |
11 | 12 | 13 | Not Found 14 | 15 |
16 | ); 17 | }; 18 | -------------------------------------------------------------------------------- /code-stages/chapter-05/src/components/seo/index.ts: -------------------------------------------------------------------------------- 1 | export * from './seo'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-05/src/components/seo/seo.tsx: -------------------------------------------------------------------------------- 1 | import Head from 'next/head'; 2 | 3 | export type SeoProps = { 4 | title: string; 5 | }; 6 | 7 | export const Seo = ({ title }: SeoProps) => { 8 | return ( 9 | 10 | {title} 11 | 12 | ); 13 | }; 14 | -------------------------------------------------------------------------------- /code-stages/chapter-05/src/config/theme.ts: -------------------------------------------------------------------------------- 1 | import { extendTheme } from '@chakra-ui/react'; 2 | 3 | const colors = { 4 | primary: '#1a365d', 5 | primaryAccent: 'white', 6 | }; 7 | 8 | const styles = { 9 | global: { 10 | 'html, body': { 11 | height: '100%', 12 | bg: 'gray.50', 13 | }, 14 | 15 | '#__next': { 16 | height: '100%', 17 | bg: 'gray.50', 18 | }, 19 | }, 20 | }; 21 | 22 | export const theme = extendTheme({ colors, styles }); 23 | -------------------------------------------------------------------------------- /code-stages/chapter-05/src/features/auth/api/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/React-Application-Architecture-for-Production/40cd19895fa025e7c48127f187035ec451874061/code-stages/chapter-05/src/features/auth/api/.gitkeep -------------------------------------------------------------------------------- /code-stages/chapter-05/src/features/auth/components/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/React-Application-Architecture-for-Production/40cd19895fa025e7c48127f187035ec451874061/code-stages/chapter-05/src/features/auth/components/.gitkeep -------------------------------------------------------------------------------- /code-stages/chapter-05/src/features/auth/index.ts: -------------------------------------------------------------------------------- 1 | // types: 2 | export * from './types'; 3 | -------------------------------------------------------------------------------- /code-stages/chapter-05/src/features/auth/types/index.ts: -------------------------------------------------------------------------------- 1 | import { Entity } from '@/types'; 2 | 3 | export type AuthUser = Entity & { 4 | email: string; 5 | organizationId: string; 6 | }; 7 | 8 | export type LoginData = { 9 | email: string; 10 | password: string; 11 | }; 12 | -------------------------------------------------------------------------------- /code-stages/chapter-05/src/features/jobs/api/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/React-Application-Architecture-for-Production/40cd19895fa025e7c48127f187035ec451874061/code-stages/chapter-05/src/features/jobs/api/.gitkeep -------------------------------------------------------------------------------- /code-stages/chapter-05/src/features/jobs/components/create-job-form/index.ts: -------------------------------------------------------------------------------- 1 | export * from './create-job-form'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-05/src/features/jobs/components/dashboard-job-info/index.ts: -------------------------------------------------------------------------------- 1 | export * from './dashboard-job-info'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-05/src/features/jobs/components/jobs-list/index.ts: -------------------------------------------------------------------------------- 1 | export * from './jobs-list'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-05/src/features/jobs/components/public-job-info/index.ts: -------------------------------------------------------------------------------- 1 | export * from './public-job-info'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-05/src/features/jobs/index.ts: -------------------------------------------------------------------------------- 1 | // components: 2 | export * from './components/create-job-form'; 3 | export * from './components/dashboard-job-info'; 4 | export * from './components/jobs-list'; 5 | export * from './components/public-job-info'; 6 | 7 | // types: 8 | export * from './types'; 9 | -------------------------------------------------------------------------------- /code-stages/chapter-05/src/features/jobs/types/index.ts: -------------------------------------------------------------------------------- 1 | import { Entity } from '@/types'; 2 | 3 | export type Job = Entity & { 4 | organizationId: string; 5 | position: string; 6 | info: string; 7 | location: string; 8 | department: string; 9 | }; 10 | 11 | export type CreateJobData = Pick< 12 | Job, 13 | 'position' | 'department' | 'location' | 'info' 14 | >; 15 | -------------------------------------------------------------------------------- /code-stages/chapter-05/src/features/organizations/api/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/React-Application-Architecture-for-Production/40cd19895fa025e7c48127f187035ec451874061/code-stages/chapter-05/src/features/organizations/api/.gitkeep -------------------------------------------------------------------------------- /code-stages/chapter-05/src/features/organizations/components/organization-info/index.ts: -------------------------------------------------------------------------------- 1 | export * from './organization-info'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-05/src/features/organizations/index.ts: -------------------------------------------------------------------------------- 1 | // components: 2 | export * from './components/organization-info'; 3 | 4 | // types: 5 | export * from './types'; 6 | -------------------------------------------------------------------------------- /code-stages/chapter-05/src/features/organizations/types/index.ts: -------------------------------------------------------------------------------- 1 | import { Entity } from '@/types'; 2 | 3 | export type Organization = Entity & { 4 | adminId: string; 5 | name: string; 6 | email: string; 7 | phone: string; 8 | info: string; 9 | }; 10 | -------------------------------------------------------------------------------- /code-stages/chapter-05/src/pages/404.tsx: -------------------------------------------------------------------------------- 1 | import { Center } from '@chakra-ui/react'; 2 | 3 | import { Link } from '@/components/link'; 4 | import { NotFound } from '@/components/not-found'; 5 | 6 | const NotFoundPage = () => { 7 | return ( 8 | <> 9 | 10 |
11 | Home 12 |
13 | 14 | ); 15 | }; 16 | 17 | export default NotFoundPage; 18 | -------------------------------------------------------------------------------- /code-stages/chapter-05/src/stores/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/React-Application-Architecture-for-Production/40cd19895fa025e7c48127f187035ec451874061/code-stages/chapter-05/src/stores/.gitkeep -------------------------------------------------------------------------------- /code-stages/chapter-05/src/testing/mocks/browser.ts: -------------------------------------------------------------------------------- 1 | import { setupWorker } from 'msw'; 2 | 3 | import { handlers } from './handlers'; 4 | 5 | export const worker = setupWorker(...handlers); 6 | -------------------------------------------------------------------------------- /code-stages/chapter-05/src/testing/mocks/index.ts: -------------------------------------------------------------------------------- 1 | export * from './handlers'; 2 | 3 | export * from './db'; 4 | -------------------------------------------------------------------------------- /code-stages/chapter-05/src/testing/mocks/initialize.ts: -------------------------------------------------------------------------------- 1 | import { IS_SERVER } from '@/config/constants'; 2 | 3 | import { seedDb } from './seed-db'; 4 | 5 | const initializeMocks = () => { 6 | if (IS_SERVER) { 7 | const { server } = require('./server'); 8 | server.listen(); 9 | } else { 10 | const { worker } = require('./browser'); 11 | worker.start(); 12 | } 13 | seedDb(); 14 | }; 15 | 16 | initializeMocks(); 17 | -------------------------------------------------------------------------------- /code-stages/chapter-05/src/testing/mocks/seed-db.ts: -------------------------------------------------------------------------------- 1 | import { testData } from '../test-data'; 2 | 3 | import { db } from './db'; 4 | 5 | export const seedDb = () => { 6 | const userCount = db.user.count(); 7 | 8 | if (userCount > 0) return; 9 | 10 | testData.users.forEach((user) => db.user.create(user)); 11 | 12 | testData.organizations.forEach((organization) => 13 | db.organization.create(organization) 14 | ); 15 | 16 | testData.jobs.forEach((job) => db.job.create(job)); 17 | }; 18 | -------------------------------------------------------------------------------- /code-stages/chapter-05/src/testing/mocks/server.ts: -------------------------------------------------------------------------------- 1 | import { setupServer } from 'msw/node'; 2 | 3 | import { handlers } from './handlers'; 4 | 5 | export const server = setupServer(...handlers); 6 | -------------------------------------------------------------------------------- /code-stages/chapter-05/src/types/index.ts: -------------------------------------------------------------------------------- 1 | export type Entity = { 2 | id: string; 3 | createdAt: number; 4 | }; 5 | -------------------------------------------------------------------------------- /code-stages/chapter-05/src/utils/format.ts: -------------------------------------------------------------------------------- 1 | export const formatDate = (date: number | string) => { 2 | return new Date(date).toLocaleDateString('en-US', { 3 | month: 'long', 4 | year: 'numeric', 5 | day: 'numeric', 6 | }); 7 | }; 8 | -------------------------------------------------------------------------------- /code-stages/chapter-05/src/utils/uid.ts: -------------------------------------------------------------------------------- 1 | // https://gist.github.com/gordonbrander/2230317?permalink_comment_id=3443509#gistcomment-3443509 2 | export const uid = () => { 3 | return ( 4 | performance.now().toString(36) + 5 | Math.random().toString(36) 6 | ).replace(/\./g, ''); 7 | }; 8 | -------------------------------------------------------------------------------- /code-stages/chapter-06-start/src/components/button/index.ts: -------------------------------------------------------------------------------- 1 | export * from './button'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-06-start/src/components/content/content.tsx: -------------------------------------------------------------------------------- 1 | import { Box } from '@chakra-ui/react'; 2 | 3 | export type ContentProps = { 4 | children: string; 5 | }; 6 | 7 | export const Content = ({ children }: ContentProps) => { 8 | return ( 9 | 10 | {children} 11 | 12 | ); 13 | }; 14 | -------------------------------------------------------------------------------- /code-stages/chapter-06-start/src/components/content/index.ts: -------------------------------------------------------------------------------- 1 | export * from './content'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-06-start/src/components/data-table/index.ts: -------------------------------------------------------------------------------- 1 | export * from './data-table'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-06-start/src/components/form/index.ts: -------------------------------------------------------------------------------- 1 | export * from './input-field'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-06-start/src/components/info-card/index.ts: -------------------------------------------------------------------------------- 1 | export * from './info-card'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-06-start/src/components/link/index.ts: -------------------------------------------------------------------------------- 1 | export * from './link'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-06-start/src/components/loading/index.ts: -------------------------------------------------------------------------------- 1 | export * from './loading'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-06-start/src/components/loading/loading.stories.tsx: -------------------------------------------------------------------------------- 1 | import { Meta, Story } from '@storybook/react'; 2 | 3 | import { Loading } from './loading'; 4 | 5 | const meta: Meta = { 6 | title: 'Components/Loading', 7 | component: Loading, 8 | }; 9 | 10 | export default meta; 11 | 12 | const Template: Story = (props) => ; 13 | 14 | export const Default = Template.bind({}); 15 | -------------------------------------------------------------------------------- /code-stages/chapter-06-start/src/components/loading/loading.tsx: -------------------------------------------------------------------------------- 1 | import { Center, Spinner } from '@chakra-ui/react'; 2 | 3 | export const Loading = () => { 4 | return ( 5 |
6 | 11 |
12 | ); 13 | }; 14 | -------------------------------------------------------------------------------- /code-stages/chapter-06-start/src/components/not-found/index.ts: -------------------------------------------------------------------------------- 1 | export * from './not-found'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-06-start/src/components/not-found/not-found.stories.tsx: -------------------------------------------------------------------------------- 1 | import { Meta, Story } from '@storybook/react'; 2 | 3 | import { NotFound } from './not-found'; 4 | 5 | const meta: Meta = { 6 | title: 'Components/NotFound', 7 | component: NotFound, 8 | }; 9 | 10 | export default meta; 11 | 12 | const Template: Story = (props) => ( 13 | 14 | ); 15 | 16 | export const Default = Template.bind({}); 17 | -------------------------------------------------------------------------------- /code-stages/chapter-06-start/src/components/not-found/not-found.tsx: -------------------------------------------------------------------------------- 1 | import { NotAllowedIcon } from '@chakra-ui/icons'; 2 | import { 3 | Center, 4 | Heading, 5 | VStack, 6 | } from '@chakra-ui/react'; 7 | 8 | export const NotFound = () => { 9 | return ( 10 |
11 | 12 | 13 | Not Found 14 | 15 |
16 | ); 17 | }; 18 | -------------------------------------------------------------------------------- /code-stages/chapter-06-start/src/components/seo/index.ts: -------------------------------------------------------------------------------- 1 | export * from './seo'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-06-start/src/components/seo/seo.tsx: -------------------------------------------------------------------------------- 1 | import Head from 'next/head'; 2 | 3 | export type SeoProps = { 4 | title: string; 5 | }; 6 | 7 | export const Seo = ({ title }: SeoProps) => { 8 | return ( 9 | 10 | {title} 11 | 12 | ); 13 | }; 14 | -------------------------------------------------------------------------------- /code-stages/chapter-06-start/src/config/theme.ts: -------------------------------------------------------------------------------- 1 | import { extendTheme } from '@chakra-ui/react'; 2 | 3 | const colors = { 4 | primary: '#1a365d', 5 | primaryAccent: 'white', 6 | }; 7 | 8 | const styles = { 9 | global: { 10 | 'html, body': { 11 | height: '100%', 12 | bg: 'gray.50', 13 | }, 14 | 15 | '#__next': { 16 | height: '100%', 17 | bg: 'gray.50', 18 | }, 19 | }, 20 | }; 21 | 22 | export const theme = extendTheme({ colors, styles }); 23 | -------------------------------------------------------------------------------- /code-stages/chapter-06-start/src/features/auth/api/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/React-Application-Architecture-for-Production/40cd19895fa025e7c48127f187035ec451874061/code-stages/chapter-06-start/src/features/auth/api/.gitkeep -------------------------------------------------------------------------------- /code-stages/chapter-06-start/src/features/auth/components/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/React-Application-Architecture-for-Production/40cd19895fa025e7c48127f187035ec451874061/code-stages/chapter-06-start/src/features/auth/components/.gitkeep -------------------------------------------------------------------------------- /code-stages/chapter-06-start/src/features/auth/index.ts: -------------------------------------------------------------------------------- 1 | // types: 2 | export * from './types'; 3 | -------------------------------------------------------------------------------- /code-stages/chapter-06-start/src/features/auth/types/index.ts: -------------------------------------------------------------------------------- 1 | import { Entity } from '@/types'; 2 | 3 | export type AuthUser = Entity & { 4 | email: string; 5 | organizationId: string; 6 | }; 7 | 8 | export type LoginData = { 9 | email: string; 10 | password: string; 11 | }; 12 | -------------------------------------------------------------------------------- /code-stages/chapter-06-start/src/features/jobs/api/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/React-Application-Architecture-for-Production/40cd19895fa025e7c48127f187035ec451874061/code-stages/chapter-06-start/src/features/jobs/api/.gitkeep -------------------------------------------------------------------------------- /code-stages/chapter-06-start/src/features/jobs/components/create-job-form/index.ts: -------------------------------------------------------------------------------- 1 | export * from './create-job-form'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-06-start/src/features/jobs/components/dashboard-job-info/index.ts: -------------------------------------------------------------------------------- 1 | export * from './dashboard-job-info'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-06-start/src/features/jobs/components/jobs-list/index.ts: -------------------------------------------------------------------------------- 1 | export * from './jobs-list'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-06-start/src/features/jobs/components/public-job-info/index.ts: -------------------------------------------------------------------------------- 1 | export * from './public-job-info'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-06-start/src/features/jobs/index.ts: -------------------------------------------------------------------------------- 1 | // components: 2 | export * from './components/create-job-form'; 3 | export * from './components/dashboard-job-info'; 4 | export * from './components/jobs-list'; 5 | export * from './components/public-job-info'; 6 | 7 | // types: 8 | export * from './types'; 9 | -------------------------------------------------------------------------------- /code-stages/chapter-06-start/src/features/jobs/types/index.ts: -------------------------------------------------------------------------------- 1 | import { Entity } from '@/types'; 2 | 3 | export type Job = Entity & { 4 | organizationId: string; 5 | position: string; 6 | info: string; 7 | location: string; 8 | department: string; 9 | }; 10 | 11 | export type CreateJobData = Pick< 12 | Job, 13 | 'position' | 'department' | 'location' | 'info' 14 | >; 15 | -------------------------------------------------------------------------------- /code-stages/chapter-06-start/src/features/organizations/api/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/React-Application-Architecture-for-Production/40cd19895fa025e7c48127f187035ec451874061/code-stages/chapter-06-start/src/features/organizations/api/.gitkeep -------------------------------------------------------------------------------- /code-stages/chapter-06-start/src/features/organizations/components/organization-info/index.ts: -------------------------------------------------------------------------------- 1 | export * from './organization-info'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-06-start/src/features/organizations/index.ts: -------------------------------------------------------------------------------- 1 | // components: 2 | export * from './components/organization-info'; 3 | 4 | // types: 5 | export * from './types'; 6 | -------------------------------------------------------------------------------- /code-stages/chapter-06-start/src/features/organizations/types/index.ts: -------------------------------------------------------------------------------- 1 | import { Entity } from '@/types'; 2 | 3 | export type Organization = Entity & { 4 | adminId: string; 5 | name: string; 6 | email: string; 7 | phone: string; 8 | info: string; 9 | }; 10 | -------------------------------------------------------------------------------- /code-stages/chapter-06-start/src/pages/404.tsx: -------------------------------------------------------------------------------- 1 | import { Center } from '@chakra-ui/react'; 2 | 3 | import { Link } from '@/components/link'; 4 | import { NotFound } from '@/components/not-found'; 5 | 6 | const NotFoundPage = () => { 7 | return ( 8 | <> 9 | 10 |
11 | Home 12 |
13 | 14 | ); 15 | }; 16 | 17 | export default NotFoundPage; 18 | -------------------------------------------------------------------------------- /code-stages/chapter-06-start/src/stores/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/React-Application-Architecture-for-Production/40cd19895fa025e7c48127f187035ec451874061/code-stages/chapter-06-start/src/stores/.gitkeep -------------------------------------------------------------------------------- /code-stages/chapter-06-start/src/testing/mocks/browser.ts: -------------------------------------------------------------------------------- 1 | import { setupWorker } from 'msw'; 2 | 3 | import { handlers } from './handlers'; 4 | 5 | export const worker = setupWorker(...handlers); 6 | -------------------------------------------------------------------------------- /code-stages/chapter-06-start/src/testing/mocks/index.ts: -------------------------------------------------------------------------------- 1 | export * from './handlers'; 2 | 3 | export * from './db'; 4 | -------------------------------------------------------------------------------- /code-stages/chapter-06-start/src/testing/mocks/initialize.ts: -------------------------------------------------------------------------------- 1 | import { IS_SERVER } from '@/config/constants'; 2 | 3 | import { seedDb } from './seed-db'; 4 | 5 | const initializeMocks = () => { 6 | if (IS_SERVER) { 7 | const { server } = require('./server'); 8 | server.listen(); 9 | } else { 10 | const { worker } = require('./browser'); 11 | worker.start(); 12 | } 13 | seedDb(); 14 | }; 15 | 16 | initializeMocks(); 17 | -------------------------------------------------------------------------------- /code-stages/chapter-06-start/src/testing/mocks/seed-db.ts: -------------------------------------------------------------------------------- 1 | import { testData } from '../test-data'; 2 | 3 | import { db } from './db'; 4 | 5 | export const seedDb = () => { 6 | const userCount = db.user.count(); 7 | 8 | if (userCount > 0) return; 9 | 10 | testData.users.forEach((user) => db.user.create(user)); 11 | 12 | testData.organizations.forEach((organization) => 13 | db.organization.create(organization) 14 | ); 15 | 16 | testData.jobs.forEach((job) => db.job.create(job)); 17 | }; 18 | -------------------------------------------------------------------------------- /code-stages/chapter-06-start/src/testing/mocks/server.ts: -------------------------------------------------------------------------------- 1 | import { setupServer } from 'msw/node'; 2 | 3 | import { handlers } from './handlers'; 4 | 5 | export const server = setupServer(...handlers); 6 | -------------------------------------------------------------------------------- /code-stages/chapter-06-start/src/types/index.ts: -------------------------------------------------------------------------------- 1 | export type Entity = { 2 | id: string; 3 | createdAt: number; 4 | }; 5 | -------------------------------------------------------------------------------- /code-stages/chapter-06-start/src/utils/format.ts: -------------------------------------------------------------------------------- 1 | export const formatDate = (date: number | string) => { 2 | return new Date(date).toLocaleDateString('en-US', { 3 | month: 'long', 4 | year: 'numeric', 5 | day: 'numeric', 6 | }); 7 | }; 8 | -------------------------------------------------------------------------------- /code-stages/chapter-06-start/src/utils/uid.ts: -------------------------------------------------------------------------------- 1 | // https://gist.github.com/gordonbrander/2230317?permalink_comment_id=3443509#gistcomment-3443509 2 | export const uid = () => { 3 | return ( 4 | performance.now().toString(36) + 5 | Math.random().toString(36) 6 | ).replace(/\./g, ''); 7 | }; 8 | -------------------------------------------------------------------------------- /code-stages/chapter-06/src/components/button/index.ts: -------------------------------------------------------------------------------- 1 | export * from './button'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-06/src/components/content/content.tsx: -------------------------------------------------------------------------------- 1 | import { Box } from '@chakra-ui/react'; 2 | 3 | export type ContentProps = { 4 | children: string; 5 | }; 6 | 7 | export const Content = ({ children }: ContentProps) => { 8 | return ( 9 | 10 | {children} 11 | 12 | ); 13 | }; 14 | -------------------------------------------------------------------------------- /code-stages/chapter-06/src/components/content/index.ts: -------------------------------------------------------------------------------- 1 | export * from './content'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-06/src/components/data-table/index.ts: -------------------------------------------------------------------------------- 1 | export * from './data-table'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-06/src/components/form/index.ts: -------------------------------------------------------------------------------- 1 | export * from './input-field'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-06/src/components/info-card/index.ts: -------------------------------------------------------------------------------- 1 | export * from './info-card'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-06/src/components/link/index.ts: -------------------------------------------------------------------------------- 1 | export * from './link'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-06/src/components/link/link.stories.tsx: -------------------------------------------------------------------------------- 1 | import { Meta, Story } from '@storybook/react'; 2 | 3 | import { Link, LinkProps } from './link'; 4 | 5 | const meta: Meta = { 6 | title: 'Components/Link', 7 | component: Link, 8 | }; 9 | 10 | export default meta; 11 | 12 | const Template: Story = (props) => ( 13 | 14 | ); 15 | 16 | export const Default = Template.bind({}); 17 | 18 | Default.args = { 19 | href: '/', 20 | children: 'Click Me', 21 | }; 22 | -------------------------------------------------------------------------------- /code-stages/chapter-06/src/components/loading/index.ts: -------------------------------------------------------------------------------- 1 | export * from './loading'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-06/src/components/loading/loading.stories.tsx: -------------------------------------------------------------------------------- 1 | import { Meta, Story } from '@storybook/react'; 2 | 3 | import { Loading } from './loading'; 4 | 5 | const meta: Meta = { 6 | title: 'Components/Loading', 7 | component: Loading, 8 | }; 9 | 10 | export default meta; 11 | 12 | const Template: Story = (props) => ; 13 | 14 | export const Default = Template.bind({}); 15 | -------------------------------------------------------------------------------- /code-stages/chapter-06/src/components/loading/loading.tsx: -------------------------------------------------------------------------------- 1 | import { Center, Spinner } from '@chakra-ui/react'; 2 | 3 | export const Loading = () => { 4 | return ( 5 |
6 | 11 |
12 | ); 13 | }; 14 | -------------------------------------------------------------------------------- /code-stages/chapter-06/src/components/not-found/index.ts: -------------------------------------------------------------------------------- 1 | export * from './not-found'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-06/src/components/not-found/not-found.stories.tsx: -------------------------------------------------------------------------------- 1 | import { Meta, Story } from '@storybook/react'; 2 | 3 | import { NotFound } from './not-found'; 4 | 5 | const meta: Meta = { 6 | title: 'Components/NotFound', 7 | component: NotFound, 8 | }; 9 | 10 | export default meta; 11 | 12 | const Template: Story = (props) => ( 13 | 14 | ); 15 | 16 | export const Default = Template.bind({}); 17 | -------------------------------------------------------------------------------- /code-stages/chapter-06/src/components/not-found/not-found.tsx: -------------------------------------------------------------------------------- 1 | import { NotAllowedIcon } from '@chakra-ui/icons'; 2 | import { 3 | Center, 4 | Heading, 5 | VStack, 6 | } from '@chakra-ui/react'; 7 | 8 | export const NotFound = () => { 9 | return ( 10 |
11 | 12 | 13 | Not Found 14 | 15 |
16 | ); 17 | }; 18 | -------------------------------------------------------------------------------- /code-stages/chapter-06/src/components/seo/index.ts: -------------------------------------------------------------------------------- 1 | export * from './seo'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-06/src/components/seo/seo.tsx: -------------------------------------------------------------------------------- 1 | import Head from 'next/head'; 2 | 3 | export type SeoProps = { 4 | title: string; 5 | }; 6 | 7 | export const Seo = ({ title }: SeoProps) => { 8 | return ( 9 | 10 | {title} 11 | 12 | ); 13 | }; 14 | -------------------------------------------------------------------------------- /code-stages/chapter-06/src/config/theme.ts: -------------------------------------------------------------------------------- 1 | import { extendTheme } from '@chakra-ui/react'; 2 | 3 | const colors = { 4 | primary: '#1a365d', 5 | primaryAccent: 'white', 6 | }; 7 | 8 | const styles = { 9 | global: { 10 | 'html, body': { 11 | height: '100%', 12 | bg: 'gray.50', 13 | }, 14 | 15 | '#__next': { 16 | height: '100%', 17 | bg: 'gray.50', 18 | }, 19 | }, 20 | }; 21 | 22 | export const theme = extendTheme({ colors, styles }); 23 | -------------------------------------------------------------------------------- /code-stages/chapter-06/src/features/auth/api/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/React-Application-Architecture-for-Production/40cd19895fa025e7c48127f187035ec451874061/code-stages/chapter-06/src/features/auth/api/.gitkeep -------------------------------------------------------------------------------- /code-stages/chapter-06/src/features/auth/components/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/React-Application-Architecture-for-Production/40cd19895fa025e7c48127f187035ec451874061/code-stages/chapter-06/src/features/auth/components/.gitkeep -------------------------------------------------------------------------------- /code-stages/chapter-06/src/features/auth/index.ts: -------------------------------------------------------------------------------- 1 | // types: 2 | export * from './types'; 3 | -------------------------------------------------------------------------------- /code-stages/chapter-06/src/features/auth/types/index.ts: -------------------------------------------------------------------------------- 1 | import { Entity } from '@/types'; 2 | 3 | export type AuthUser = Entity & { 4 | email: string; 5 | organizationId: string; 6 | }; 7 | 8 | export type LoginData = { 9 | email: string; 10 | password: string; 11 | }; 12 | -------------------------------------------------------------------------------- /code-stages/chapter-06/src/features/jobs/components/create-job-form/index.ts: -------------------------------------------------------------------------------- 1 | export * from './create-job-form'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-06/src/features/jobs/components/dashboard-job-info/index.ts: -------------------------------------------------------------------------------- 1 | export * from './dashboard-job-info'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-06/src/features/jobs/components/jobs-list/index.ts: -------------------------------------------------------------------------------- 1 | export * from './jobs-list'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-06/src/features/jobs/components/public-job-info/index.ts: -------------------------------------------------------------------------------- 1 | export * from './public-job-info'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-06/src/features/jobs/index.ts: -------------------------------------------------------------------------------- 1 | // api: 2 | export * from './api/get-job'; 3 | export * from './api/get-jobs'; 4 | 5 | // components: 6 | export * from './components/create-job-form'; 7 | export * from './components/dashboard-job-info'; 8 | export * from './components/jobs-list'; 9 | export * from './components/public-job-info'; 10 | 11 | // types: 12 | export * from './types'; 13 | -------------------------------------------------------------------------------- /code-stages/chapter-06/src/features/jobs/types/index.ts: -------------------------------------------------------------------------------- 1 | import { Entity } from '@/types'; 2 | 3 | export type Job = Entity & { 4 | organizationId: string; 5 | position: string; 6 | info: string; 7 | location: string; 8 | department: string; 9 | }; 10 | 11 | export type CreateJobData = Pick< 12 | Job, 13 | 'position' | 'department' | 'location' | 'info' 14 | >; 15 | -------------------------------------------------------------------------------- /code-stages/chapter-06/src/features/organizations/components/organization-info/index.ts: -------------------------------------------------------------------------------- 1 | export * from './organization-info'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-06/src/features/organizations/index.ts: -------------------------------------------------------------------------------- 1 | // api: 2 | export * from './api/get-organization'; 3 | 4 | // components: 5 | export * from './components/organization-info'; 6 | 7 | // types: 8 | export * from './types'; 9 | -------------------------------------------------------------------------------- /code-stages/chapter-06/src/features/organizations/types/index.ts: -------------------------------------------------------------------------------- 1 | import { Entity } from '@/types'; 2 | 3 | export type Organization = Entity & { 4 | adminId: string; 5 | name: string; 6 | email: string; 7 | phone: string; 8 | info: string; 9 | }; 10 | -------------------------------------------------------------------------------- /code-stages/chapter-06/src/lib/react-query.ts: -------------------------------------------------------------------------------- 1 | import { QueryClient } from '@tanstack/react-query'; 2 | 3 | export const queryClient = new QueryClient({ 4 | defaultOptions: { 5 | queries: { 6 | retry: false, 7 | refetchOnWindowFocus: false, 8 | useErrorBoundary: true, 9 | }, 10 | }, 11 | }); 12 | -------------------------------------------------------------------------------- /code-stages/chapter-06/src/pages/404.tsx: -------------------------------------------------------------------------------- 1 | import { Center } from '@chakra-ui/react'; 2 | 3 | import { Link } from '@/components/link'; 4 | import { NotFound } from '@/components/not-found'; 5 | 6 | const NotFoundPage = () => { 7 | return ( 8 | <> 9 | 10 |
11 | Home 12 |
13 | 14 | ); 15 | }; 16 | 17 | export default NotFoundPage; 18 | -------------------------------------------------------------------------------- /code-stages/chapter-06/src/stores/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/React-Application-Architecture-for-Production/40cd19895fa025e7c48127f187035ec451874061/code-stages/chapter-06/src/stores/.gitkeep -------------------------------------------------------------------------------- /code-stages/chapter-06/src/testing/mocks/browser.ts: -------------------------------------------------------------------------------- 1 | import { setupWorker } from 'msw'; 2 | 3 | import { handlers } from './handlers'; 4 | 5 | export const worker = setupWorker(...handlers); 6 | -------------------------------------------------------------------------------- /code-stages/chapter-06/src/testing/mocks/index.ts: -------------------------------------------------------------------------------- 1 | export * from './handlers'; 2 | 3 | export * from './db'; 4 | -------------------------------------------------------------------------------- /code-stages/chapter-06/src/testing/mocks/initialize.ts: -------------------------------------------------------------------------------- 1 | import { IS_SERVER } from '@/config/constants'; 2 | 3 | import { seedDb } from './seed-db'; 4 | 5 | const initializeMocks = () => { 6 | if (IS_SERVER) { 7 | const { server } = require('./server'); 8 | server.listen(); 9 | } else { 10 | const { worker } = require('./browser'); 11 | worker.start(); 12 | } 13 | seedDb(); 14 | }; 15 | 16 | initializeMocks(); 17 | -------------------------------------------------------------------------------- /code-stages/chapter-06/src/testing/mocks/seed-db.ts: -------------------------------------------------------------------------------- 1 | import { testData } from '../test-data'; 2 | 3 | import { db } from './db'; 4 | 5 | export const seedDb = () => { 6 | const userCount = db.user.count(); 7 | 8 | if (userCount > 0) return; 9 | 10 | testData.users.forEach((user) => db.user.create(user)); 11 | 12 | testData.organizations.forEach((organization) => 13 | db.organization.create(organization) 14 | ); 15 | 16 | testData.jobs.forEach((job) => db.job.create(job)); 17 | }; 18 | -------------------------------------------------------------------------------- /code-stages/chapter-06/src/testing/mocks/server.ts: -------------------------------------------------------------------------------- 1 | import { setupServer } from 'msw/node'; 2 | 3 | import { handlers } from './handlers'; 4 | 5 | export const server = setupServer(...handlers); 6 | -------------------------------------------------------------------------------- /code-stages/chapter-06/src/types/index.ts: -------------------------------------------------------------------------------- 1 | export type Entity = { 2 | id: string; 3 | createdAt: number; 4 | }; 5 | -------------------------------------------------------------------------------- /code-stages/chapter-06/src/utils/format.ts: -------------------------------------------------------------------------------- 1 | export const formatDate = (date: number | string) => { 2 | return new Date(date).toLocaleDateString('en-US', { 3 | month: 'long', 4 | year: 'numeric', 5 | day: 'numeric', 6 | }); 7 | }; 8 | -------------------------------------------------------------------------------- /code-stages/chapter-06/src/utils/uid.ts: -------------------------------------------------------------------------------- 1 | // https://gist.github.com/gordonbrander/2230317?permalink_comment_id=3443509#gistcomment-3443509 2 | export const uid = () => { 3 | return ( 4 | performance.now().toString(36) + 5 | Math.random().toString(36) 6 | ).replace(/\./g, ''); 7 | }; 8 | -------------------------------------------------------------------------------- /code-stages/chapter-07-start/src/components/button/index.ts: -------------------------------------------------------------------------------- 1 | export * from './button'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-07-start/src/components/content/content.tsx: -------------------------------------------------------------------------------- 1 | import { Box } from '@chakra-ui/react'; 2 | 3 | export type ContentProps = { 4 | children: string; 5 | }; 6 | 7 | export const Content = ({ children }: ContentProps) => { 8 | return ( 9 | 10 | {children} 11 | 12 | ); 13 | }; 14 | -------------------------------------------------------------------------------- /code-stages/chapter-07-start/src/components/content/index.ts: -------------------------------------------------------------------------------- 1 | export * from './content'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-07-start/src/components/data-table/index.ts: -------------------------------------------------------------------------------- 1 | export * from './data-table'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-07-start/src/components/form/index.ts: -------------------------------------------------------------------------------- 1 | export * from './input-field'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-07-start/src/components/info-card/index.ts: -------------------------------------------------------------------------------- 1 | export * from './info-card'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-07-start/src/components/link/index.ts: -------------------------------------------------------------------------------- 1 | export * from './link'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-07-start/src/components/loading/index.ts: -------------------------------------------------------------------------------- 1 | export * from './loading'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-07-start/src/components/loading/loading.stories.tsx: -------------------------------------------------------------------------------- 1 | import { Meta, Story } from '@storybook/react'; 2 | 3 | import { Loading } from './loading'; 4 | 5 | const meta: Meta = { 6 | title: 'Components/Loading', 7 | component: Loading, 8 | }; 9 | 10 | export default meta; 11 | 12 | const Template: Story = (props) => ; 13 | 14 | export const Default = Template.bind({}); 15 | -------------------------------------------------------------------------------- /code-stages/chapter-07-start/src/components/loading/loading.tsx: -------------------------------------------------------------------------------- 1 | import { Center, Spinner } from '@chakra-ui/react'; 2 | 3 | export const Loading = () => { 4 | return ( 5 |
6 | 11 |
12 | ); 13 | }; 14 | -------------------------------------------------------------------------------- /code-stages/chapter-07-start/src/components/not-found/index.ts: -------------------------------------------------------------------------------- 1 | export * from './not-found'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-07-start/src/components/not-found/not-found.stories.tsx: -------------------------------------------------------------------------------- 1 | import { Meta, Story } from '@storybook/react'; 2 | 3 | import { NotFound } from './not-found'; 4 | 5 | const meta: Meta = { 6 | title: 'Components/NotFound', 7 | component: NotFound, 8 | }; 9 | 10 | export default meta; 11 | 12 | const Template: Story = (props) => ( 13 | 14 | ); 15 | 16 | export const Default = Template.bind({}); 17 | -------------------------------------------------------------------------------- /code-stages/chapter-07-start/src/components/not-found/not-found.tsx: -------------------------------------------------------------------------------- 1 | import { NotAllowedIcon } from '@chakra-ui/icons'; 2 | import { 3 | Center, 4 | Heading, 5 | VStack, 6 | } from '@chakra-ui/react'; 7 | 8 | export const NotFound = () => { 9 | return ( 10 |
11 | 12 | 13 | Not Found 14 | 15 |
16 | ); 17 | }; 18 | -------------------------------------------------------------------------------- /code-stages/chapter-07-start/src/components/notifications/index.ts: -------------------------------------------------------------------------------- 1 | export * from './notifications'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-07-start/src/components/notifications/notifications.tsx: -------------------------------------------------------------------------------- 1 | export const Notifications = () => { 2 | return <>Notifications; 3 | }; 4 | -------------------------------------------------------------------------------- /code-stages/chapter-07-start/src/components/seo/index.ts: -------------------------------------------------------------------------------- 1 | export * from './seo'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-07-start/src/components/seo/seo.tsx: -------------------------------------------------------------------------------- 1 | import Head from 'next/head'; 2 | 3 | export type SeoProps = { 4 | title: string; 5 | }; 6 | 7 | export const Seo = ({ title }: SeoProps) => { 8 | return ( 9 | 10 | {title} 11 | 12 | ); 13 | }; 14 | -------------------------------------------------------------------------------- /code-stages/chapter-07-start/src/config/theme.ts: -------------------------------------------------------------------------------- 1 | import { extendTheme } from '@chakra-ui/react'; 2 | 3 | const colors = { 4 | primary: '#1a365d', 5 | primaryAccent: 'white', 6 | }; 7 | 8 | const styles = { 9 | global: { 10 | 'html, body': { 11 | height: '100%', 12 | bg: 'gray.50', 13 | }, 14 | 15 | '#__next': { 16 | height: '100%', 17 | bg: 'gray.50', 18 | }, 19 | }, 20 | }; 21 | 22 | export const theme = extendTheme({ colors, styles }); 23 | -------------------------------------------------------------------------------- /code-stages/chapter-07-start/src/features/auth/api/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/React-Application-Architecture-for-Production/40cd19895fa025e7c48127f187035ec451874061/code-stages/chapter-07-start/src/features/auth/api/.gitkeep -------------------------------------------------------------------------------- /code-stages/chapter-07-start/src/features/auth/components/login-form/index.ts: -------------------------------------------------------------------------------- 1 | export * from './login-form'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-07-start/src/features/auth/components/protected/index.ts: -------------------------------------------------------------------------------- 1 | export * from './protected'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-07-start/src/features/auth/components/protected/protected.tsx: -------------------------------------------------------------------------------- 1 | import { ReactNode } from 'react'; 2 | 3 | export type ProtectedProps = { 4 | children: ReactNode; 5 | }; 6 | 7 | export const Protected = ({ 8 | children, 9 | }: ProtectedProps) => { 10 | return <>{children}; 11 | }; 12 | -------------------------------------------------------------------------------- /code-stages/chapter-07-start/src/features/auth/index.ts: -------------------------------------------------------------------------------- 1 | // components: 2 | export * from './components/login-form'; 3 | export * from './components/protected'; 4 | 5 | // types: 6 | export * from './types'; 7 | -------------------------------------------------------------------------------- /code-stages/chapter-07-start/src/features/auth/types/index.ts: -------------------------------------------------------------------------------- 1 | import { Entity } from '@/types'; 2 | 3 | export type AuthUser = Entity & { 4 | email: string; 5 | organizationId: string; 6 | }; 7 | 8 | export type LoginData = { 9 | email: string; 10 | password: string; 11 | }; 12 | -------------------------------------------------------------------------------- /code-stages/chapter-07-start/src/features/jobs/components/create-job-form/index.ts: -------------------------------------------------------------------------------- 1 | export * from './create-job-form'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-07-start/src/features/jobs/components/dashboard-job-info/index.ts: -------------------------------------------------------------------------------- 1 | export * from './dashboard-job-info'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-07-start/src/features/jobs/components/jobs-list/index.ts: -------------------------------------------------------------------------------- 1 | export * from './jobs-list'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-07-start/src/features/jobs/components/public-job-info/index.ts: -------------------------------------------------------------------------------- 1 | export * from './public-job-info'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-07-start/src/features/jobs/index.ts: -------------------------------------------------------------------------------- 1 | // api: 2 | export * from './api/get-job'; 3 | export * from './api/get-jobs'; 4 | 5 | // components: 6 | export * from './components/create-job-form'; 7 | export * from './components/dashboard-job-info'; 8 | export * from './components/jobs-list'; 9 | export * from './components/public-job-info'; 10 | 11 | // types: 12 | export * from './types'; 13 | -------------------------------------------------------------------------------- /code-stages/chapter-07-start/src/features/jobs/types/index.ts: -------------------------------------------------------------------------------- 1 | import { Entity } from '@/types'; 2 | 3 | export type Job = Entity & { 4 | organizationId: string; 5 | position: string; 6 | info: string; 7 | location: string; 8 | department: string; 9 | }; 10 | 11 | export type CreateJobData = Pick< 12 | Job, 13 | 'position' | 'department' | 'location' | 'info' 14 | >; 15 | -------------------------------------------------------------------------------- /code-stages/chapter-07-start/src/features/organizations/components/organization-info/index.ts: -------------------------------------------------------------------------------- 1 | export * from './organization-info'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-07-start/src/features/organizations/index.ts: -------------------------------------------------------------------------------- 1 | // api: 2 | export * from './api/get-organization'; 3 | 4 | // components: 5 | export * from './components/organization-info'; 6 | 7 | // types: 8 | export * from './types'; 9 | -------------------------------------------------------------------------------- /code-stages/chapter-07-start/src/features/organizations/types/index.ts: -------------------------------------------------------------------------------- 1 | import { Entity } from '@/types'; 2 | 3 | export type Organization = Entity & { 4 | adminId: string; 5 | name: string; 6 | email: string; 7 | phone: string; 8 | info: string; 9 | }; 10 | -------------------------------------------------------------------------------- /code-stages/chapter-07-start/src/lib/react-query.ts: -------------------------------------------------------------------------------- 1 | import { QueryClient } from '@tanstack/react-query'; 2 | 3 | export const queryClient = new QueryClient({ 4 | defaultOptions: { 5 | queries: { 6 | retry: false, 7 | refetchOnWindowFocus: false, 8 | useErrorBoundary: true, 9 | }, 10 | }, 11 | }); 12 | -------------------------------------------------------------------------------- /code-stages/chapter-07-start/src/pages/404.tsx: -------------------------------------------------------------------------------- 1 | import { Center } from '@chakra-ui/react'; 2 | 3 | import { Link } from '@/components/link'; 4 | import { NotFound } from '@/components/not-found'; 5 | 6 | const NotFoundPage = () => { 7 | return ( 8 | <> 9 | 10 |
11 | Home 12 |
13 | 14 | ); 15 | }; 16 | 17 | export default NotFoundPage; 18 | -------------------------------------------------------------------------------- /code-stages/chapter-07-start/src/stores/notifications/index.ts: -------------------------------------------------------------------------------- 1 | export * from './notifications'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-07-start/src/stores/notifications/notifications.ts: -------------------------------------------------------------------------------- 1 | export {}; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-07-start/src/testing/mocks/browser.ts: -------------------------------------------------------------------------------- 1 | import { setupWorker } from 'msw'; 2 | 3 | import { handlers } from './handlers'; 4 | 5 | export const worker = setupWorker(...handlers); 6 | -------------------------------------------------------------------------------- /code-stages/chapter-07-start/src/testing/mocks/index.ts: -------------------------------------------------------------------------------- 1 | export * from './handlers'; 2 | 3 | export * from './db'; 4 | -------------------------------------------------------------------------------- /code-stages/chapter-07-start/src/testing/mocks/initialize.ts: -------------------------------------------------------------------------------- 1 | import { IS_SERVER } from '@/config/constants'; 2 | 3 | import { seedDb } from './seed-db'; 4 | 5 | const initializeMocks = () => { 6 | if (IS_SERVER) { 7 | const { server } = require('./server'); 8 | server.listen(); 9 | } else { 10 | const { worker } = require('./browser'); 11 | worker.start(); 12 | } 13 | seedDb(); 14 | }; 15 | 16 | initializeMocks(); 17 | -------------------------------------------------------------------------------- /code-stages/chapter-07-start/src/testing/mocks/seed-db.ts: -------------------------------------------------------------------------------- 1 | import { testData } from '../test-data'; 2 | 3 | import { db } from './db'; 4 | 5 | export const seedDb = () => { 6 | const userCount = db.user.count(); 7 | 8 | if (userCount > 0) return; 9 | 10 | testData.users.forEach((user) => db.user.create(user)); 11 | 12 | testData.organizations.forEach((organization) => 13 | db.organization.create(organization) 14 | ); 15 | 16 | testData.jobs.forEach((job) => db.job.create(job)); 17 | }; 18 | -------------------------------------------------------------------------------- /code-stages/chapter-07-start/src/testing/mocks/server.ts: -------------------------------------------------------------------------------- 1 | import { setupServer } from 'msw/node'; 2 | 3 | import { handlers } from './handlers'; 4 | 5 | export const server = setupServer(...handlers); 6 | -------------------------------------------------------------------------------- /code-stages/chapter-07-start/src/types/index.ts: -------------------------------------------------------------------------------- 1 | export type Entity = { 2 | id: string; 3 | createdAt: number; 4 | }; 5 | -------------------------------------------------------------------------------- /code-stages/chapter-07-start/src/utils/format.ts: -------------------------------------------------------------------------------- 1 | export const formatDate = (date: number | string) => { 2 | return new Date(date).toLocaleDateString('en-US', { 3 | month: 'long', 4 | year: 'numeric', 5 | day: 'numeric', 6 | }); 7 | }; 8 | -------------------------------------------------------------------------------- /code-stages/chapter-07-start/src/utils/uid.ts: -------------------------------------------------------------------------------- 1 | // https://gist.github.com/gordonbrander/2230317?permalink_comment_id=3443509#gistcomment-3443509 2 | export const uid = () => { 3 | return ( 4 | performance.now().toString(36) + 5 | Math.random().toString(36) 6 | ).replace(/\./g, ''); 7 | }; 8 | -------------------------------------------------------------------------------- /code-stages/chapter-07/src/components/button/index.ts: -------------------------------------------------------------------------------- 1 | export * from './button'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-07/src/components/content/content.tsx: -------------------------------------------------------------------------------- 1 | import { Box } from '@chakra-ui/react'; 2 | 3 | export type ContentProps = { 4 | children: string; 5 | }; 6 | 7 | export const Content = ({ children }: ContentProps) => { 8 | return ( 9 | 10 | {children} 11 | 12 | ); 13 | }; 14 | -------------------------------------------------------------------------------- /code-stages/chapter-07/src/components/content/index.ts: -------------------------------------------------------------------------------- 1 | export * from './content'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-07/src/components/data-table/index.ts: -------------------------------------------------------------------------------- 1 | export * from './data-table'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-07/src/components/form/index.ts: -------------------------------------------------------------------------------- 1 | export * from './input-field'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-07/src/components/info-card/index.ts: -------------------------------------------------------------------------------- 1 | export * from './info-card'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-07/src/components/link/index.ts: -------------------------------------------------------------------------------- 1 | export * from './link'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-07/src/components/link/link.stories.tsx: -------------------------------------------------------------------------------- 1 | import { Meta, Story } from '@storybook/react'; 2 | 3 | import { Link, LinkProps } from './link'; 4 | 5 | const meta: Meta = { 6 | title: 'Components/Link', 7 | component: Link, 8 | }; 9 | 10 | export default meta; 11 | 12 | const Template: Story = (props) => ( 13 | 14 | ); 15 | 16 | export const Default = Template.bind({}); 17 | 18 | Default.args = { 19 | href: '/', 20 | children: 'Click Me', 21 | }; 22 | -------------------------------------------------------------------------------- /code-stages/chapter-07/src/components/loading/index.ts: -------------------------------------------------------------------------------- 1 | export * from './loading'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-07/src/components/loading/loading.stories.tsx: -------------------------------------------------------------------------------- 1 | import { Meta, Story } from '@storybook/react'; 2 | 3 | import { Loading } from './loading'; 4 | 5 | const meta: Meta = { 6 | title: 'Components/Loading', 7 | component: Loading, 8 | }; 9 | 10 | export default meta; 11 | 12 | const Template: Story = (props) => ; 13 | 14 | export const Default = Template.bind({}); 15 | -------------------------------------------------------------------------------- /code-stages/chapter-07/src/components/loading/loading.tsx: -------------------------------------------------------------------------------- 1 | import { Center, Spinner } from '@chakra-ui/react'; 2 | 3 | export const Loading = () => { 4 | return ( 5 |
6 | 11 |
12 | ); 13 | }; 14 | -------------------------------------------------------------------------------- /code-stages/chapter-07/src/components/not-found/index.ts: -------------------------------------------------------------------------------- 1 | export * from './not-found'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-07/src/components/not-found/not-found.stories.tsx: -------------------------------------------------------------------------------- 1 | import { Meta, Story } from '@storybook/react'; 2 | 3 | import { NotFound } from './not-found'; 4 | 5 | const meta: Meta = { 6 | title: 'Components/NotFound', 7 | component: NotFound, 8 | }; 9 | 10 | export default meta; 11 | 12 | const Template: Story = (props) => ( 13 | 14 | ); 15 | 16 | export const Default = Template.bind({}); 17 | -------------------------------------------------------------------------------- /code-stages/chapter-07/src/components/not-found/not-found.tsx: -------------------------------------------------------------------------------- 1 | import { NotAllowedIcon } from '@chakra-ui/icons'; 2 | import { 3 | Center, 4 | Heading, 5 | VStack, 6 | } from '@chakra-ui/react'; 7 | 8 | export const NotFound = () => { 9 | return ( 10 |
11 | 12 | 13 | Not Found 14 | 15 |
16 | ); 17 | }; 18 | -------------------------------------------------------------------------------- /code-stages/chapter-07/src/components/notifications/index.ts: -------------------------------------------------------------------------------- 1 | export * from './notifications'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-07/src/components/seo/index.ts: -------------------------------------------------------------------------------- 1 | export * from './seo'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-07/src/components/seo/seo.tsx: -------------------------------------------------------------------------------- 1 | import Head from 'next/head'; 2 | 3 | export type SeoProps = { 4 | title: string; 5 | }; 6 | 7 | export const Seo = ({ title }: SeoProps) => { 8 | return ( 9 | 10 | {title} 11 | 12 | ); 13 | }; 14 | -------------------------------------------------------------------------------- /code-stages/chapter-07/src/config/theme.ts: -------------------------------------------------------------------------------- 1 | import { extendTheme } from '@chakra-ui/react'; 2 | 3 | const colors = { 4 | primary: '#1a365d', 5 | primaryAccent: 'white', 6 | }; 7 | 8 | const styles = { 9 | global: { 10 | 'html, body': { 11 | height: '100%', 12 | bg: 'gray.50', 13 | }, 14 | 15 | '#__next': { 16 | height: '100%', 17 | bg: 'gray.50', 18 | }, 19 | }, 20 | }; 21 | 22 | export const theme = extendTheme({ colors, styles }); 23 | -------------------------------------------------------------------------------- /code-stages/chapter-07/src/features/auth/components/login-form/index.ts: -------------------------------------------------------------------------------- 1 | export * from './login-form'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-07/src/features/auth/components/protected/index.ts: -------------------------------------------------------------------------------- 1 | export * from './protected'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-07/src/features/auth/index.ts: -------------------------------------------------------------------------------- 1 | // api: 2 | export * from './api/get-auth-user'; 3 | export * from './api/logout'; 4 | 5 | // components: 6 | export * from './components/login-form'; 7 | export * from './components/protected'; 8 | 9 | // types: 10 | export * from './types'; 11 | -------------------------------------------------------------------------------- /code-stages/chapter-07/src/features/auth/types/index.ts: -------------------------------------------------------------------------------- 1 | import { Entity } from '@/types'; 2 | 3 | export type AuthUser = Entity & { 4 | email: string; 5 | organizationId: string; 6 | }; 7 | 8 | export type LoginData = { 9 | email: string; 10 | password: string; 11 | }; 12 | -------------------------------------------------------------------------------- /code-stages/chapter-07/src/features/jobs/components/create-job-form/index.ts: -------------------------------------------------------------------------------- 1 | export * from './create-job-form'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-07/src/features/jobs/components/dashboard-job-info/index.ts: -------------------------------------------------------------------------------- 1 | export * from './dashboard-job-info'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-07/src/features/jobs/components/jobs-list/index.ts: -------------------------------------------------------------------------------- 1 | export * from './jobs-list'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-07/src/features/jobs/components/public-job-info/index.ts: -------------------------------------------------------------------------------- 1 | export * from './public-job-info'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-07/src/features/jobs/index.ts: -------------------------------------------------------------------------------- 1 | // api: 2 | export * from './api/get-job'; 3 | export * from './api/get-jobs'; 4 | 5 | // components: 6 | export * from './components/create-job-form'; 7 | export * from './components/dashboard-job-info'; 8 | export * from './components/jobs-list'; 9 | export * from './components/public-job-info'; 10 | 11 | // types: 12 | export * from './types'; 13 | -------------------------------------------------------------------------------- /code-stages/chapter-07/src/features/jobs/types/index.ts: -------------------------------------------------------------------------------- 1 | import { Entity } from '@/types'; 2 | 3 | export type Job = Entity & { 4 | organizationId: string; 5 | position: string; 6 | info: string; 7 | location: string; 8 | department: string; 9 | }; 10 | 11 | export type CreateJobData = Pick< 12 | Job, 13 | 'position' | 'department' | 'location' | 'info' 14 | >; 15 | -------------------------------------------------------------------------------- /code-stages/chapter-07/src/features/organizations/components/organization-info/index.ts: -------------------------------------------------------------------------------- 1 | export * from './organization-info'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-07/src/features/organizations/index.ts: -------------------------------------------------------------------------------- 1 | // api: 2 | export * from './api/get-organization'; 3 | 4 | // components: 5 | export * from './components/organization-info'; 6 | 7 | // types: 8 | export * from './types'; 9 | -------------------------------------------------------------------------------- /code-stages/chapter-07/src/features/organizations/types/index.ts: -------------------------------------------------------------------------------- 1 | import { Entity } from '@/types'; 2 | 3 | export type Organization = Entity & { 4 | adminId: string; 5 | name: string; 6 | email: string; 7 | phone: string; 8 | info: string; 9 | }; 10 | -------------------------------------------------------------------------------- /code-stages/chapter-07/src/lib/react-query.ts: -------------------------------------------------------------------------------- 1 | import { QueryClient } from '@tanstack/react-query'; 2 | 3 | export const queryClient = new QueryClient({ 4 | defaultOptions: { 5 | queries: { 6 | retry: false, 7 | refetchOnWindowFocus: false, 8 | useErrorBoundary: true, 9 | }, 10 | }, 11 | }); 12 | -------------------------------------------------------------------------------- /code-stages/chapter-07/src/pages/404.tsx: -------------------------------------------------------------------------------- 1 | import { Center } from '@chakra-ui/react'; 2 | 3 | import { Link } from '@/components/link'; 4 | import { NotFound } from '@/components/not-found'; 5 | 6 | const NotFoundPage = () => { 7 | return ( 8 | <> 9 | 10 |
11 | Home 12 |
13 | 14 | ); 15 | }; 16 | 17 | export default NotFoundPage; 18 | -------------------------------------------------------------------------------- /code-stages/chapter-07/src/stores/notifications/index.ts: -------------------------------------------------------------------------------- 1 | export * from './notifications'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-07/src/testing/mocks/browser.ts: -------------------------------------------------------------------------------- 1 | import { setupWorker } from 'msw'; 2 | 3 | import { handlers } from './handlers'; 4 | 5 | export const worker = setupWorker(...handlers); 6 | -------------------------------------------------------------------------------- /code-stages/chapter-07/src/testing/mocks/index.ts: -------------------------------------------------------------------------------- 1 | export * from './handlers'; 2 | 3 | export * from './db'; 4 | -------------------------------------------------------------------------------- /code-stages/chapter-07/src/testing/mocks/initialize.ts: -------------------------------------------------------------------------------- 1 | import { IS_SERVER } from '@/config/constants'; 2 | 3 | import { seedDb } from './seed-db'; 4 | 5 | const initializeMocks = () => { 6 | if (IS_SERVER) { 7 | const { server } = require('./server'); 8 | server.listen(); 9 | } else { 10 | const { worker } = require('./browser'); 11 | worker.start(); 12 | } 13 | seedDb(); 14 | }; 15 | 16 | initializeMocks(); 17 | -------------------------------------------------------------------------------- /code-stages/chapter-07/src/testing/mocks/seed-db.ts: -------------------------------------------------------------------------------- 1 | import { testData } from '../test-data'; 2 | 3 | import { db } from './db'; 4 | 5 | export const seedDb = () => { 6 | const userCount = db.user.count(); 7 | 8 | if (userCount > 0) return; 9 | 10 | testData.users.forEach((user) => db.user.create(user)); 11 | 12 | testData.organizations.forEach((organization) => 13 | db.organization.create(organization) 14 | ); 15 | 16 | testData.jobs.forEach((job) => db.job.create(job)); 17 | }; 18 | -------------------------------------------------------------------------------- /code-stages/chapter-07/src/testing/mocks/server.ts: -------------------------------------------------------------------------------- 1 | import { setupServer } from 'msw/node'; 2 | 3 | import { handlers } from './handlers'; 4 | 5 | export const server = setupServer(...handlers); 6 | -------------------------------------------------------------------------------- /code-stages/chapter-07/src/types/index.ts: -------------------------------------------------------------------------------- 1 | export type Entity = { 2 | id: string; 3 | createdAt: number; 4 | }; 5 | -------------------------------------------------------------------------------- /code-stages/chapter-07/src/utils/format.ts: -------------------------------------------------------------------------------- 1 | export const formatDate = (date: number | string) => { 2 | return new Date(date).toLocaleDateString('en-US', { 3 | month: 'long', 4 | year: 'numeric', 5 | day: 'numeric', 6 | }); 7 | }; 8 | -------------------------------------------------------------------------------- /code-stages/chapter-07/src/utils/uid.ts: -------------------------------------------------------------------------------- 1 | // https://gist.github.com/gordonbrander/2230317?permalink_comment_id=3443509#gistcomment-3443509 2 | export const uid = () => { 3 | return ( 4 | performance.now().toString(36) + 5 | Math.random().toString(36) 6 | ).replace(/\./g, ''); 7 | }; 8 | -------------------------------------------------------------------------------- /code-stages/chapter-08-start/cypress.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'cypress'; 2 | 3 | export default defineConfig({ 4 | video: false, 5 | videoUploadOnPasses: false, 6 | e2e: { 7 | // We've imported your old cypress plugins here. 8 | // You may want to clean this up later by importing these. 9 | setupNodeEvents(on, config) { 10 | return require('./cypress/plugins/index.ts')( 11 | on, 12 | config 13 | ); 14 | }, 15 | }, 16 | }); 17 | -------------------------------------------------------------------------------- /code-stages/chapter-08-start/cypress/e2e/dashboard.cy.ts: -------------------------------------------------------------------------------- 1 | describe('dashboard', () => { 2 | it('should authenticate into the dashboard', () => {}); 3 | 4 | it('should navigate to and visit the job details page', () => {}); 5 | 6 | it('should create a new job', () => {}); 7 | 8 | it('should log out from the dashboard', () => {}); 9 | }); 10 | -------------------------------------------------------------------------------- /code-stages/chapter-08-start/cypress/e2e/public.cy.ts: -------------------------------------------------------------------------------- 1 | describe('public application flow', () => { 2 | it('should display the organization public page', () => {}); 3 | 4 | it('should navigate to and display the public job details page', () => {}); 5 | }); 6 | -------------------------------------------------------------------------------- /code-stages/chapter-08-start/cypress/fixtures/example.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Using fixtures to represent data", 3 | "email": "hello@cypress.io", 4 | "body": "Fixtures are a great way to mock data for responses to routes" 5 | } 6 | -------------------------------------------------------------------------------- /code-stages/chapter-08-start/cypress/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "esModuleInterop": true, 4 | "target": "es5", 5 | "lib": ["es5", "dom"], 6 | "types": [ 7 | "node", 8 | "cypress", 9 | "@testing-library/cypress" 10 | ] 11 | }, 12 | "include": ["**/*.ts"] 13 | } 14 | -------------------------------------------------------------------------------- /code-stages/chapter-08-start/src/__tests__/dashboard-create-job-page.test.tsx: -------------------------------------------------------------------------------- 1 | describe('Dashboard Create Job Page', () => { 2 | it.todo('should create a new job'); 3 | }); 4 | -------------------------------------------------------------------------------- /code-stages/chapter-08-start/src/__tests__/dashboard-job-page.test.tsx: -------------------------------------------------------------------------------- 1 | describe('Dashboard Job Page', () => { 2 | it.todo('should render all the job details'); 3 | }); 4 | -------------------------------------------------------------------------------- /code-stages/chapter-08-start/src/__tests__/dashboard-jobs-page.test.tsx: -------------------------------------------------------------------------------- 1 | describe('Dashboard Jobs Page', () => { 2 | it.todo('should render the jobs list'); 3 | }); 4 | -------------------------------------------------------------------------------- /code-stages/chapter-08-start/src/__tests__/login-page.test.tsx: -------------------------------------------------------------------------------- 1 | describe('Login Page', () => { 2 | it.todo('should login the user into the dashboard'); 3 | }); 4 | -------------------------------------------------------------------------------- /code-stages/chapter-08-start/src/__tests__/public-job-page.test.tsx: -------------------------------------------------------------------------------- 1 | describe('Public Job Page', () => { 2 | it.todo( 3 | 'should use getServerSideProps that fetches and returns the proper data' 4 | ); 5 | 6 | it.todo('should render the job details'); 7 | 8 | it.todo( 9 | 'should render the not found message if the data does not exist' 10 | ); 11 | }); 12 | -------------------------------------------------------------------------------- /code-stages/chapter-08-start/src/__tests__/public-organization-page.test.tsx: -------------------------------------------------------------------------------- 1 | describe('Public Organization Page', () => { 2 | it.todo( 3 | 'should use getServerSideProps that fetches and returns the proper data' 4 | ); 5 | 6 | it.todo('should render the organization details'); 7 | 8 | it.todo( 9 | 'should render the not found message if the organization is not found' 10 | ); 11 | }); 12 | -------------------------------------------------------------------------------- /code-stages/chapter-08-start/src/components/button/index.ts: -------------------------------------------------------------------------------- 1 | export * from './button'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-08-start/src/components/content/content.tsx: -------------------------------------------------------------------------------- 1 | import { Box } from '@chakra-ui/react'; 2 | 3 | export type ContentProps = { 4 | children: string; 5 | }; 6 | 7 | export const Content = ({ children }: ContentProps) => { 8 | return ( 9 | 10 | {children} 11 | 12 | ); 13 | }; 14 | -------------------------------------------------------------------------------- /code-stages/chapter-08-start/src/components/content/index.ts: -------------------------------------------------------------------------------- 1 | export * from './content'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-08-start/src/components/data-table/index.ts: -------------------------------------------------------------------------------- 1 | export * from './data-table'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-08-start/src/components/form/index.ts: -------------------------------------------------------------------------------- 1 | export * from './input-field'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-08-start/src/components/info-card/index.ts: -------------------------------------------------------------------------------- 1 | export * from './info-card'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-08-start/src/components/link/index.ts: -------------------------------------------------------------------------------- 1 | export * from './link'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-08-start/src/components/loading/index.ts: -------------------------------------------------------------------------------- 1 | export * from './loading'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-08-start/src/components/loading/loading.stories.tsx: -------------------------------------------------------------------------------- 1 | import { Meta, Story } from '@storybook/react'; 2 | 3 | import { Loading } from './loading'; 4 | 5 | const meta: Meta = { 6 | title: 'Components/Loading', 7 | component: Loading, 8 | }; 9 | 10 | export default meta; 11 | 12 | const Template: Story = (props) => ; 13 | 14 | export const Default = Template.bind({}); 15 | -------------------------------------------------------------------------------- /code-stages/chapter-08-start/src/components/loading/loading.tsx: -------------------------------------------------------------------------------- 1 | import { Center, Spinner } from '@chakra-ui/react'; 2 | 3 | export const Loading = () => { 4 | return ( 5 |
6 | 11 |
12 | ); 13 | }; 14 | -------------------------------------------------------------------------------- /code-stages/chapter-08-start/src/components/not-found/index.ts: -------------------------------------------------------------------------------- 1 | export * from './not-found'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-08-start/src/components/not-found/not-found.stories.tsx: -------------------------------------------------------------------------------- 1 | import { Meta, Story } from '@storybook/react'; 2 | 3 | import { NotFound } from './not-found'; 4 | 5 | const meta: Meta = { 6 | title: 'Components/NotFound', 7 | component: NotFound, 8 | }; 9 | 10 | export default meta; 11 | 12 | const Template: Story = (props) => ( 13 | 14 | ); 15 | 16 | export const Default = Template.bind({}); 17 | -------------------------------------------------------------------------------- /code-stages/chapter-08-start/src/components/not-found/not-found.tsx: -------------------------------------------------------------------------------- 1 | import { NotAllowedIcon } from '@chakra-ui/icons'; 2 | import { 3 | Center, 4 | Heading, 5 | VStack, 6 | } from '@chakra-ui/react'; 7 | 8 | export const NotFound = () => { 9 | return ( 10 |
11 | 12 | 13 | Not Found 14 | 15 |
16 | ); 17 | }; 18 | -------------------------------------------------------------------------------- /code-stages/chapter-08-start/src/components/notifications/index.ts: -------------------------------------------------------------------------------- 1 | export * from './notifications'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-08-start/src/components/seo/index.ts: -------------------------------------------------------------------------------- 1 | export * from './seo'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-08-start/src/components/seo/seo.tsx: -------------------------------------------------------------------------------- 1 | import Head from 'next/head'; 2 | 3 | export type SeoProps = { 4 | title: string; 5 | }; 6 | 7 | export const Seo = ({ title }: SeoProps) => { 8 | return ( 9 | 10 | {title} 11 | 12 | ); 13 | }; 14 | -------------------------------------------------------------------------------- /code-stages/chapter-08-start/src/config/theme.ts: -------------------------------------------------------------------------------- 1 | import { extendTheme } from '@chakra-ui/react'; 2 | 3 | const colors = { 4 | primary: '#1a365d', 5 | primaryAccent: 'white', 6 | }; 7 | 8 | const styles = { 9 | global: { 10 | 'html, body': { 11 | height: '100%', 12 | bg: 'gray.50', 13 | }, 14 | 15 | '#__next': { 16 | height: '100%', 17 | bg: 'gray.50', 18 | }, 19 | }, 20 | }; 21 | 22 | export const theme = extendTheme({ colors, styles }); 23 | -------------------------------------------------------------------------------- /code-stages/chapter-08-start/src/features/auth/components/login-form/index.ts: -------------------------------------------------------------------------------- 1 | export * from './login-form'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-08-start/src/features/auth/components/protected/index.ts: -------------------------------------------------------------------------------- 1 | export * from './protected'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-08-start/src/features/auth/index.ts: -------------------------------------------------------------------------------- 1 | // api: 2 | export * from './api/get-auth-user'; 3 | export * from './api/logout'; 4 | 5 | // components: 6 | export * from './components/login-form'; 7 | export * from './components/protected'; 8 | 9 | // types: 10 | export * from './types'; 11 | -------------------------------------------------------------------------------- /code-stages/chapter-08-start/src/features/auth/types/index.ts: -------------------------------------------------------------------------------- 1 | import { Entity } from '@/types'; 2 | 3 | export type AuthUser = Entity & { 4 | email: string; 5 | organizationId: string; 6 | }; 7 | 8 | export type LoginData = { 9 | email: string; 10 | password: string; 11 | }; 12 | -------------------------------------------------------------------------------- /code-stages/chapter-08-start/src/features/jobs/components/create-job-form/index.ts: -------------------------------------------------------------------------------- 1 | export * from './create-job-form'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-08-start/src/features/jobs/components/dashboard-job-info/index.ts: -------------------------------------------------------------------------------- 1 | export * from './dashboard-job-info'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-08-start/src/features/jobs/components/jobs-list/index.ts: -------------------------------------------------------------------------------- 1 | export * from './jobs-list'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-08-start/src/features/jobs/components/public-job-info/index.ts: -------------------------------------------------------------------------------- 1 | export * from './public-job-info'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-08-start/src/features/jobs/index.ts: -------------------------------------------------------------------------------- 1 | // api: 2 | export * from './api/get-job'; 3 | export * from './api/get-jobs'; 4 | 5 | // components: 6 | export * from './components/create-job-form'; 7 | export * from './components/dashboard-job-info'; 8 | export * from './components/jobs-list'; 9 | export * from './components/public-job-info'; 10 | 11 | // types: 12 | export * from './types'; 13 | -------------------------------------------------------------------------------- /code-stages/chapter-08-start/src/features/jobs/types/index.ts: -------------------------------------------------------------------------------- 1 | import { Entity } from '@/types'; 2 | 3 | export type Job = Entity & { 4 | organizationId: string; 5 | position: string; 6 | info: string; 7 | location: string; 8 | department: string; 9 | }; 10 | 11 | export type CreateJobData = Pick< 12 | Job, 13 | 'position' | 'department' | 'location' | 'info' 14 | >; 15 | -------------------------------------------------------------------------------- /code-stages/chapter-08-start/src/features/organizations/components/organization-info/index.ts: -------------------------------------------------------------------------------- 1 | export * from './organization-info'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-08-start/src/features/organizations/index.ts: -------------------------------------------------------------------------------- 1 | // api: 2 | export * from './api/get-organization'; 3 | 4 | // components: 5 | export * from './components/organization-info'; 6 | 7 | // types: 8 | export * from './types'; 9 | -------------------------------------------------------------------------------- /code-stages/chapter-08-start/src/features/organizations/types/index.ts: -------------------------------------------------------------------------------- 1 | import { Entity } from '@/types'; 2 | 3 | export type Organization = Entity & { 4 | adminId: string; 5 | name: string; 6 | email: string; 7 | phone: string; 8 | info: string; 9 | }; 10 | -------------------------------------------------------------------------------- /code-stages/chapter-08-start/src/lib/react-query.ts: -------------------------------------------------------------------------------- 1 | import { QueryClient } from '@tanstack/react-query'; 2 | 3 | export const queryClient = new QueryClient({ 4 | defaultOptions: { 5 | queries: { 6 | retry: false, 7 | refetchOnWindowFocus: false, 8 | useErrorBoundary: true, 9 | }, 10 | }, 11 | }); 12 | -------------------------------------------------------------------------------- /code-stages/chapter-08-start/src/pages/404.tsx: -------------------------------------------------------------------------------- 1 | import { Center } from '@chakra-ui/react'; 2 | 3 | import { Link } from '@/components/link'; 4 | import { NotFound } from '@/components/not-found'; 5 | 6 | const NotFoundPage = () => { 7 | return ( 8 | <> 9 | 10 |
11 | Home 12 |
13 | 14 | ); 15 | }; 16 | 17 | export default NotFoundPage; 18 | -------------------------------------------------------------------------------- /code-stages/chapter-08-start/src/stores/notifications/__tests__/notifications.test.ts: -------------------------------------------------------------------------------- 1 | describe('notifications store', () => { 2 | it.todo('should add and remove notifications'); 3 | }); 4 | -------------------------------------------------------------------------------- /code-stages/chapter-08-start/src/stores/notifications/index.ts: -------------------------------------------------------------------------------- 1 | export * from './notifications'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-08-start/src/testing/mocks/browser.ts: -------------------------------------------------------------------------------- 1 | import { setupWorker } from 'msw'; 2 | 3 | import { handlers } from './handlers'; 4 | 5 | export const worker = setupWorker(...handlers); 6 | -------------------------------------------------------------------------------- /code-stages/chapter-08-start/src/testing/mocks/index.ts: -------------------------------------------------------------------------------- 1 | export * from './handlers'; 2 | 3 | export * from './db'; 4 | -------------------------------------------------------------------------------- /code-stages/chapter-08-start/src/testing/mocks/initialize.ts: -------------------------------------------------------------------------------- 1 | import { IS_SERVER } from '@/config/constants'; 2 | 3 | import { seedDb } from './seed-db'; 4 | 5 | const initializeMocks = () => { 6 | if (IS_SERVER) { 7 | const { server } = require('./server'); 8 | server.listen(); 9 | } else { 10 | const { worker } = require('./browser'); 11 | worker.start(); 12 | } 13 | seedDb(); 14 | }; 15 | 16 | initializeMocks(); 17 | -------------------------------------------------------------------------------- /code-stages/chapter-08-start/src/testing/mocks/seed-db.ts: -------------------------------------------------------------------------------- 1 | import { testData } from '../test-data'; 2 | 3 | import { db } from './db'; 4 | 5 | export const seedDb = () => { 6 | const userCount = db.user.count(); 7 | 8 | if (userCount > 0) return; 9 | 10 | testData.users.forEach((user) => db.user.create(user)); 11 | 12 | testData.organizations.forEach((organization) => 13 | db.organization.create(organization) 14 | ); 15 | 16 | testData.jobs.forEach((job) => db.job.create(job)); 17 | }; 18 | -------------------------------------------------------------------------------- /code-stages/chapter-08-start/src/testing/mocks/server.ts: -------------------------------------------------------------------------------- 1 | import { setupServer } from 'msw/node'; 2 | 3 | import { handlers } from './handlers'; 4 | 5 | export const server = setupServer(...handlers); 6 | -------------------------------------------------------------------------------- /code-stages/chapter-08-start/src/types/index.ts: -------------------------------------------------------------------------------- 1 | export type Entity = { 2 | id: string; 3 | createdAt: number; 4 | }; 5 | -------------------------------------------------------------------------------- /code-stages/chapter-08-start/src/utils/format.ts: -------------------------------------------------------------------------------- 1 | export const formatDate = (date: number | string) => { 2 | return new Date(date).toLocaleDateString('en-US', { 3 | month: 'long', 4 | year: 'numeric', 5 | day: 'numeric', 6 | }); 7 | }; 8 | -------------------------------------------------------------------------------- /code-stages/chapter-08-start/src/utils/uid.ts: -------------------------------------------------------------------------------- 1 | // https://gist.github.com/gordonbrander/2230317?permalink_comment_id=3443509#gistcomment-3443509 2 | export const uid = () => { 3 | return ( 4 | performance.now().toString(36) + 5 | Math.random().toString(36) 6 | ).replace(/\./g, ''); 7 | }; 8 | -------------------------------------------------------------------------------- /code-stages/chapter-08/cypress.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'cypress'; 2 | 3 | export default defineConfig({ 4 | video: false, 5 | videoUploadOnPasses: false, 6 | e2e: { 7 | // We've imported your old cypress plugins here. 8 | // You may want to clean this up later by importing these. 9 | setupNodeEvents(on, config) { 10 | return require('./cypress/plugins/index.ts')( 11 | on, 12 | config 13 | ); 14 | }, 15 | }, 16 | }); 17 | -------------------------------------------------------------------------------- /code-stages/chapter-08/cypress/fixtures/example.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Using fixtures to represent data", 3 | "email": "hello@cypress.io", 4 | "body": "Fixtures are a great way to mock data for responses to routes" 5 | } 6 | -------------------------------------------------------------------------------- /code-stages/chapter-08/cypress/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "esModuleInterop": true, 4 | "target": "es5", 5 | "lib": ["es5", "dom"], 6 | "types": [ 7 | "node", 8 | "cypress", 9 | "@testing-library/cypress" 10 | ] 11 | }, 12 | "include": ["**/*.ts"] 13 | } 14 | -------------------------------------------------------------------------------- /code-stages/chapter-08/src/components/button/index.ts: -------------------------------------------------------------------------------- 1 | export * from './button'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-08/src/components/content/content.tsx: -------------------------------------------------------------------------------- 1 | import { Box } from '@chakra-ui/react'; 2 | 3 | export type ContentProps = { 4 | children: string; 5 | }; 6 | 7 | export const Content = ({ children }: ContentProps) => { 8 | return ( 9 | 10 | {children} 11 | 12 | ); 13 | }; 14 | -------------------------------------------------------------------------------- /code-stages/chapter-08/src/components/content/index.ts: -------------------------------------------------------------------------------- 1 | export * from './content'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-08/src/components/data-table/index.ts: -------------------------------------------------------------------------------- 1 | export * from './data-table'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-08/src/components/form/index.ts: -------------------------------------------------------------------------------- 1 | export * from './input-field'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-08/src/components/info-card/index.ts: -------------------------------------------------------------------------------- 1 | export * from './info-card'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-08/src/components/link/index.ts: -------------------------------------------------------------------------------- 1 | export * from './link'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-08/src/components/loading/index.ts: -------------------------------------------------------------------------------- 1 | export * from './loading'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-08/src/components/loading/loading.stories.tsx: -------------------------------------------------------------------------------- 1 | import { Meta, Story } from '@storybook/react'; 2 | 3 | import { Loading } from './loading'; 4 | 5 | const meta: Meta = { 6 | title: 'Components/Loading', 7 | component: Loading, 8 | }; 9 | 10 | export default meta; 11 | 12 | const Template: Story = (props) => ; 13 | 14 | export const Default = Template.bind({}); 15 | -------------------------------------------------------------------------------- /code-stages/chapter-08/src/components/loading/loading.tsx: -------------------------------------------------------------------------------- 1 | import { Center, Spinner } from '@chakra-ui/react'; 2 | 3 | export const Loading = () => { 4 | return ( 5 |
6 | 11 |
12 | ); 13 | }; 14 | -------------------------------------------------------------------------------- /code-stages/chapter-08/src/components/not-found/index.ts: -------------------------------------------------------------------------------- 1 | export * from './not-found'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-08/src/components/not-found/not-found.stories.tsx: -------------------------------------------------------------------------------- 1 | import { Meta, Story } from '@storybook/react'; 2 | 3 | import { NotFound } from './not-found'; 4 | 5 | const meta: Meta = { 6 | title: 'Components/NotFound', 7 | component: NotFound, 8 | }; 9 | 10 | export default meta; 11 | 12 | const Template: Story = (props) => ( 13 | 14 | ); 15 | 16 | export const Default = Template.bind({}); 17 | -------------------------------------------------------------------------------- /code-stages/chapter-08/src/components/not-found/not-found.tsx: -------------------------------------------------------------------------------- 1 | import { NotAllowedIcon } from '@chakra-ui/icons'; 2 | import { 3 | Center, 4 | Heading, 5 | VStack, 6 | } from '@chakra-ui/react'; 7 | 8 | export const NotFound = () => { 9 | return ( 10 |
11 | 12 | 13 | Not Found 14 | 15 |
16 | ); 17 | }; 18 | -------------------------------------------------------------------------------- /code-stages/chapter-08/src/components/notifications/index.ts: -------------------------------------------------------------------------------- 1 | export * from './notifications'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-08/src/components/seo/index.ts: -------------------------------------------------------------------------------- 1 | export * from './seo'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-08/src/components/seo/seo.tsx: -------------------------------------------------------------------------------- 1 | import Head from 'next/head'; 2 | 3 | export type SeoProps = { 4 | title: string; 5 | }; 6 | 7 | export const Seo = ({ title }: SeoProps) => { 8 | return ( 9 | 10 | {title} 11 | 12 | ); 13 | }; 14 | -------------------------------------------------------------------------------- /code-stages/chapter-08/src/config/theme.ts: -------------------------------------------------------------------------------- 1 | import { extendTheme } from '@chakra-ui/react'; 2 | 3 | const colors = { 4 | primary: '#1a365d', 5 | primaryAccent: 'white', 6 | }; 7 | 8 | const styles = { 9 | global: { 10 | 'html, body': { 11 | height: '100%', 12 | bg: 'gray.50', 13 | }, 14 | 15 | '#__next': { 16 | height: '100%', 17 | bg: 'gray.50', 18 | }, 19 | }, 20 | }; 21 | 22 | export const theme = extendTheme({ colors, styles }); 23 | -------------------------------------------------------------------------------- /code-stages/chapter-08/src/features/auth/components/login-form/index.ts: -------------------------------------------------------------------------------- 1 | export * from './login-form'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-08/src/features/auth/components/protected/index.ts: -------------------------------------------------------------------------------- 1 | export * from './protected'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-08/src/features/auth/index.ts: -------------------------------------------------------------------------------- 1 | // api: 2 | export * from './api/get-auth-user'; 3 | export * from './api/logout'; 4 | 5 | // components: 6 | export * from './components/login-form'; 7 | export * from './components/protected'; 8 | 9 | // types: 10 | export * from './types'; 11 | -------------------------------------------------------------------------------- /code-stages/chapter-08/src/features/auth/types/index.ts: -------------------------------------------------------------------------------- 1 | import { Entity } from '@/types'; 2 | 3 | export type AuthUser = Entity & { 4 | email: string; 5 | organizationId: string; 6 | }; 7 | 8 | export type LoginData = { 9 | email: string; 10 | password: string; 11 | }; 12 | -------------------------------------------------------------------------------- /code-stages/chapter-08/src/features/jobs/components/create-job-form/index.ts: -------------------------------------------------------------------------------- 1 | export * from './create-job-form'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-08/src/features/jobs/components/dashboard-job-info/index.ts: -------------------------------------------------------------------------------- 1 | export * from './dashboard-job-info'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-08/src/features/jobs/components/jobs-list/index.ts: -------------------------------------------------------------------------------- 1 | export * from './jobs-list'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-08/src/features/jobs/components/public-job-info/index.ts: -------------------------------------------------------------------------------- 1 | export * from './public-job-info'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-08/src/features/jobs/index.ts: -------------------------------------------------------------------------------- 1 | // api: 2 | export * from './api/get-job'; 3 | export * from './api/get-jobs'; 4 | 5 | // components: 6 | export * from './components/create-job-form'; 7 | export * from './components/dashboard-job-info'; 8 | export * from './components/jobs-list'; 9 | export * from './components/public-job-info'; 10 | 11 | // types: 12 | export * from './types'; 13 | -------------------------------------------------------------------------------- /code-stages/chapter-08/src/features/jobs/types/index.ts: -------------------------------------------------------------------------------- 1 | import { Entity } from '@/types'; 2 | 3 | export type Job = Entity & { 4 | organizationId: string; 5 | position: string; 6 | info: string; 7 | location: string; 8 | department: string; 9 | }; 10 | 11 | export type CreateJobData = Pick< 12 | Job, 13 | 'position' | 'department' | 'location' | 'info' 14 | >; 15 | -------------------------------------------------------------------------------- /code-stages/chapter-08/src/features/organizations/components/organization-info/index.ts: -------------------------------------------------------------------------------- 1 | export * from './organization-info'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-08/src/features/organizations/index.ts: -------------------------------------------------------------------------------- 1 | // api: 2 | export * from './api/get-organization'; 3 | 4 | // components: 5 | export * from './components/organization-info'; 6 | 7 | // types: 8 | export * from './types'; 9 | -------------------------------------------------------------------------------- /code-stages/chapter-08/src/features/organizations/types/index.ts: -------------------------------------------------------------------------------- 1 | import { Entity } from '@/types'; 2 | 3 | export type Organization = Entity & { 4 | adminId: string; 5 | name: string; 6 | email: string; 7 | phone: string; 8 | info: string; 9 | }; 10 | -------------------------------------------------------------------------------- /code-stages/chapter-08/src/lib/react-query.ts: -------------------------------------------------------------------------------- 1 | import { QueryClient } from '@tanstack/react-query'; 2 | 3 | export const queryClient = new QueryClient({ 4 | defaultOptions: { 5 | queries: { 6 | retry: false, 7 | refetchOnWindowFocus: false, 8 | useErrorBoundary: true, 9 | }, 10 | }, 11 | }); 12 | -------------------------------------------------------------------------------- /code-stages/chapter-08/src/pages/404.tsx: -------------------------------------------------------------------------------- 1 | import { Center } from '@chakra-ui/react'; 2 | 3 | import { Link } from '@/components/link'; 4 | import { NotFound } from '@/components/not-found'; 5 | 6 | const NotFoundPage = () => { 7 | return ( 8 | <> 9 | 10 |
11 | Home 12 |
13 | 14 | ); 15 | }; 16 | 17 | export default NotFoundPage; 18 | -------------------------------------------------------------------------------- /code-stages/chapter-08/src/stores/notifications/index.ts: -------------------------------------------------------------------------------- 1 | export * from './notifications'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-08/src/testing/mocks/browser.ts: -------------------------------------------------------------------------------- 1 | import { setupWorker } from 'msw'; 2 | 3 | import { handlers } from './handlers'; 4 | 5 | export const worker = setupWorker(...handlers); 6 | -------------------------------------------------------------------------------- /code-stages/chapter-08/src/testing/mocks/index.ts: -------------------------------------------------------------------------------- 1 | export * from './handlers'; 2 | 3 | export * from './db'; 4 | -------------------------------------------------------------------------------- /code-stages/chapter-08/src/testing/mocks/initialize.ts: -------------------------------------------------------------------------------- 1 | import { IS_SERVER } from '@/config/constants'; 2 | 3 | import { seedDb } from './seed-db'; 4 | 5 | const initializeMocks = () => { 6 | if (IS_SERVER) { 7 | const { server } = require('./server'); 8 | server.listen(); 9 | } else { 10 | const { worker } = require('./browser'); 11 | worker.start(); 12 | } 13 | seedDb(); 14 | }; 15 | 16 | initializeMocks(); 17 | -------------------------------------------------------------------------------- /code-stages/chapter-08/src/testing/mocks/seed-db.ts: -------------------------------------------------------------------------------- 1 | import { testData } from '../test-data'; 2 | 3 | import { db } from './db'; 4 | 5 | export const seedDb = () => { 6 | const userCount = db.user.count(); 7 | 8 | if (userCount > 0) return; 9 | 10 | testData.users.forEach((user) => db.user.create(user)); 11 | 12 | testData.organizations.forEach((organization) => 13 | db.organization.create(organization) 14 | ); 15 | 16 | testData.jobs.forEach((job) => db.job.create(job)); 17 | }; 18 | -------------------------------------------------------------------------------- /code-stages/chapter-08/src/testing/mocks/server.ts: -------------------------------------------------------------------------------- 1 | import { setupServer } from 'msw/node'; 2 | 3 | import { handlers } from './handlers'; 4 | 5 | export const server = setupServer(...handlers); 6 | -------------------------------------------------------------------------------- /code-stages/chapter-08/src/types/index.ts: -------------------------------------------------------------------------------- 1 | export type Entity = { 2 | id: string; 3 | createdAt: number; 4 | }; 5 | -------------------------------------------------------------------------------- /code-stages/chapter-08/src/utils/format.ts: -------------------------------------------------------------------------------- 1 | export const formatDate = (date: number | string) => { 2 | return new Date(date).toLocaleDateString('en-US', { 3 | month: 'long', 4 | year: 'numeric', 5 | day: 'numeric', 6 | }); 7 | }; 8 | -------------------------------------------------------------------------------- /code-stages/chapter-08/src/utils/uid.ts: -------------------------------------------------------------------------------- 1 | // https://gist.github.com/gordonbrander/2230317?permalink_comment_id=3443509#gistcomment-3443509 2 | export const uid = () => { 3 | return ( 4 | performance.now().toString(36) + 5 | Math.random().toString(36) 6 | ).replace(/\./g, ''); 7 | }; 8 | -------------------------------------------------------------------------------- /code-stages/chapter-09-start/cypress.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'cypress'; 2 | 3 | export default defineConfig({ 4 | video: false, 5 | videoUploadOnPasses: false, 6 | e2e: { 7 | // We've imported your old cypress plugins here. 8 | // You may want to clean this up later by importing these. 9 | setupNodeEvents(on, config) { 10 | return require('./cypress/plugins/index.ts')( 11 | on, 12 | config 13 | ); 14 | }, 15 | }, 16 | }); 17 | -------------------------------------------------------------------------------- /code-stages/chapter-09-start/cypress/fixtures/example.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Using fixtures to represent data", 3 | "email": "hello@cypress.io", 4 | "body": "Fixtures are a great way to mock data for responses to routes" 5 | } 6 | -------------------------------------------------------------------------------- /code-stages/chapter-09-start/cypress/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "esModuleInterop": true, 4 | "target": "es5", 5 | "lib": ["es5", "dom"], 6 | "types": [ 7 | "node", 8 | "cypress", 9 | "@testing-library/cypress" 10 | ] 11 | }, 12 | "include": ["**/*.ts"] 13 | } 14 | -------------------------------------------------------------------------------- /code-stages/chapter-09-start/src/components/button/index.ts: -------------------------------------------------------------------------------- 1 | export * from './button'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-09-start/src/components/content/content.tsx: -------------------------------------------------------------------------------- 1 | import { Box } from '@chakra-ui/react'; 2 | 3 | export type ContentProps = { 4 | children: string; 5 | }; 6 | 7 | export const Content = ({ children }: ContentProps) => { 8 | return ( 9 | 10 | {children} 11 | 12 | ); 13 | }; 14 | -------------------------------------------------------------------------------- /code-stages/chapter-09-start/src/components/content/index.ts: -------------------------------------------------------------------------------- 1 | export * from './content'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-09-start/src/components/data-table/index.ts: -------------------------------------------------------------------------------- 1 | export * from './data-table'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-09-start/src/components/form/index.ts: -------------------------------------------------------------------------------- 1 | export * from './input-field'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-09-start/src/components/info-card/index.ts: -------------------------------------------------------------------------------- 1 | export * from './info-card'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-09-start/src/components/link/index.ts: -------------------------------------------------------------------------------- 1 | export * from './link'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-09-start/src/components/loading/index.ts: -------------------------------------------------------------------------------- 1 | export * from './loading'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-09-start/src/components/loading/loading.stories.tsx: -------------------------------------------------------------------------------- 1 | import { Meta, Story } from '@storybook/react'; 2 | 3 | import { Loading } from './loading'; 4 | 5 | const meta: Meta = { 6 | title: 'Components/Loading', 7 | component: Loading, 8 | }; 9 | 10 | export default meta; 11 | 12 | const Template: Story = (props) => ; 13 | 14 | export const Default = Template.bind({}); 15 | -------------------------------------------------------------------------------- /code-stages/chapter-09-start/src/components/loading/loading.tsx: -------------------------------------------------------------------------------- 1 | import { Center, Spinner } from '@chakra-ui/react'; 2 | 3 | export const Loading = () => { 4 | return ( 5 |
6 | 11 |
12 | ); 13 | }; 14 | -------------------------------------------------------------------------------- /code-stages/chapter-09-start/src/components/not-found/index.ts: -------------------------------------------------------------------------------- 1 | export * from './not-found'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-09-start/src/components/not-found/not-found.stories.tsx: -------------------------------------------------------------------------------- 1 | import { Meta, Story } from '@storybook/react'; 2 | 3 | import { NotFound } from './not-found'; 4 | 5 | const meta: Meta = { 6 | title: 'Components/NotFound', 7 | component: NotFound, 8 | }; 9 | 10 | export default meta; 11 | 12 | const Template: Story = (props) => ( 13 | 14 | ); 15 | 16 | export const Default = Template.bind({}); 17 | -------------------------------------------------------------------------------- /code-stages/chapter-09-start/src/components/not-found/not-found.tsx: -------------------------------------------------------------------------------- 1 | import { NotAllowedIcon } from '@chakra-ui/icons'; 2 | import { 3 | Center, 4 | Heading, 5 | VStack, 6 | } from '@chakra-ui/react'; 7 | 8 | export const NotFound = () => { 9 | return ( 10 |
11 | 12 | 13 | Not Found 14 | 15 |
16 | ); 17 | }; 18 | -------------------------------------------------------------------------------- /code-stages/chapter-09-start/src/components/notifications/index.ts: -------------------------------------------------------------------------------- 1 | export * from './notifications'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-09-start/src/components/seo/index.ts: -------------------------------------------------------------------------------- 1 | export * from './seo'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-09-start/src/components/seo/seo.tsx: -------------------------------------------------------------------------------- 1 | import Head from 'next/head'; 2 | 3 | export type SeoProps = { 4 | title: string; 5 | }; 6 | 7 | export const Seo = ({ title }: SeoProps) => { 8 | return ( 9 | 10 | {title} 11 | 12 | ); 13 | }; 14 | -------------------------------------------------------------------------------- /code-stages/chapter-09-start/src/config/theme.ts: -------------------------------------------------------------------------------- 1 | import { extendTheme } from '@chakra-ui/react'; 2 | 3 | const colors = { 4 | primary: '#1a365d', 5 | primaryAccent: 'white', 6 | }; 7 | 8 | const styles = { 9 | global: { 10 | 'html, body': { 11 | height: '100%', 12 | bg: 'gray.50', 13 | }, 14 | 15 | '#__next': { 16 | height: '100%', 17 | bg: 'gray.50', 18 | }, 19 | }, 20 | }; 21 | 22 | export const theme = extendTheme({ colors, styles }); 23 | -------------------------------------------------------------------------------- /code-stages/chapter-09-start/src/features/auth/components/login-form/index.ts: -------------------------------------------------------------------------------- 1 | export * from './login-form'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-09-start/src/features/auth/components/protected/index.ts: -------------------------------------------------------------------------------- 1 | export * from './protected'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-09-start/src/features/auth/index.ts: -------------------------------------------------------------------------------- 1 | // api: 2 | export * from './api/get-auth-user'; 3 | export * from './api/logout'; 4 | 5 | // components: 6 | export * from './components/login-form'; 7 | export * from './components/protected'; 8 | 9 | // types: 10 | export * from './types'; 11 | -------------------------------------------------------------------------------- /code-stages/chapter-09-start/src/features/auth/types/index.ts: -------------------------------------------------------------------------------- 1 | import { Entity } from '@/types'; 2 | 3 | export type AuthUser = Entity & { 4 | email: string; 5 | organizationId: string; 6 | }; 7 | 8 | export type LoginData = { 9 | email: string; 10 | password: string; 11 | }; 12 | -------------------------------------------------------------------------------- /code-stages/chapter-09-start/src/features/jobs/components/create-job-form/index.ts: -------------------------------------------------------------------------------- 1 | export * from './create-job-form'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-09-start/src/features/jobs/components/dashboard-job-info/index.ts: -------------------------------------------------------------------------------- 1 | export * from './dashboard-job-info'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-09-start/src/features/jobs/components/jobs-list/index.ts: -------------------------------------------------------------------------------- 1 | export * from './jobs-list'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-09-start/src/features/jobs/components/public-job-info/index.ts: -------------------------------------------------------------------------------- 1 | export * from './public-job-info'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-09-start/src/features/jobs/index.ts: -------------------------------------------------------------------------------- 1 | // api: 2 | export * from './api/get-job'; 3 | export * from './api/get-jobs'; 4 | 5 | // components: 6 | export * from './components/create-job-form'; 7 | export * from './components/dashboard-job-info'; 8 | export * from './components/jobs-list'; 9 | export * from './components/public-job-info'; 10 | 11 | // types: 12 | export * from './types'; 13 | -------------------------------------------------------------------------------- /code-stages/chapter-09-start/src/features/jobs/types/index.ts: -------------------------------------------------------------------------------- 1 | import { Entity } from '@/types'; 2 | 3 | export type Job = Entity & { 4 | organizationId: string; 5 | position: string; 6 | info: string; 7 | location: string; 8 | department: string; 9 | }; 10 | 11 | export type CreateJobData = Pick< 12 | Job, 13 | 'position' | 'department' | 'location' | 'info' 14 | >; 15 | -------------------------------------------------------------------------------- /code-stages/chapter-09-start/src/features/organizations/components/organization-info/index.ts: -------------------------------------------------------------------------------- 1 | export * from './organization-info'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-09-start/src/features/organizations/index.ts: -------------------------------------------------------------------------------- 1 | // api: 2 | export * from './api/get-organization'; 3 | 4 | // components: 5 | export * from './components/organization-info'; 6 | 7 | // types: 8 | export * from './types'; 9 | -------------------------------------------------------------------------------- /code-stages/chapter-09-start/src/features/organizations/types/index.ts: -------------------------------------------------------------------------------- 1 | import { Entity } from '@/types'; 2 | 3 | export type Organization = Entity & { 4 | adminId: string; 5 | name: string; 6 | email: string; 7 | phone: string; 8 | info: string; 9 | }; 10 | -------------------------------------------------------------------------------- /code-stages/chapter-09-start/src/lib/react-query.ts: -------------------------------------------------------------------------------- 1 | import { QueryClient } from '@tanstack/react-query'; 2 | 3 | export const queryClient = new QueryClient({ 4 | defaultOptions: { 5 | queries: { 6 | retry: false, 7 | refetchOnWindowFocus: false, 8 | useErrorBoundary: true, 9 | }, 10 | }, 11 | }); 12 | -------------------------------------------------------------------------------- /code-stages/chapter-09-start/src/pages/404.tsx: -------------------------------------------------------------------------------- 1 | import { Center } from '@chakra-ui/react'; 2 | 3 | import { Link } from '@/components/link'; 4 | import { NotFound } from '@/components/not-found'; 5 | 6 | const NotFoundPage = () => { 7 | return ( 8 | <> 9 | 10 |
11 | Home 12 |
13 | 14 | ); 15 | }; 16 | 17 | export default NotFoundPage; 18 | -------------------------------------------------------------------------------- /code-stages/chapter-09-start/src/stores/notifications/index.ts: -------------------------------------------------------------------------------- 1 | export * from './notifications'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-09-start/src/testing/mocks/browser.ts: -------------------------------------------------------------------------------- 1 | import { setupWorker } from 'msw'; 2 | 3 | import { handlers } from './handlers'; 4 | 5 | export const worker = setupWorker(...handlers); 6 | -------------------------------------------------------------------------------- /code-stages/chapter-09-start/src/testing/mocks/index.ts: -------------------------------------------------------------------------------- 1 | export * from './handlers'; 2 | 3 | export * from './db'; 4 | -------------------------------------------------------------------------------- /code-stages/chapter-09-start/src/testing/mocks/initialize.ts: -------------------------------------------------------------------------------- 1 | import { IS_SERVER } from '@/config/constants'; 2 | 3 | import { seedDb } from './seed-db'; 4 | 5 | const initializeMocks = () => { 6 | if (IS_SERVER) { 7 | const { server } = require('./server'); 8 | server.listen(); 9 | } else { 10 | const { worker } = require('./browser'); 11 | worker.start(); 12 | } 13 | seedDb(); 14 | }; 15 | 16 | initializeMocks(); 17 | -------------------------------------------------------------------------------- /code-stages/chapter-09-start/src/testing/mocks/server.ts: -------------------------------------------------------------------------------- 1 | import { setupServer } from 'msw/node'; 2 | 3 | import { handlers } from './handlers'; 4 | 5 | export const server = setupServer(...handlers); 6 | -------------------------------------------------------------------------------- /code-stages/chapter-09-start/src/types/index.ts: -------------------------------------------------------------------------------- 1 | export type Entity = { 2 | id: string; 3 | createdAt: number; 4 | }; 5 | -------------------------------------------------------------------------------- /code-stages/chapter-09-start/src/utils/format.ts: -------------------------------------------------------------------------------- 1 | export const formatDate = (date: number | string) => { 2 | return new Date(date).toLocaleDateString('en-US', { 3 | month: 'long', 4 | year: 'numeric', 5 | day: 'numeric', 6 | }); 7 | }; 8 | -------------------------------------------------------------------------------- /code-stages/chapter-09-start/src/utils/uid.ts: -------------------------------------------------------------------------------- 1 | // https://gist.github.com/gordonbrander/2230317?permalink_comment_id=3443509#gistcomment-3443509 2 | export const uid = () => { 3 | return ( 4 | performance.now().toString(36) + 5 | Math.random().toString(36) 6 | ).replace(/\./g, ''); 7 | }; 8 | -------------------------------------------------------------------------------- /code-stages/chapter-09/cypress.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'cypress'; 2 | 3 | export default defineConfig({ 4 | video: false, 5 | videoUploadOnPasses: false, 6 | e2e: { 7 | // We've imported your old cypress plugins here. 8 | // You may want to clean this up later by importing these. 9 | setupNodeEvents(on, config) { 10 | return require('./cypress/plugins/index.ts')( 11 | on, 12 | config 13 | ); 14 | }, 15 | }, 16 | }); 17 | -------------------------------------------------------------------------------- /code-stages/chapter-09/cypress/fixtures/example.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Using fixtures to represent data", 3 | "email": "hello@cypress.io", 4 | "body": "Fixtures are a great way to mock data for responses to routes" 5 | } 6 | -------------------------------------------------------------------------------- /code-stages/chapter-09/cypress/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "esModuleInterop": true, 4 | "target": "es5", 5 | "lib": ["es5", "dom"], 6 | "types": [ 7 | "node", 8 | "cypress", 9 | "@testing-library/cypress" 10 | ] 11 | }, 12 | "include": ["**/*.ts"] 13 | } 14 | -------------------------------------------------------------------------------- /code-stages/chapter-09/src/components/button/index.ts: -------------------------------------------------------------------------------- 1 | export * from './button'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-09/src/components/content/content.tsx: -------------------------------------------------------------------------------- 1 | import { Box } from '@chakra-ui/react'; 2 | 3 | export type ContentProps = { 4 | children: string; 5 | }; 6 | 7 | export const Content = ({ children }: ContentProps) => { 8 | return ( 9 | 10 | {children} 11 | 12 | ); 13 | }; 14 | -------------------------------------------------------------------------------- /code-stages/chapter-09/src/components/content/index.ts: -------------------------------------------------------------------------------- 1 | export * from './content'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-09/src/components/data-table/index.ts: -------------------------------------------------------------------------------- 1 | export * from './data-table'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-09/src/components/form/index.ts: -------------------------------------------------------------------------------- 1 | export * from './input-field'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-09/src/components/info-card/index.ts: -------------------------------------------------------------------------------- 1 | export * from './info-card'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-09/src/components/link/index.ts: -------------------------------------------------------------------------------- 1 | export * from './link'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-09/src/components/loading/index.ts: -------------------------------------------------------------------------------- 1 | export * from './loading'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-09/src/components/loading/loading.stories.tsx: -------------------------------------------------------------------------------- 1 | import { Meta, Story } from '@storybook/react'; 2 | 3 | import { Loading } from './loading'; 4 | 5 | const meta: Meta = { 6 | title: 'Components/Loading', 7 | component: Loading, 8 | }; 9 | 10 | export default meta; 11 | 12 | const Template: Story = (props) => ; 13 | 14 | export const Default = Template.bind({}); 15 | -------------------------------------------------------------------------------- /code-stages/chapter-09/src/components/loading/loading.tsx: -------------------------------------------------------------------------------- 1 | import { Center, Spinner } from '@chakra-ui/react'; 2 | 3 | export const Loading = () => { 4 | return ( 5 |
6 | 11 |
12 | ); 13 | }; 14 | -------------------------------------------------------------------------------- /code-stages/chapter-09/src/components/not-found/index.ts: -------------------------------------------------------------------------------- 1 | export * from './not-found'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-09/src/components/not-found/not-found.stories.tsx: -------------------------------------------------------------------------------- 1 | import { Meta, Story } from '@storybook/react'; 2 | 3 | import { NotFound } from './not-found'; 4 | 5 | const meta: Meta = { 6 | title: 'Components/NotFound', 7 | component: NotFound, 8 | }; 9 | 10 | export default meta; 11 | 12 | const Template: Story = (props) => ( 13 | 14 | ); 15 | 16 | export const Default = Template.bind({}); 17 | -------------------------------------------------------------------------------- /code-stages/chapter-09/src/components/not-found/not-found.tsx: -------------------------------------------------------------------------------- 1 | import { NotAllowedIcon } from '@chakra-ui/icons'; 2 | import { 3 | Center, 4 | Heading, 5 | VStack, 6 | } from '@chakra-ui/react'; 7 | 8 | export const NotFound = () => { 9 | return ( 10 |
11 | 12 | 13 | Not Found 14 | 15 |
16 | ); 17 | }; 18 | -------------------------------------------------------------------------------- /code-stages/chapter-09/src/components/notifications/index.ts: -------------------------------------------------------------------------------- 1 | export * from './notifications'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-09/src/components/seo/index.ts: -------------------------------------------------------------------------------- 1 | export * from './seo'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-09/src/components/seo/seo.tsx: -------------------------------------------------------------------------------- 1 | import Head from 'next/head'; 2 | 3 | export type SeoProps = { 4 | title: string; 5 | }; 6 | 7 | export const Seo = ({ title }: SeoProps) => { 8 | return ( 9 | 10 | {title} 11 | 12 | ); 13 | }; 14 | -------------------------------------------------------------------------------- /code-stages/chapter-09/src/config/theme.ts: -------------------------------------------------------------------------------- 1 | import { extendTheme } from '@chakra-ui/react'; 2 | 3 | const colors = { 4 | primary: '#1a365d', 5 | primaryAccent: 'white', 6 | }; 7 | 8 | const styles = { 9 | global: { 10 | 'html, body': { 11 | height: '100%', 12 | bg: 'gray.50', 13 | }, 14 | 15 | '#__next': { 16 | height: '100%', 17 | bg: 'gray.50', 18 | }, 19 | }, 20 | }; 21 | 22 | export const theme = extendTheme({ colors, styles }); 23 | -------------------------------------------------------------------------------- /code-stages/chapter-09/src/features/auth/components/login-form/index.ts: -------------------------------------------------------------------------------- 1 | export * from './login-form'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-09/src/features/auth/components/protected/index.ts: -------------------------------------------------------------------------------- 1 | export * from './protected'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-09/src/features/auth/index.ts: -------------------------------------------------------------------------------- 1 | // api: 2 | export * from './api/get-auth-user'; 3 | export * from './api/logout'; 4 | 5 | // components: 6 | export * from './components/login-form'; 7 | export * from './components/protected'; 8 | 9 | // types: 10 | export * from './types'; 11 | -------------------------------------------------------------------------------- /code-stages/chapter-09/src/features/auth/types/index.ts: -------------------------------------------------------------------------------- 1 | import { Entity } from '@/types'; 2 | 3 | export type AuthUser = Entity & { 4 | email: string; 5 | organizationId: string; 6 | }; 7 | 8 | export type LoginData = { 9 | email: string; 10 | password: string; 11 | }; 12 | -------------------------------------------------------------------------------- /code-stages/chapter-09/src/features/jobs/components/create-job-form/index.ts: -------------------------------------------------------------------------------- 1 | export * from './create-job-form'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-09/src/features/jobs/components/dashboard-job-info/index.ts: -------------------------------------------------------------------------------- 1 | export * from './dashboard-job-info'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-09/src/features/jobs/components/jobs-list/index.ts: -------------------------------------------------------------------------------- 1 | export * from './jobs-list'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-09/src/features/jobs/components/public-job-info/index.ts: -------------------------------------------------------------------------------- 1 | export * from './public-job-info'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-09/src/features/jobs/index.ts: -------------------------------------------------------------------------------- 1 | // api: 2 | export * from './api/get-job'; 3 | export * from './api/get-jobs'; 4 | 5 | // components: 6 | export * from './components/create-job-form'; 7 | export * from './components/dashboard-job-info'; 8 | export * from './components/jobs-list'; 9 | export * from './components/public-job-info'; 10 | 11 | // types: 12 | export * from './types'; 13 | -------------------------------------------------------------------------------- /code-stages/chapter-09/src/features/jobs/types/index.ts: -------------------------------------------------------------------------------- 1 | import { Entity } from '@/types'; 2 | 3 | export type Job = Entity & { 4 | organizationId: string; 5 | position: string; 6 | info: string; 7 | location: string; 8 | department: string; 9 | }; 10 | 11 | export type CreateJobData = Pick< 12 | Job, 13 | 'position' | 'department' | 'location' | 'info' 14 | >; 15 | -------------------------------------------------------------------------------- /code-stages/chapter-09/src/features/organizations/components/organization-info/index.ts: -------------------------------------------------------------------------------- 1 | export * from './organization-info'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-09/src/features/organizations/index.ts: -------------------------------------------------------------------------------- 1 | // api: 2 | export * from './api/get-organization'; 3 | 4 | // components: 5 | export * from './components/organization-info'; 6 | 7 | // types: 8 | export * from './types'; 9 | -------------------------------------------------------------------------------- /code-stages/chapter-09/src/features/organizations/types/index.ts: -------------------------------------------------------------------------------- 1 | import { Entity } from '@/types'; 2 | 3 | export type Organization = Entity & { 4 | adminId: string; 5 | name: string; 6 | email: string; 7 | phone: string; 8 | info: string; 9 | }; 10 | -------------------------------------------------------------------------------- /code-stages/chapter-09/src/lib/react-query.ts: -------------------------------------------------------------------------------- 1 | import { QueryClient } from '@tanstack/react-query'; 2 | 3 | export const queryClient = new QueryClient({ 4 | defaultOptions: { 5 | queries: { 6 | retry: false, 7 | refetchOnWindowFocus: false, 8 | useErrorBoundary: true, 9 | }, 10 | }, 11 | }); 12 | -------------------------------------------------------------------------------- /code-stages/chapter-09/src/pages/404.tsx: -------------------------------------------------------------------------------- 1 | import { Center } from '@chakra-ui/react'; 2 | 3 | import { Link } from '@/components/link'; 4 | import { NotFound } from '@/components/not-found'; 5 | 6 | const NotFoundPage = () => { 7 | return ( 8 | <> 9 | 10 |
11 | Home 12 |
13 | 14 | ); 15 | }; 16 | 17 | export default NotFoundPage; 18 | -------------------------------------------------------------------------------- /code-stages/chapter-09/src/stores/notifications/index.ts: -------------------------------------------------------------------------------- 1 | export * from './notifications'; 2 | -------------------------------------------------------------------------------- /code-stages/chapter-09/src/testing/mocks/browser.ts: -------------------------------------------------------------------------------- 1 | import { setupWorker } from 'msw'; 2 | 3 | import { handlers } from './handlers'; 4 | 5 | export const worker = setupWorker(...handlers); 6 | -------------------------------------------------------------------------------- /code-stages/chapter-09/src/testing/mocks/index.ts: -------------------------------------------------------------------------------- 1 | export * from './handlers'; 2 | 3 | export * from './db'; 4 | -------------------------------------------------------------------------------- /code-stages/chapter-09/src/testing/mocks/initialize.ts: -------------------------------------------------------------------------------- 1 | import { IS_SERVER } from '@/config/constants'; 2 | 3 | import { seedDb } from './seed-db'; 4 | 5 | const initializeMocks = () => { 6 | if (IS_SERVER) { 7 | const { server } = require('./server'); 8 | server.listen(); 9 | } else { 10 | const { worker } = require('./browser'); 11 | worker.start(); 12 | } 13 | seedDb(); 14 | }; 15 | 16 | initializeMocks(); 17 | -------------------------------------------------------------------------------- /code-stages/chapter-09/src/testing/mocks/seed-db.ts: -------------------------------------------------------------------------------- 1 | import { testData } from '../test-data'; 2 | 3 | import { db } from './db'; 4 | 5 | export const seedDb = () => { 6 | const userCount = db.user.count(); 7 | 8 | if (userCount > 0) return; 9 | 10 | testData.users.forEach((user) => db.user.create(user)); 11 | 12 | testData.organizations.forEach((organization) => 13 | db.organization.create(organization) 14 | ); 15 | 16 | testData.jobs.forEach((job) => db.job.create(job)); 17 | }; 18 | -------------------------------------------------------------------------------- /code-stages/chapter-09/src/testing/mocks/server.ts: -------------------------------------------------------------------------------- 1 | import { setupServer } from 'msw/node'; 2 | 3 | import { handlers } from './handlers'; 4 | 5 | export const server = setupServer(...handlers); 6 | -------------------------------------------------------------------------------- /code-stages/chapter-09/src/types/index.ts: -------------------------------------------------------------------------------- 1 | export type Entity = { 2 | id: string; 3 | createdAt: number; 4 | }; 5 | -------------------------------------------------------------------------------- /code-stages/chapter-09/src/utils/format.ts: -------------------------------------------------------------------------------- 1 | export const formatDate = (date: number | string) => { 2 | return new Date(date).toLocaleDateString('en-US', { 3 | month: 'long', 4 | year: 'numeric', 5 | day: 'numeric', 6 | }); 7 | }; 8 | -------------------------------------------------------------------------------- /code-stages/chapter-09/src/utils/uid.ts: -------------------------------------------------------------------------------- 1 | // https://gist.github.com/gordonbrander/2230317?permalink_comment_id=3443509#gistcomment-3443509 2 | export const uid = () => { 3 | return ( 4 | performance.now().toString(36) + 5 | Math.random().toString(36) 6 | ).replace(/\./g, ''); 7 | }; 8 | -------------------------------------------------------------------------------- /code-stages/chapter-09/vercel.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 2, 3 | "github": { 4 | "enabled": false 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /lint-staged.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | '*.{ts,tsx}': [ 3 | 'npm run lint', 4 | "bash -c 'npm run types:check'", 5 | 'npm run format:check', 6 | ], 7 | }; 8 | -------------------------------------------------------------------------------- /next-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | 4 | // NOTE: This file should not be edited 5 | // see https://nextjs.org/docs/basic-features/typescript for more information. 6 | -------------------------------------------------------------------------------- /next.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | module.exports = { 3 | reactStrictMode: true, 4 | experimental: { 5 | esmExternals: false, 6 | }, 7 | }; 8 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/React-Application-Architecture-for-Production/40cd19895fa025e7c48127f187035ec451874061/public/favicon.ico -------------------------------------------------------------------------------- /scripts/clear-stage.js: -------------------------------------------------------------------------------- 1 | const { clearCurrent } = require('./utils'); 2 | 3 | async function clearStage() { 4 | await clearCurrent(); 5 | 6 | console.log('Success: stage cleared!'); 7 | } 8 | 9 | clearStage(); 10 | --------------------------------------------------------------------------------