Skip to content

Commit

Permalink
3 / Plugins
Browse files Browse the repository at this point in the history
  • Loading branch information
cyp3rius committed Oct 23, 2024
1 parent 6cebadf commit cc11af0
Show file tree
Hide file tree
Showing 38 changed files with 11,611 additions and 1 deletion.
Binary file modified .tmp/data.db
Binary file not shown.
7 changes: 6 additions & 1 deletion config/plugins.ts
Original file line number Diff line number Diff line change
@@ -1 +1,6 @@
export default () => ({});
export default () => ({
'booking-calendar': {
enabled: true,
resolve: 'src/plugins/booking-calendar',
},
});
16 changes: 16 additions & 0 deletions src/plugins/booking-calendar/.editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
root = true

[*]
indent_style = space
indent_size = 2
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true

[{package.json,*.yml}]
indent_style = space
indent_size = 2

[*.md]
trim_trailing_whitespace = false
1 change: 1 addition & 0 deletions src/plugins/booking-calendar/.eslintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
dist
138 changes: 138 additions & 0 deletions src/plugins/booking-calendar/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

############################
# OS X
############################

.DS_Store
.AppleDouble
.LSOverride
Icon
.Spotlight-V100
.Trashes
._*


############################
# Linux
############################

*~


############################
# Windows
############################

Thumbs.db
ehthumbs.db
Desktop.ini
$RECYCLE.BIN/
*.cab
*.msi
*.msm
*.msp


############################
# Packages
############################

*.7z
*.csv
*.dat
*.dmg
*.gz
*.iso
*.jar
*.rar
*.tar
*.zip
*.com
*.class
*.dll
*.exe
*.o
*.seed
*.so
*.swo
*.swp
*.swn
*.swm
*.out
*.pid


############################
# Logs and databases
############################

.tmp
*.log
*.sql
*.sqlite
*.sqlite3


############################
# Misc.
############################

*#
ssl
.idea
nbproject
.tsbuildinfo
.eslintcache
.env


############################
# Strapi
############################

public/uploads/*
!public/uploads/.gitkeep


############################
# Build
############################

dist
build


############################
# Node.js
############################

lib-cov
lcov.info
pids
logs
results
node_modules
.node_history


############################
# Package managers
############################

.yarn/*
!.yarn/cache
!.yarn/unplugged
!.yarn/patches
!.yarn/releases
!.yarn/sdks
!.yarn/versions
.pnp.*
yarn-error.log


############################
# Tests
############################

coverage
2 changes: 2 additions & 0 deletions src/plugins/booking-calendar/.prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
dist
coverage
7 changes: 7 additions & 0 deletions src/plugins/booking-calendar/.prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"endOfLine": "lf",
"tabWidth": 2,
"printWidth": 100,
"singleQuote": true,
"trailingComma": "es5"
}
3 changes: 3 additions & 0 deletions src/plugins/booking-calendar/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# booking-calendar

Booking Calendar
2 changes: 2 additions & 0 deletions src/plugins/booking-calendar/admin/custom.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
declare module '@strapi/design-system/*';
declare module '@strapi/design-system';
19 changes: 19 additions & 0 deletions src/plugins/booking-calendar/admin/src/components/Initializer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { useEffect, useRef } from 'react';

import { PLUGIN_ID } from '../pluginId';

type InitializerProps = {
setPlugin: (id: string) => void;
};

const Initializer = ({ setPlugin }: InitializerProps) => {
const ref = useRef(setPlugin);

useEffect(() => {
ref.current(PLUGIN_ID);
}, []);

return null;
};

export { Initializer };
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { PuzzlePiece } from '@strapi/icons';

const PluginIcon = () => <PuzzlePiece />;

export { PluginIcon };
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import { useState, useEffect } from "react"
import { Data, UID } from "@strapi/strapi";
import { Box, Flex, Typography } from '@strapi/design-system';

import { useIntl } from "react-intl";
import { Calendar, DateObject } from "react-multi-date-picker";
import { useLocation } from "react-router-dom";

import useApi from "../../hooks/useApi";
import { getTranslation } from "../../utils/getTranslation";

type ContentManagerType = 'single-types' | 'collection-types';

const CONTENT_MANAGER_PATH_PATTERN = /.*\/(?<type>[a-zA-Z-]+)\/(?<uid>[a-z0-9-_]+::[a-z0-9-_]+\.[a-z0-9-_]+)\/?(?<documentId>.{24})/;

type ContentManagerPathProps = {
type: ContentManagerType;
uid: UID.ContentType;
documentId: Data.DocumentID;
};

const BookingCalendar = () => {
const location = useLocation();
const { formatMessage } = useIntl();
const api = useApi();
const [value, setValue] = useState([]);

const groups: ContentManagerPathProps = new RegExp(CONTENT_MANAGER_PATH_PATTERN, "gm")
.exec(location.pathname)?.groups as ContentManagerPathProps;

const { uid, documentId } = groups ?? {};

if (!documentId || !(uid === 'api::car.car')) {
return null;
}

useEffect(() => {
const fetchAPI = async (id: string) => {
const bookings = await api.getBookingsByCar(id);
const ranges = bookings?.data?.results?.map((booking: any) => {
// Mapping the bookings to ranges
const from = new DateObject(booking.from);
const to = new DateObject(booking.to);

return [from, to];
}).reduce((acc: Array<Array<DateObject>>, curr: Array<DateObject>) => {
// Join the ranges which got return and next take in a same day
const prev = acc.length ? acc[acc.length - 1] : null;
if (prev && (prev[1].day === curr[0].day)) {
acc.pop();

return [...(acc ?? []), [prev[0], curr[1]]];
}

return [...(acc ?? []), curr];
}, []);

setValue(ranges);
};

if (documentId) {
fetchAPI(documentId);
}
}, [documentId]);

return (<Box width="100%" marginTop={2}>
<Flex gap={2} direction="column" alignItems="flex-start">
<Typography as="h2" variant="sigma">{formatMessage({
id: getTranslation('injection.content-manager.booking-calendar.header')
})}</Typography>
<Flex width="100%" direction="column" alignItems="center" justifyContent="center">
<Calendar
value={value}
shadow={false}
highlightToday={false}
numberOfMonths={1}
weekStartDayIndex={1}
showOtherDays
readOnly
multiple
range />
</Flex>
</Flex>
</Box>);
};

export default BookingCalendar;
36 changes: 36 additions & 0 deletions src/plugins/booking-calendar/admin/src/hooks/useApi.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { useFetchClient } from '@strapi/strapi/admin';
import qs from 'qs';

const useApi = () => {
const fetchClient = useFetchClient();

const getBookingsByCar = async (id: string, locale?: string) => {
const relationsQuery = qs.stringify({
fields: ['from', 'to'],
locale: locale ?? 'en',
pageSize: 100,
}, {
encodeValuesOnly: true,
});

const relations = await fetchClient.get(`/content-manager/relations/api::car.car/${id}/bookings?${relationsQuery}`);
const bookingsIds = relations.data.results.map((relation: any) => relation.id);

const bookingsQuery = qs.stringify({
filters: {
id: {
$in: bookingsIds
}
},
fields: ['from', 'to'],
sort: 'from:asc',
}, {
encodeValuesOnly: true,
});

return fetchClient.get(`/content-manager/collection-types/api::booking.booking?${bookingsQuery}`);
};

return { getBookingsByCar }
};
export default useApi;
62 changes: 62 additions & 0 deletions src/plugins/booking-calendar/admin/src/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import { getTranslation } from './utils/getTranslation';
import { PLUGIN_ID } from './pluginId';
import { Initializer } from './components/Initializer';
import { PluginIcon } from './components/PluginIcon';
import BookingCalendar from './components/calendar';

export default {
register(app: any) {
app.addMenuLink({
to: `plugins/${PLUGIN_ID}`,
icon: PluginIcon,
intlLabel: {
id: `${PLUGIN_ID}.plugin.name`,
defaultMessage: PLUGIN_ID,
},
Component: async () => {
const { App } = await import('./pages/App');

return App;
},
});

app.registerPlugin({
id: PLUGIN_ID,
initializer: Initializer,
isReady: false,
name: PLUGIN_ID,
});
},

bootstrap(app: any) {
app.getPlugin('content-manager').injectComponent('editView', 'right-links', {
name: 'booking-calendar-view',
Component: () => (<BookingCalendar />),
});
},

async registerTrads(app: any) {
const { locales } = app;

const importedTranslations = await Promise.all(
(locales as string[]).map((locale) => {
return import(`./translations/${locale}.json`)
.then(({ default: data }) => ({ // The default keys generator does not work, fix to the following
data: Object.keys(data).reduce((acc, current) => ({
...acc,
[getTranslation(current)]: data[current],
}), {}),
locale,
}))
.catch(() => {
return {
data: {},
locale,
};
});
})
);

return importedTranslations;
},
};
Loading

0 comments on commit cc11af0

Please sign in to comment.