diff --git a/samples/react-soccer-highlights/src/index.ts b/samples/react-soccer-highlights/src/index.ts new file mode 100644 index 000000000..289f09830 --- /dev/null +++ b/samples/react-soccer-highlights/src/index.ts @@ -0,0 +1 @@ +// A file is required to be in the root of the /src directory by the TypeScript compiler diff --git a/samples/react-soccer-highlights/src/webparts/reactSpFx/ReactSpFxWebPart.manifest.json b/samples/react-soccer-highlights/src/webparts/reactSpFx/ReactSpFxWebPart.manifest.json new file mode 100644 index 000000000..196030a2e --- /dev/null +++ b/samples/react-soccer-highlights/src/webparts/reactSpFx/ReactSpFxWebPart.manifest.json @@ -0,0 +1,27 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/spfx/client-side-web-part-manifest.schema.json", + "id": "0d3e8554-de4b-4b8c-bf6c-71591ffb926a", + "alias": "ReactSpFxWebPart", + "componentType": "WebPart", + + // The "*" signifies that the version should be taken from the package.json + "version": "*", + "manifestVersion": 2, + + // If true, the component can only be installed on sites where Custom Script is allowed. + // Components that allow authors to embed arbitrary script code should set this to true. + // https://support.office.com/en-us/article/Turn-scripting-capabilities-on-or-off-1f2c515f-5d7e-448a-9fd7-835da935584f + "requiresCustomScript": false, + "supportedHosts": ["SharePointWebPart"], + + "preconfiguredEntries": [{ + "groupId": "5c03119e-3074-46fd-976b-c60198311f70", // Other + "group": { "default": "Entertainment" }, + "title": { "default": "Soccer Hightlights" }, + "description": { "default": "Soccer Hightlights Web Parts show latest hightlights from around the world." }, + "officeFabricIconFontName": "Soccer", + "properties": { + "tile": "Soocer Highlights" + } + }] +} diff --git a/samples/react-soccer-highlights/src/webparts/reactSpFx/ReactSpFxWebPart.ts b/samples/react-soccer-highlights/src/webparts/reactSpFx/ReactSpFxWebPart.ts new file mode 100644 index 000000000..0530259e4 --- /dev/null +++ b/samples/react-soccer-highlights/src/webparts/reactSpFx/ReactSpFxWebPart.ts @@ -0,0 +1,80 @@ +import * as React from 'react'; +import * as ReactDom from 'react-dom'; +import { Version } from '@microsoft/sp-core-library'; +import { + IPropertyPaneConfiguration, + PropertyPaneTextField, + PropertyPaneSlider, +} from '@microsoft/sp-property-pane'; +import { BaseClientSideWebPart } from '@microsoft/sp-webpart-base'; + + +import * as strings from 'ReactSpFxWebPartStrings'; +import ReactSpFx from './components/ReactSpFx'; +import { IReactSpFxProps } from './components/IReactSpFxProps'; +import { DisplayMode } from '@microsoft/sp-core-library'; + +export interface IReactSpFxWebPartProps { + title: string; + pageSize: number; + displayMode: DisplayMode; + updateProperty: (value: string) => void; +} + +export default class ReactSpFxWebPart extends BaseClientSideWebPart { + + public render(): void { + const element: React.ReactElement = React.createElement( + ReactSpFx, + { + title: this.properties.title, + displayMode: this.properties.displayMode, + pageSize: this.properties.pageSize, + updateProperty: (value: string) => {this.properties.title = value;}, + onConfigure: () => { + this.context.propertyPane.open(); + }, + } + ); + + ReactDom.render(element, this.domElement); + } + + protected onDispose(): void { + ReactDom.unmountComponentAtNode(this.domElement); + } + + protected get dataVersion(): Version { + return Version.parse('1.0'); + } + + protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration { + return { + pages: [ + { + header: { + description: strings.PropertyPaneDescription + }, + groups: [ + { + groupName: strings.BasicGroupName, + groupFields: [ + PropertyPaneTextField('title', { + label: strings.DescriptionFieldLabel + }), + PropertyPaneSlider('pageSize',{ + label:"Highlights Per Page", + min:1, + max:20, + value:2, + showValue:true, + step:1 + }) + ] + } + ] + } + ] + }; + } +} diff --git a/samples/react-soccer-highlights/src/webparts/reactSpFx/components/IReactSpFxProps.ts b/samples/react-soccer-highlights/src/webparts/reactSpFx/components/IReactSpFxProps.ts new file mode 100644 index 000000000..07f9e48e7 --- /dev/null +++ b/samples/react-soccer-highlights/src/webparts/reactSpFx/components/IReactSpFxProps.ts @@ -0,0 +1,57 @@ +import { DisplayMode } from '@microsoft/sp-core-library'; +import { Placeholder } from "@pnp/spfx-controls-react/lib/Placeholder"; + +export interface IReactSpFxProps { + title: string; + displayMode: DisplayMode; + pageSize: number; + updateProperty: (value: string) => void; + onConfigure: () => void; +} + +export interface IVidesList { + videos: IVideo[]; +} + +export interface IVideo { + title: string; + embed: string; +} + +export interface ISportsHighlightsState { + sportHighlightState: []; +} +export interface ISportsHighlightPagingState { + currentPage: number; + indexOfLastHighlight: number; + indexOfFirstHighlight: number; + highLightsPerPage: number; +} + +export interface ISportsHightLightsProps { + pageSize:number; + sportsHighlights: []; +} + +export interface ISide { + name: string; +} +export interface ICompetition{ + name: string; + id: number; +} + +export interface ISportsHighlightProps { + title: string; + id: string; + date: Date; + side1: ISide; + side2: ISide; + competition: ICompetition; + thumbnail: string; + videos: IVideo[]; +} + + + + diff --git a/samples/react-soccer-highlights/src/webparts/reactSpFx/components/Pagination.tsx b/samples/react-soccer-highlights/src/webparts/reactSpFx/components/Pagination.tsx new file mode 100644 index 000000000..d793e4b62 --- /dev/null +++ b/samples/react-soccer-highlights/src/webparts/reactSpFx/components/Pagination.tsx @@ -0,0 +1,25 @@ +import React from "react"; + +const Pagination = ({ highLightsPerPage, totalHighlights, paginate }) => { + const pageNumbers = []; + + for (let i = 1; i <= Math.ceil(totalHighlights / highLightsPerPage); i++) { + pageNumbers.push(i); + } + + return ( + + ); +}; + +export default Pagination; diff --git a/samples/react-soccer-highlights/src/webparts/reactSpFx/components/ReactSpFx.module.scss b/samples/react-soccer-highlights/src/webparts/reactSpFx/components/ReactSpFx.module.scss new file mode 100644 index 000000000..fa33b1bd1 --- /dev/null +++ b/samples/react-soccer-highlights/src/webparts/reactSpFx/components/ReactSpFx.module.scss @@ -0,0 +1,85 @@ +@import '~office-ui-fabric-react/dist/sass/References.scss'; + +.reactSpFx { + .container { + max-width: 700px; + margin: 0px auto; + box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.2), 0 25px 50px 0 rgba(0, 0, 0, 0.1); + } + + .paginationDiv{ + border: 1px solid lightblue; + height: 100px; + padding: 10px 0; + display: flex; + justify-content: center; + } + + .row { + @include ms-Grid-row; + @include ms-fontColor-white; + background-color: $ms-color-themeDark; + padding: 20px; + } + + .column { + @include ms-Grid-col; + @include ms-lg10; + @include ms-xl8; + @include ms-xlPush2; + @include ms-lgPush1; + } + + .title { + font-size: large; + font-weight: bold; + font-style: normal; + @include ms-font-xl; + @include ms-fontColor-white; + } + + .subTitle { + @include ms-font-l; + @include ms-fontColor-white; + } + + .description { + @include ms-font-l; + @include ms-fontColor-white; + } + + .button { + // Our button + text-decoration: none; + height: 32px; + + // Primary Button + min-width: 80px; + background-color: $ms-color-themePrimary; + border-color: $ms-color-themePrimary; + color: $ms-color-white; + + // Basic Button + outline: transparent; + position: relative; + font-family: "Segoe UI WestEuropean","Segoe UI",-apple-system,BlinkMacSystemFont,Roboto,"Helvetica Neue",sans-serif; + -webkit-font-smoothing: antialiased; + font-size: $ms-font-size-m; + font-weight: $ms-font-weight-regular; + border-width: 0; + text-align: center; + cursor: pointer; + display: inline-block; + padding: 0 16px; + + .label { + font-weight: $ms-font-weight-semibold; + font-size: $ms-font-size-m; + height: 32px; + line-height: 32px; + margin: 0 4px; + vertical-align: top; + display: inline-block; + } + } +} diff --git a/samples/react-soccer-highlights/src/webparts/reactSpFx/components/ReactSpFx.module.scss.d.ts b/samples/react-soccer-highlights/src/webparts/reactSpFx/components/ReactSpFx.module.scss.d.ts new file mode 100644 index 000000000..5bff2ff08 --- /dev/null +++ b/samples/react-soccer-highlights/src/webparts/reactSpFx/components/ReactSpFx.module.scss.d.ts @@ -0,0 +1,17 @@ +// This file is automatically generated. +// Please do not change this file! +interface CssExports { + 'button': string; + 'column': string; + 'container': string; + 'description': string; + 'label': string; + 'ms-Grid': string; + 'paginationDiv': string; + 'reactSpFx': string; + 'row': string; + 'subTitle': string; + 'title': string; +} +export const cssExports: CssExports; +export default cssExports; diff --git a/samples/react-soccer-highlights/src/webparts/reactSpFx/components/ReactSpFx.tsx b/samples/react-soccer-highlights/src/webparts/reactSpFx/components/ReactSpFx.tsx new file mode 100644 index 000000000..941a2f552 --- /dev/null +++ b/samples/react-soccer-highlights/src/webparts/reactSpFx/components/ReactSpFx.tsx @@ -0,0 +1,66 @@ +import * as React from "react"; +import styles from "./ReactSpFx.module.scss"; +import { IReactSpFxProps, ISportsHighlightsState } from "./IReactSpFxProps"; +import { escape } from "@microsoft/sp-lodash-subset"; +import SportsHighlightsList from "./SportsHighlightsList"; +import { WebPartTitle } from "@pnp/spfx-controls-react/lib/WebPartTitle"; +import { Placeholder } from "@pnp/spfx-controls-react/lib/Placeholder"; + +import axios from "axios"; +import { setVirtualParent } from "office-ui-fabric-react"; +import SportsHighlights from "./SportsHighlightsList"; +import "bootstrap/dist/css/bootstrap.css"; + +export default class ReactSpFx extends React.Component< + IReactSpFxProps, + ISportsHighlightsState +> { + public constructor(props: IReactSpFxProps, state: ISportsHighlightsState) { + super(props); + this.state = { + sportHighlightState: [], + }; + } + + GetData = async () => { + const resp = await axios.get(`https://www.scorebat.com/video-api/v1/`); + const data = await resp.data; + this.setState({ sportHighlightState: data }); + }; + + async componentDidMount() { + this.GetData(); + } + + public render(): React.ReactElement { + const globalComponent = this; + console.log(this.props.pageSize); + return ( +
+ {!this.props.title && ( + + )} + {typeof this.props.title !== "undefined" && ( +
+ +
+ )} + + +
+ ); + } +} diff --git a/samples/react-soccer-highlights/src/webparts/reactSpFx/components/SportsHighlight.tsx b/samples/react-soccer-highlights/src/webparts/reactSpFx/components/SportsHighlight.tsx new file mode 100644 index 000000000..ac78bb9e7 --- /dev/null +++ b/samples/react-soccer-highlights/src/webparts/reactSpFx/components/SportsHighlight.tsx @@ -0,0 +1,45 @@ +import { videoProperties } from "office-ui-fabric-react"; +import React from "react"; +import ReactDOM from "react-dom"; +import { ISportsHighlightProps } from "./IReactSpFxProps"; +import SportsVideoList from "./SportsVideoList"; + +export default class SportsHighlight extends React.Component< + ISportsHighlightProps +> { + public render() { + const options = { + year: "2-digit", + month: "2-digit", + day: "2-digit", + hour: "2-digit", + minute: "2-digit", + }; + + const { + title, + id, + date, + side1, + side2, + competition, + thumbnail, + videos, + } = this.props; + return ( +
+
+
{title}
+
+ {competition.name} +
+
+ Date & Time: {new Date(date.toString()).toLocaleString("en-US", options)} +
+
{id}
+ +
+
+ ); + } +} diff --git a/samples/react-soccer-highlights/src/webparts/reactSpFx/components/SportsHighlightsList.tsx b/samples/react-soccer-highlights/src/webparts/reactSpFx/components/SportsHighlightsList.tsx new file mode 100644 index 000000000..a8f679866 --- /dev/null +++ b/samples/react-soccer-highlights/src/webparts/reactSpFx/components/SportsHighlightsList.tsx @@ -0,0 +1,94 @@ +import React from "react"; +import ReactDOM from "react-dom"; +import { + ISportsHightLightsProps, + ISportsHighlightPagingState, + IVideo, +} from "./IReactSpFxProps"; +import SportsHighlight from "./SportsHighlight"; +import Paging from "react-paging"; +import Pagination from "./Pagination"; + +export default class SportsHighlightsList extends React.Component< + ISportsHightLightsProps, + ISportsHighlightPagingState +> { + constructor(props) { + super(props); + this.state = { + currentPage: 1, + indexOfFirstHighlight: 1, + indexOfLastHighlight: 5, + highLightsPerPage: this.props.pageSize, + }; + } + + + paginate = (page) => { + console.clear(); + + const indexOfLastHighlight = + this.state.currentPage * this.state.highLightsPerPage; + const indexOfFirstHighlight = + indexOfLastHighlight - this.state.highLightsPerPage; + + this.setState({ + currentPage: page, + indexOfLastHighlight: indexOfLastHighlight, + indexOfFirstHighlight: indexOfFirstHighlight, + }); + }; + + //paginate = (pageNumber) => setCurrentPage(pageNumber); + + render(): React.ReactElement { + const sportsHighlights = this.props.sportsHighlights; + var { + currentPage, + indexOfFirstHighlight, + indexOfLastHighlight, + } = this.state; + + + if (typeof indexOfFirstHighlight === "undefined" || indexOfFirstHighlight == 0) + { + indexOfFirstHighlight=1 + } + + if ( + typeof indexOfFirstHighlight === "undefined" || + indexOfFirstHighlight == 0 + ) { + indexOfFirstHighlight = 1; + } + const CurrentsportsHighlights = this.props.sportsHighlights.slice( + indexOfFirstHighlight, + indexOfLastHighlight + ); + + console.clear(); + console.log("indexOfFirstHighlight:" + indexOfFirstHighlight); + console.log("indexOfLastHighlight : " + indexOfLastHighlight); + console.log("currentPage :" + currentPage); + console.log("Page Size :" + this.props.pageSize); + + //this.updateLastPage(currentPage); + + return ( +
+
+ +
+
+ {CurrentsportsHighlights.map((highLight, i) => ( + + ))} +
+
+ ); + } +} diff --git a/samples/react-soccer-highlights/src/webparts/reactSpFx/components/SportsVideo.tsx b/samples/react-soccer-highlights/src/webparts/reactSpFx/components/SportsVideo.tsx new file mode 100644 index 000000000..adec9d9ea --- /dev/null +++ b/samples/react-soccer-highlights/src/webparts/reactSpFx/components/SportsVideo.tsx @@ -0,0 +1,26 @@ +import React from "react"; +import ReactDOM from "react-dom"; +import { IVideo } from "./IReactSpFxProps"; +import ReactMarkdownWithHtml from "react-markdown/with-html"; +import { body } from "@pnp/pnpjs"; + +export default class SportsVideo extends React.Component { + public render() { + const { title, embed } = this.props; + return ( +
+
+ {title} +
+
+
+ ); + } +} diff --git a/samples/react-soccer-highlights/src/webparts/reactSpFx/components/SportsVideoList.tsx b/samples/react-soccer-highlights/src/webparts/reactSpFx/components/SportsVideoList.tsx new file mode 100644 index 000000000..360ab8bef --- /dev/null +++ b/samples/react-soccer-highlights/src/webparts/reactSpFx/components/SportsVideoList.tsx @@ -0,0 +1,22 @@ +import React from "react"; +import ReactDOM from "react-dom"; +import { IVidesList } from "./IReactSpFxProps"; +import SportsVideo from "./SportsVideo"; +import ReactMarkdownWithHtml from "react-markdown/with-html"; + +export default class SportsVideoList extends React.Component { + public render() { + const videos = this.props.videos; + return ( +
+ {this.props.videos.map((video, i) => ( + + ))} +
+ ); + } +} diff --git a/samples/react-soccer-highlights/src/webparts/reactSpFx/loc/en-us.js b/samples/react-soccer-highlights/src/webparts/reactSpFx/loc/en-us.js new file mode 100644 index 000000000..e8d676648 --- /dev/null +++ b/samples/react-soccer-highlights/src/webparts/reactSpFx/loc/en-us.js @@ -0,0 +1,7 @@ +define([], function() { + return { + "PropertyPaneDescription": "Title", + "BasicGroupName": "General", + "DescriptionFieldLabel": "Title" + } +}); diff --git a/samples/react-soccer-highlights/src/webparts/reactSpFx/loc/mystrings.d.ts b/samples/react-soccer-highlights/src/webparts/reactSpFx/loc/mystrings.d.ts new file mode 100644 index 000000000..b80d409e0 --- /dev/null +++ b/samples/react-soccer-highlights/src/webparts/reactSpFx/loc/mystrings.d.ts @@ -0,0 +1,10 @@ +declare interface IReactSpFxWebPartStrings { + PropertyPaneDescription: string; + BasicGroupName: string; + DescriptionFieldLabel: string; +} + +declare module 'ReactSpFxWebPartStrings' { + const strings: IReactSpFxWebPartStrings; + export = strings; +} diff --git a/samples/react-soccer-highlights/teams/0d3e8554-de4b-4b8c-bf6c-71591ffb926a_color.png b/samples/react-soccer-highlights/teams/0d3e8554-de4b-4b8c-bf6c-71591ffb926a_color.png new file mode 100644 index 000000000..48a2de133 Binary files /dev/null and b/samples/react-soccer-highlights/teams/0d3e8554-de4b-4b8c-bf6c-71591ffb926a_color.png differ diff --git a/samples/react-soccer-highlights/teams/0d3e8554-de4b-4b8c-bf6c-71591ffb926a_outline.png b/samples/react-soccer-highlights/teams/0d3e8554-de4b-4b8c-bf6c-71591ffb926a_outline.png new file mode 100644 index 000000000..dbfa92772 Binary files /dev/null and b/samples/react-soccer-highlights/teams/0d3e8554-de4b-4b8c-bf6c-71591ffb926a_outline.png differ