Before converting to hook

This commit is contained in:
Hugo Bernier 2020-04-17 02:59:43 -04:00
parent 092482c498
commit ce98f07dd9
27 changed files with 6157 additions and 3188 deletions

View File

@ -2,7 +2,7 @@
"@microsoft/generator-sharepoint": {
"isCreatingSolution": true,
"environment": "spo",
"version": "1.9.1",
"version": "1.10.0",
"libraryName": "react-calendar-feed",
"libraryId": "25653136-fc83-4abe-b9d2-a4ac041959d5",
"packageManager": "npm",

View File

@ -24,7 +24,7 @@ For more information about how this solution was built, including some design de
## Used SharePoint Framework Version
![SPFx v1.9.1](https://img.shields.io/badge/SPFx-1.9.1-green.svg)
![SPFx v1.10.0](https://img.shields.io/badge/SPFx-1.10.0-green.svg)
## Applies to
@ -40,9 +40,9 @@ Before you can use this web part example, you will need one of the following:
- A WordPress WP-FullCalendar feed
- An Exchange Public Calendar
It is important that all feeds do not require authentication. Also, make sure that your calendar includes upcoming events, as the web part will filter out evens that are earlier than today's date.
This web part only supports anonymous external feeds. Also, make sure that your calendar includes upcoming events, as the web part will filter out evens that are earlier than today's date.
If your feed supports filtering by dates, you can specify **{s}** in the URL where the start date should be inserted, and the web part will automatically replace the **{s}** placeholder with today's date. Similarly, you can specify **{e}** in the URL where you wish the end date to be inserted, and the web part will automatically replace the placeholder for the end date, as determined by the date range you select.
If your feed supports filtering by dates, you can specify `{s}` in the URL where the start date should be inserted, and the web part will automatically replace the `{s}` placeholder with today's date. Similarly, you can specify `{e}` in the URL where you wish the end date to be inserted, and the web part will automatically replace the placeholder for the end date, as determined by the date range you select.
## Solution
@ -59,6 +59,7 @@ Version|Date|Comments
3.0|November 9, 2018|Converted to SPFx 1.7; Added SharePoint Calendar feed
4.0|January 16, 2019|Converted to SPFx 1.7.1; Removed NPM libraries associated with issue #708.
5.0|August 17, 2019|Converted to SPFx 1.9.1; Refreshed carousel code; Addresses #735, #909. Also added **Convert from UTC** option to handle feeds which do not provide time zone information.
5.1|April 16, 2020|Converted to SPFx 1.10.0
## Disclaimer

View File

@ -3,7 +3,7 @@
"solution": {
"name": "react-calendar-feed-client-side-solution",
"id": "25653136-fc83-4abe-b9d2-a4ac041959d5",
"version": "1.0.0.0",
"version": "5.1.0.0",
"includeClientSideAssets": true
},
"paths": {

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
{
"name": "react-calendar-feed",
"version": "1.1.0",
"version": "5.1.0",
"private": true,
"main": "lib/index.js",
"engines": {
@ -12,10 +12,11 @@
"test": "gulp test"
},
"dependencies": {
"@microsoft/sp-core-library": "1.9.1",
"@microsoft/sp-lodash-subset": "1.9.1",
"@microsoft/sp-office-ui-fabric-core": "1.9.1",
"@microsoft/sp-webpart-base": "1.9.1",
"@microsoft/sp-core-library": "1.10.0",
"@microsoft/sp-lodash-subset": "1.10.0",
"@microsoft/sp-office-ui-fabric-core": "1.10.0",
"@microsoft/sp-property-pane": "1.10.0",
"@microsoft/sp-webpart-base": "1.10.0",
"@pnp/common": "^1.2.8",
"@pnp/logging": "^1.2.8",
"@pnp/odata": "^1.2.8",
@ -29,6 +30,7 @@
"feedparser": "^2.2.9",
"ical.js": "^1.3.0",
"ics-js": "^0.10.2",
"moment": "^2.24.0",
"office-ui-fabric-react": "6.189.2",
"react": "16.8.5",
"react-dom": "16.8.5",
@ -41,10 +43,11 @@
},
"devDependencies": {
"@microsoft/rush-stack-compiler-2.9": "0.7.16",
"@microsoft/sp-build-web": "1.9.1",
"@microsoft/sp-module-interfaces": "1.9.1",
"@microsoft/sp-tslint-rules": "1.9.1",
"@microsoft/sp-webpart-workbench": "1.9.1",
"@microsoft/rush-stack-compiler-3.3": "0.3.5",
"@microsoft/sp-build-web": "1.10.0",
"@microsoft/sp-module-interfaces": "1.10.0",
"@microsoft/sp-tslint-rules": "1.10.0",
"@microsoft/sp-webpart-workbench": "1.10.0",
"@types/chai": "3.4.34",
"@types/mocha": "2.2.38",
"ajv": "~5.2.2",

View File

@ -2,7 +2,8 @@ import * as moment from "moment";
import { css } from "office-ui-fabric-react/lib/Utilities";
import * as React from "react";
import styles from "./DateBox.module.scss";
import { DateBoxSize, IDateBoxProps, IDateBoxState } from "./DateBox.types";
import { DateBoxSize, IDateBoxProps } from ".";
import { IDateBoxState } from "./IDateBoxState";
/**
* Shows a date in a SharePoint-looking date

View File

@ -1,15 +0,0 @@
export interface IDateBoxProps {
startDate: Date;
endDate: Date;
className?: string;
size: DateBoxSize;
}
export interface IDateBoxState {
// you just proved advertising works!
}
export enum DateBoxSize {
Small,
Medium
}

View File

@ -0,0 +1,4 @@
export enum DateBoxSize {
Small,
Medium
}

View File

@ -0,0 +1,9 @@
import { DateBoxSize } from "./DateBoxSize";
export interface IDateBoxProps {
startDate: Date;
endDate: Date;
className?: string;
size: DateBoxSize;
}

View File

@ -0,0 +1,3 @@
export interface IDateBoxState {
// you just proved advertising works!
}

View File

@ -1,2 +1,3 @@
export * from "./DateBox";
export * from "./DateBox.types";
export * from "./IDateBoxProps";
export * from "./DateBoxSize";

View File

@ -4,7 +4,8 @@ import * as ICS from "ics-js";
import * as moment from "moment";
import { ActionButton, DocumentCard, DocumentCardType, FocusZone, css } from "office-ui-fabric-react";
import * as React from "react";
import { IEventCardProps, IEventCardState } from ".";
import { IEventCardProps } from ".";
import { IEventCardState } from "./IEventCardState";
import { DateBox, DateBoxSize } from "../DateBox";
import styles from "./EventCard.module.scss";
import { Text } from "@microsoft/sp-core-library";
@ -88,7 +89,7 @@ export class EventCard extends React.Component<IEventCardProps, IEventCardState>
// category,
// location
} = this.props.event;
const eventDate: moment.Moment = moment.utc(start);
const eventDate: moment.Moment = moment(start);
const dateString: string = allDay ? eventDate.format(strings.AllDayDateFormat) : eventDate.format(strings.LocalizedTimeFormat);
return (
<div>

View File

@ -1,9 +1,7 @@
import { ICalendarEvent } from "../../../shared/services/CalendarService";
import { ICalendarEvent } from "../../services/CalendarService";
export interface IEventCardProps {
isEditMode: boolean;
event: ICalendarEvent;
isNarrow: boolean;
}
export interface IEventCardState {}

View File

@ -0,0 +1,3 @@
export interface IEventCardState {
// Not in use
}

View File

@ -1,2 +1,2 @@
export * from "./EventCard";
export * from "./EventCard.types";
export * from "./IEventCardProps";

View File

@ -5,5 +5,3 @@ export interface IPagingProps {
showPageNum: boolean;
onPageUpdate: (pageNumber: number) => void;
}
export interface IPagingState { }

View File

@ -0,0 +1,3 @@
export interface IPagingState {
// Not in use
}

View File

@ -2,7 +2,8 @@ import { ActionButton, IButtonProps } from "office-ui-fabric-react/lib/Button";
import { Icon } from "office-ui-fabric-react/lib/Icon";
import { css } from "office-ui-fabric-react/lib/Utilities";
import * as React from "react";
import { IPagingProps, IPagingState } from ".";
import { IPagingProps } from ".";
import { IPagingState } from "./IPagingState";
import styles from "./Paging.module.scss";
import * as strings from "CalendarFeedSummaryWebPartStrings";

View File

@ -1,2 +1,2 @@
export * from "./Paging";
export * from "./Paging.types";
export * from "./IPagingProps";

View File

@ -1,5 +1,4 @@
@import '~office-ui-fabric-react/dist/sass/References.scss';
@import "~office-ui-fabric-react/dist/sass/References.scss";
:export {
centerPadding: 50px;
}
@ -20,14 +19,6 @@
opacity: 0;
}
.sliderButtonRight {
right: 10px;
}
.sliderButtonLeft {
left: 10px;
}
&:hover .sliderButtons {
opacity: 1;
@ -45,8 +36,8 @@
}
.indexButton {
font-size: 17px;
font-weight: 300;
font-size: 28px;
font-weight: 400;
height: 40px;
padding: 0;
border: 0;
@ -67,6 +58,8 @@
&:hover {
color: $ms-color-white;
background-color: $ms-color-black;
opacity: 0.6;
}
&:active {
@ -74,6 +67,39 @@
}
}
.carouselDotsContainer {
.carouselDot {
display: inline-block;
background-color: $ms-color-black;
height: 4px;
width: 4px;
opacity: 0.5;
border: 2px solid $ms-color-black;
border-radius: 4px;
cursor: pointer;
opacity: 0.25;
outline: 0;
&:hover {
opacity: 1;
}
}
}
:global(.slick-active) {
.carouselDotsContainer {
.carouselDot {
background-color: "[theme:themeDark, default: #005a9e]";
opacity: 0.75;
border-color: "[theme:themeDark, default: #005a9e]";
&:hover {
background-color: "[theme:themeDarker, default: #004578]";
}
}
}
}
.indexButton:global(.ms-Button-flexContainer):hover:global(.ms-Icon),
.indexButton:global(.ms-Icon:hover),
.indexButton:hover:global(.ms-Icon) {

View File

@ -1,11 +1,9 @@
import { css } from '@uifabric/utilities/lib/css';
import { IconButton } from 'office-ui-fabric-react/lib/Button';
import * as React from 'react';
// import * as slick from 'slick-carousel';
import Slider from 'react-slick';
import { IFilmstripLayoutProps, IFilmstripLayoutState } from "./FilmstripLayout.types";
import { IFilmstripLayoutProps } from "./IFilmstripLayoutProps";
import { IFilmstripLayoutState} from "./IFilmstripLayoutState";
import { SPComponentLoader } from '@microsoft/sp-loader';
import styles from "./FilmstripLayout.module.scss";
@ -20,14 +18,32 @@ export class FilmstripLayout extends React.Component<
// the slick slider used in normal views
private _slider: Slider;
private _container: HTMLDivElement;
/**
*
*/
constructor(props: IFilmstripLayoutProps) {
super(props);
SPComponentLoader.loadCss('https://cdnjs.cloudflare.com/ajax/libs/slick-carousel/1.6.0/slick.min.css');
SPComponentLoader.loadCss('https://cdnjs.cloudflare.com/ajax/libs/slick-carousel/1.6.0/slick-theme.min.css');
this.state = {
dimensions: undefined
};
SPComponentLoader.loadCss('https://cdnjs.cloudflare.com/ajax/libs/slick-carousel/1.8.1/slick.min.css');
SPComponentLoader.loadCss('https://cdnjs.cloudflare.com/ajax/libs/slick-carousel/1.8.1/slick-theme.min.css');
}
public componentDidMount(): void {
if (this._container) {
this.setState({
dimensions: {
width: this._container.offsetWidth,
height: this._container.offsetHeight,
},
});
}
}
/**
* Renders a slick switch, a slide for each child, and next/previous arrows
@ -35,15 +51,35 @@ export class FilmstripLayout extends React.Component<
public render(): React.ReactElement<IFilmstripLayoutProps> {
// slick seems to have an issue with having "infinite" mode set to true and having less items than the number of slides per page
// set infinite to true only if there are more than 3 children
var isInfinite: boolean = React.Children.count(this.props.children) > 3;
let numSlides: number = 3;
if (this.state.dimensions) {
if (this.state.dimensions.width > 927) {
numSlides = 4;
} else if (this.state.dimensions.width <= 695) {
numSlides = 2;
}
}
var isInfinite: boolean = React.Children.count(this.props.children) > numSlides;
var settings: any = {
accessibility: true,
arrows: false,
autoplaySpeed: 5000,
dots: true,
//dotsClass: css("slick-dots", styles.slickDots),
customPaging: (i:number)=> {
return (
<a>
<div role="button" className={styles.carouselDotsContainer} aria-label={`Carousel Dot ${i}`} data-is-focusable={true} tabIndex={0}>
<span className={styles.carouselDot} tabIndex={-1}></span>
</div>
</a>
);
},
infinite: isInfinite,
slidesToShow: 4,
slidesToScroll: 4,
slidesToShow: numSlides,
slidesToScroll: numSlides,
speed: 500,
centerPadding: styles.centerPadding,
pauseOnHover: true,
@ -51,60 +87,64 @@ export class FilmstripLayout extends React.Component<
useCSS: true,
rows: 1,
respondTo: "slider",
responsive: [
{
breakpoint: 499,
settings: {
slidesToShow: 1,
slidesToScroll: 1
}
},
{
breakpoint: 731,
settings: {
slidesToShow: 2,
slidesToScroll: 2
}
},
{
breakpoint: 963,
settings: {
slidesToShow: 3,
slidesToScroll: 3
}
},
{
breakpoint: 1028,
settings: {
slidesToShow: 4,
slidesToScroll: 4
}
}
]
// responsive: [
// // {
// // breakpoint: 1440,
// // settings: {
// // slidesToShow: 4,
// // slidesToScroll: 4,
// // infinite: isInfinite,
// // dots: true
// // }
// // },
// {
// breakpoint: 1024,
// settings: {
// slidesToShow: 3,
// slidesToScroll: 3,
// infinite: isInfinite,
// dots: true
// }
// },
// {
// // breakpoint: 754,
// breakpoint: 767,
// settings: {
// slidesToShow: 2,
// slidesToScroll: 2,
// infinite: isInfinite,
// dots: true
// }
// }
// ]
};
console.log("Dimensions", this.state.dimensions);
return (
<div>
<div className={css(styles.filmstripLayout, styles.filmStrip)} aria-label={this.props.ariaLabel}>
<Slider ref={c => (this._slider = c)} {...settings}>
WIDTH: {this.state.dimensions && this.state.dimensions.width}
<div className={css(styles.filmstripLayout, styles.filmStrip)} aria-label={this.props.ariaLabel} ref={(el: HTMLDivElement) => (this._container = el)}>
<Slider ref={(c:Slider) => (this._slider = c)} {...settings}>
{this.props.children}
</Slider>
<div
className={css(styles.indexButtonContainer, styles.sliderButtons, styles.sliderButtonLeft)}
className={css(styles.indexButtonContainer, styles.sliderButtons)}
style={{ left: "10px" }}
onClick={() => this._slider.slickPrev()}
>
<IconButton
className={css(styles.indexButton, styles.leftPositioned)}
iconProps={{ iconName: "ChevronLeft" }}
iconProps={{ iconName: "ChevronLeft", styles: {root: { fontSize:'28px', fontWeight:'400'} }}}
/>
</div>
<div
className={css(styles.indexButtonContainer, styles.sliderButtons, styles.sliderButtonRight)}
className={css(styles.indexButtonContainer, styles.sliderButtons)}
style={{ right: "10px" }}
onClick={() => this._slider.slickNext()}
>
<IconButton
className={css(styles.indexButton, styles.rightPositioned)}
iconProps={{ iconName: "ChevronRight" }}
iconProps={{ iconName: "ChevronRight", styles: {root: { fontSize:'28px', fontWeight:'400'} }}}
/>
</div>
</div>

View File

@ -1,5 +1,3 @@
export interface IFilmstripLayoutProps {
ariaLabel?: string;
}
export interface IFilmstripLayoutState { }

View File

@ -0,0 +1,7 @@
export interface IFilmstripLayoutState {
dimensions: {
width: any;
height: any;
};
}

View File

@ -1,2 +1,2 @@
export * from "./FilmstripLayout";
export * from "./FilmstripLayout.types";
export * from "./IFilmstripLayoutProps";

View File

@ -151,7 +151,7 @@ export class MockCalendarService extends BaseCalendarService implements ICalenda
return new Promise<ICalendarEvent[]>((resolve: any) => {
setTimeout(() => {
resolve(this.filterEventRange(sampleEvents));
}, 1000);
}, 100);
});
}
}

View File

@ -9,12 +9,13 @@
}
.webPartChrome {
display: -ms-flexbox;
display: flex;
-ms-flex-align: stretch;
align-items: stretch;
-ms-flex-direction: column;
flex-direction: column;
// display: -ms-flexbox;
// display: flex;
// -ms-flex-align: stretch;
// align-items: stretch;
// -ms-flex-direction: column;
// flex-direction: column;
color: inherit;
}
.headerSmMargin {

View File

@ -1,4 +1,5 @@
{
"extends": "./node_modules/@microsoft/rush-stack-compiler-3.3/includes/tsconfig-web.json",
"compilerOptions": {
"inlineSources": false,
"strictNullChecks": false,