Merge pull request #2066 from siddharth-vaghasia/react-emojiwebpart
React emojiwebpart
|
@ -0,0 +1,33 @@
|
|||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
|
||||
# Dependency directories
|
||||
node_modules
|
||||
|
||||
# Build generated files
|
||||
dist
|
||||
lib
|
||||
release
|
||||
solution
|
||||
temp
|
||||
*.sppkg
|
||||
|
||||
# Coverage directory used by tools like istanbul
|
||||
coverage
|
||||
|
||||
# OSX
|
||||
.DS_Store
|
||||
|
||||
# Visual Studio files
|
||||
.ntvs_analysis.dat
|
||||
.vs
|
||||
bin
|
||||
obj
|
||||
|
||||
# Resx Generated Code
|
||||
*.resx.ts
|
||||
|
||||
# Styles Generated Code
|
||||
*.scss.ts
|
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"@microsoft/generator-sharepoint": {
|
||||
"isCreatingSolution": true,
|
||||
"environment": "spo",
|
||||
"version": "1.12.1",
|
||||
"libraryName": "react-emoji-reaction-rating",
|
||||
"libraryId": "fe292bb9-a5c2-40b4-b90b-61e8510c3c09",
|
||||
"packageManager": "npm",
|
||||
"isDomainIsolated": false,
|
||||
"componentType": "webpart"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,109 @@
|
|||
# Emoji Ratings
|
||||
|
||||
## Summary
|
||||
|
||||
This is sample web part which can be used to take emoji based reaction or feedback for particular news/article/posts.
|
||||
We all know every organizations would be using SharePoint news features for company's internal communications from HR to IT updates and some time annoucements. News created in SharePoint are created as Pages in library. Idea behind this web part is to take employee/user's feedback as emoji reactions on particular news. This web part can also be used on wiki articles or blog posts to take similar reactions. Web part uses concept of 1 to 5 star based rating system(configurable), you can decide low to high based on your preference.
|
||||
|
||||
Ideally, we can do some automation using PnP Powershell and PowerAutomate (trigger when item is created ) to add this web part to any every news that is published.
|
||||
|
||||
If you wish to directly use the package in your tenant here is [link](https://github.com/siddharth-vaghasia/public-docs/blob/master/react-emoji-reaction-rating.sppkg) to download.
|
||||
|
||||
|
||||
![Web part in Action](./assets/EmojiWPinAction.gif)
|
||||
|
||||
## Features
|
||||
|
||||
* Configurable header text, rating text, and images
|
||||
* We can choose to show from minimum one rating to max 5 rating images and text
|
||||
* Option to show total count of particular rating count as badge
|
||||
* Option to show and capture comments from user when submitting feedback
|
||||
* Display current user's rating selection with highlighted background
|
||||
* Allow user to change rating(update rating)
|
||||
* Stores ratings in SharePoint List
|
||||
* Option to create list on the fly and choose list to store the ratings
|
||||
* Option for admin to choose background color
|
||||
|
||||
## Technical Notes
|
||||
|
||||
* User's rating data would be stored in SP List, below are list of columns and its relevance
|
||||
|
||||
1. `Title`: To store user's display name (not required though)
|
||||
2. `Page Name`: To store page on which rating is given by particular user, this will have absolute url of page
|
||||
3. `User`: To store user who has given feedback for particular page/news where web part is added
|
||||
4. `Comment`: To store comment provided by user while submitting reaction.
|
||||
5. Then there are 5 columns `Rating1`, `Rating2`, `Rating3`, `Rating4`, `Rating5` which will store the rating text configured by admin in web part... Only one of this 5 columns would be populated for single item in list, which is what user has selected as part of giving reaction
|
||||
|
||||
* Below is how you can configure emoji's text and its image url
|
||||
![Web part in Action](./assets/EmojisConfigurations.png)
|
||||
|
||||
I have added default emoji's images which can be used and uploaded to SharePoint library in the assets folder of this solution.
|
||||
|
||||
|
||||
## Compatibility
|
||||
|
||||
![SPFx 1.11](https://img.shields.io/badge/SPFx-1.11.0-green.svg)
|
||||
![Node.js LTS 10.x](https://img.shields.io/badge/Node.js-LTS%2010.x-green.svg)
|
||||
![Compatible with SharePoint Online](https://img.shields.io/badge/SharePoint%20Online-Compatible-green.svg)
|
||||
![Does not work with SharePoint 2019](https://img.shields.io/badge/SharePoint%20Server%202019-Incompatible-red.svg "SharePoint Server 2019 requires SPFx 1.4.1 or lower")
|
||||
![Does not work with SharePoint 2016 (Feature Pack 2)](https://img.shields.io/badge/SharePoint%20Server%202016%20(Feature%20Pack%202)-Incompatible-red.svg "SharePoint Server 2016 Feature Pack 2 requires SPFx 1.1")
|
||||
![Teams Incompatible](https://img.shields.io/badge/Teams-Incompatible-lightgrey.svg)
|
||||
![Local Workbench Incompatible](https://img.shields.io/badge/Local%20Workbench-Incompatible-red.svg "This solution requires access to a SharePoint list")
|
||||
![Hosted Workbench Compatible](https://img.shields.io/badge/Hosted%20Workbench-Compatible-green.svg)
|
||||
|
||||
|
||||
## Applies to
|
||||
|
||||
- [SharePoint Framework](https://aka.ms/spfx)
|
||||
- [Microsoft 365 tenant](https://docs.microsoft.com/en-us/sharepoint/dev/spfx/set-up-your-developer-tenant)
|
||||
|
||||
> Get your own free development tenant by subscribing to [Microsoft 365 developer program](http://aka.ms/o365devprogram)
|
||||
|
||||
## Prerequisites
|
||||
|
||||
* SharePoint Online tenant
|
||||
* Permission to deploy package to Tenant or SharePoint Site collection app catalog
|
||||
|
||||
## Solution
|
||||
|
||||
Solution|Author(s)
|
||||
--------|---------
|
||||
react-emoji-ratings | [Siddharth Vaghasia](https://github.com/siddharth-vaghasia) ([@siddh_me](https://twitter.com/siddh_me))
|
||||
|
||||
## Version history
|
||||
|
||||
Version|Date|Comments
|
||||
-------|----|--------
|
||||
1.0|Sep 04, 2021|Initial release
|
||||
|
||||
## Minimal Path to Awesome
|
||||
|
||||
- Clone this repository
|
||||
- Ensure that you are at the solution folder
|
||||
- in the command-line run:
|
||||
- `npm install`
|
||||
- `gulp serve`
|
||||
|
||||
## References
|
||||
|
||||
- [Getting started with SharePoint Framework](https://docs.microsoft.com/en-us/sharepoint/dev/spfx/set-up-your-developer-tenant)
|
||||
- [Building for Microsoft teams](https://docs.microsoft.com/en-us/sharepoint/dev/spfx/build-for-teams-overview)
|
||||
- [Publish SharePoint Framework applications to the Marketplace](https://docs.microsoft.com/en-us/sharepoint/dev/spfx/publish-to-marketplace-overview)
|
||||
- [Microsoft 365 Patterns and Practices](https://aka.ms/m365pnp) - Guidance, tooling, samples and open-source controls for your Microsoft 365 development
|
||||
|
||||
|
||||
## Disclaimer
|
||||
|
||||
**THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.**
|
||||
|
||||
## Help
|
||||
|
||||
We do not support samples, but we this community is always willing to help, and we want to improve these samples. We use GitHub to track issues, which makes it easy for community members to volunteer their time and help resolve issues.
|
||||
|
||||
If you encounter any issues while using this sample, [create a new issue](https://github.com/pnp/sp-dev-fx-webparts/issues/new?assignees=&labels=Needs%3A+Triage+%3Amag%3A%2Ctype%3Abug-suspected&template=bug-report.yml&sample=react-emoji-ratings&authors=@siddharth-vaghasia&title=react-emoji-ratings%20-%20).
|
||||
|
||||
For questions regarding this sample, [create a new question](https://github.com/pnp/sp-dev-fx-webparts/issues/new?assignees=&labels=Needs%3A+Triage+%3Amag%3A%2Ctype%3Abug-suspected&template=question.yml&sample=react-emoji-ratings&authors=@siddharth-vaghasia&title=react-emoji-ratings%20-%20).
|
||||
|
||||
Finally, if you have an idea for improvement, [make a suggestion](https://github.com/pnp/sp-dev-fx-webparts/issues/new?assignees=&labels=Needs%3A+Triage+%3Amag%3A%2Ctype%3Abug-suspected&template=suggestion.yml&sample=react-emoji-ratings&authors=@siddharth-vaghasia&title=react-emoji-ratings%20-%20).
|
||||
|
||||
<img src="https://telemetry.sharepointpnp.com/sp-dev-fx-webparts/samples/react-emoji-ratings" />
|
After Width: | Height: | Size: 2.1 MiB |
After Width: | Height: | Size: 41 KiB |
After Width: | Height: | Size: 5.6 KiB |
After Width: | Height: | Size: 5.5 KiB |
After Width: | Height: | Size: 5.5 KiB |
After Width: | Height: | Size: 5.5 KiB |
After Width: | Height: | Size: 5.4 KiB |
|
@ -0,0 +1,55 @@
|
|||
[
|
||||
{
|
||||
"name": "pnp-sp-dev-spfx-web-parts-react-emoji-ratings",
|
||||
"source": "pnp",
|
||||
"title": "Emoji Ratings",
|
||||
"shortDescription": "Take emoji-based reactions or feedback for a given news/article/post",
|
||||
"url": "https://github.com/pnp/sp-dev-fx-webparts/tree/main/samples/react-emoji-ratings",
|
||||
"longDescription": [
|
||||
"This is sample web part which can be used to take emoji based reaction or feedback for particular news/article/posts.",
|
||||
"We all know every organizations would be using SharePoint news features for company's internal communications from HR to IT updates and some time annoucements. News created in SharePoint are created as Pages in library. Idea behind this web part is to take employee/user's feedback as emoji reactions on particular news. This web part can also be used on wiki articles or blog posts to take similar reactions. Web part uses concept of 1 to 5 star based rating system(configurable), you can decide low to high based on your preference."
|
||||
],
|
||||
"creationDateTime": "2021-09-24",
|
||||
"updateDateTime": "2021-09-24",
|
||||
"products": [
|
||||
"SharePoint",
|
||||
"Office"
|
||||
],
|
||||
"metadata": [
|
||||
{
|
||||
"key": "CLIENT-SIDE-DEV",
|
||||
"value": "React"
|
||||
},
|
||||
{
|
||||
"key": "SPFX-VERSION",
|
||||
"value": "1.12.1"
|
||||
},
|
||||
{
|
||||
"key": "PNPCONTROLS",
|
||||
"value": "PropertyFieldCollectionData, PropertyFieldColorPicker, Placeholder"
|
||||
}
|
||||
],
|
||||
"thumbnails": [
|
||||
{
|
||||
"type": "image",
|
||||
"order": 100,
|
||||
"url": "https://github.com/pnp/sp-dev-fx-webparts/raw/main/samples/react-emoji-ratings/assets/EmojiWPinAction.gif",
|
||||
"alt": "Web part in action"
|
||||
}
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"gitHubAccount": "siddharth-vaghasia",
|
||||
"pictureUrl": "https://github.com/siddharth-vaghasia.png",
|
||||
"name": "Siddharth Vaghasia"
|
||||
}
|
||||
],
|
||||
"references": [
|
||||
{
|
||||
"name": "Build your first SharePoint client-side web part",
|
||||
"description": "Client-side web parts are client-side components that run in the context of a SharePoint page. Client-side web parts can be deployed to SharePoint environments that support the SharePoint Framework. You can also use modern JavaScript web frameworks, tools, and libraries to build them.",
|
||||
"url": "https://docs.microsoft.com/en-us/sharepoint/dev/spfx/web-parts/get-started/build-a-hello-world-web-part"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
|
@ -0,0 +1,20 @@
|
|||
{
|
||||
"$schema": "https://developer.microsoft.com/json-schemas/spfx-build/config.2.0.schema.json",
|
||||
"version": "2.0",
|
||||
"bundles": {
|
||||
"react-emoji-reaction-rating-web-part": {
|
||||
"components": [
|
||||
{
|
||||
"entrypoint": "./lib/webparts/reactEmojiReactionRating/ReactEmojiReactionRatingWebPart.js",
|
||||
"manifest": "./src/webparts/reactEmojiReactionRating/ReactEmojiReactionRatingWebPart.manifest.json"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"externals": {},
|
||||
"localizedResources": {
|
||||
"ReactEmojiReactionRatingWebPartStrings": "lib/webparts/reactEmojiReactionRating/loc/{locale}.js",
|
||||
"PropertyControlStrings": "node_modules/@pnp/spfx-property-controls/lib/loc/{locale}.js",
|
||||
"ControlStrings": "node_modules/@pnp/spfx-controls-react/lib/loc/{locale}.js"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"$schema": "https://developer.microsoft.com/json-schemas/spfx-build/copy-assets.schema.json",
|
||||
"deployCdnPath": "./release/assets/"
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"$schema": "https://developer.microsoft.com/json-schemas/spfx-build/deploy-azure-storage.schema.json",
|
||||
"workingDir": "./release/assets/",
|
||||
"account": "<!-- STORAGE ACCOUNT NAME -->",
|
||||
"container": "react-emoji-reaction-rating",
|
||||
"accessKey": "<!-- ACCESS KEY -->"
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
{
|
||||
"$schema": "https://developer.microsoft.com/json-schemas/spfx-build/package-solution.schema.json",
|
||||
"solution": {
|
||||
"name": "react-emoji-reaction-rating-client-side-solution",
|
||||
"id": "fe292bb9-a5c2-40b4-b90b-61e8510c3c09",
|
||||
"version": "1.0.0.0",
|
||||
"includeClientSideAssets": true,
|
||||
"isDomainIsolated": false,
|
||||
"developer": {
|
||||
"name": "",
|
||||
"websiteUrl": "",
|
||||
"privacyUrl": "",
|
||||
"termsOfUseUrl": "",
|
||||
"mpnId": ""
|
||||
}
|
||||
},
|
||||
"paths": {
|
||||
"zippedPackage": "solution/react-emoji-reaction-rating.sppkg"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"$schema": "https://developer.microsoft.com/json-schemas/core-build/serve.schema.json",
|
||||
"port": 4321,
|
||||
"https": true,
|
||||
"initialPage": "https://localhost:5432/workbench",
|
||||
"api": {
|
||||
"port": 5432,
|
||||
"entryPath": "node_modules/@microsoft/sp-webpart-workbench/lib/api/"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"$schema": "https://developer.microsoft.com/json-schemas/spfx-build/write-manifests.schema.json",
|
||||
"cdnBasePath": "<!-- PATH TO CDN -->"
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
'use strict';
|
||||
|
||||
const build = require('@microsoft/sp-build-web');
|
||||
|
||||
build.addSuppression(`Warning - [sass] The local CSS class 'ms-Grid' is not camelCase and will not be type-safe.`);
|
||||
|
||||
var getTasks = build.rig.getTasks;
|
||||
build.rig.getTasks = function () {
|
||||
var result = getTasks.call(build.rig);
|
||||
|
||||
result.set('serve', result.get('serve-deprecated'));
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
build.initialize(require('gulp'));
|
|
@ -0,0 +1,37 @@
|
|||
{
|
||||
"name": "react-emoji-reaction-rating",
|
||||
"version": "0.0.1",
|
||||
"private": true,
|
||||
"main": "lib/index.js",
|
||||
"scripts": {
|
||||
"build": "gulp bundle",
|
||||
"clean": "gulp clean",
|
||||
"test": "gulp test"
|
||||
},
|
||||
"dependencies": {
|
||||
"@material-ui/core": "^4.12.3",
|
||||
"@microsoft/sp-core-library": "1.12.1",
|
||||
"@microsoft/sp-lodash-subset": "1.12.1",
|
||||
"@microsoft/sp-office-ui-fabric-core": "1.12.1",
|
||||
"@microsoft/sp-property-pane": "1.12.1",
|
||||
"@microsoft/sp-webpart-base": "1.12.1",
|
||||
"@pnp/sp": "^2.8.0",
|
||||
"@pnp/spfx-controls-react": "3.3.0",
|
||||
"@pnp/spfx-property-controls": "3.2.0",
|
||||
"office-ui-fabric-react": "7.156.0",
|
||||
"react": "16.9.0",
|
||||
"react-dom": "16.9.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/react": "16.9.36",
|
||||
"@types/react-dom": "16.9.8",
|
||||
"@microsoft/sp-build-web": "1.12.1",
|
||||
"@microsoft/sp-tslint-rules": "1.12.1",
|
||||
"@microsoft/sp-module-interfaces": "1.12.1",
|
||||
"@microsoft/sp-webpart-workbench": "1.12.1",
|
||||
"@microsoft/rush-stack-compiler-3.7": "0.2.3",
|
||||
"gulp": "~4.0.2",
|
||||
"ajv": "~5.2.2",
|
||||
"@types/webpack-env": "1.13.1"
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
// A file is required to be in the root of the /src directory by the TypeScript compiler
|
|
@ -0,0 +1,38 @@
|
|||
{
|
||||
"$schema": "https://developer.microsoft.com/json-schemas/spfx/client-side-web-part-manifest.schema.json",
|
||||
"id": "0dbbad17-3a6b-44ed-8ebb-989a8dd906b5",
|
||||
"alias": "ReactEmojiReactionRatingWebPart",
|
||||
"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": "Other" },
|
||||
"title": { "default": "react-emoji-reaction-rating" },
|
||||
"description": { "default": "react-emoji-reaction-rating description" },
|
||||
"officeFabricIconFontName": "Page",
|
||||
"properties": {
|
||||
"propertyRatingText": "React emoji reaction rating web part!. How does you like this news/article? ",
|
||||
"propertyEmojisCollection":[
|
||||
{"Title":"Wow!","ImageUrl":"https://mypersorg.sharepoint.com/sites/PnPSearchDemo/EmojiLibrary/RatingImg1.png"},
|
||||
{"Title":"Mmm","ImageUrl":"https://mypersorg.sharepoint.com/sites/PnPSearchDemo/EmojiLibrary/RatingImg2.png"},
|
||||
{"Title":"Hmm","ImageUrl":"https://mypersorg.sharepoint.com/sites/PnPSearchDemo/EmojiLibrary/RatingImg3.png"},
|
||||
{"Title":"Meh","ImageUrl":"https://mypersorg.sharepoint.com/sites/PnPSearchDemo/EmojiLibrary/RatingImg4.png"},
|
||||
{"Title":"Pff","ImageUrl":"https://mypersorg.sharepoint.com/sites/PnPSearchDemo/EmojiLibrary/RatingImg5.png"}
|
||||
|
||||
],
|
||||
/* "propertyListName":"EmojiReactionRating", */
|
||||
"propertyEnableComments":"True",
|
||||
"propertyEnableCount":"True"
|
||||
}
|
||||
}]
|
||||
}
|
|
@ -0,0 +1,189 @@
|
|||
import * as React from 'react';
|
||||
import * as ReactDom from 'react-dom';
|
||||
import { Version } from '@microsoft/sp-core-library';
|
||||
import {
|
||||
IPropertyPaneConfiguration,
|
||||
PropertyPaneButton,
|
||||
PropertyPaneButtonType,
|
||||
PropertyPaneDropdown,
|
||||
PropertyPaneTextField,
|
||||
PropertyPaneToggle
|
||||
} from '@microsoft/sp-property-pane';
|
||||
import { BaseClientSideWebPart } from '@microsoft/sp-webpart-base';
|
||||
import { sp } from "@pnp/sp";
|
||||
|
||||
import * as strings from 'ReactEmojiReactionRatingWebPartStrings';
|
||||
import ReactEmojiReactionRating from './components/ReactEmojiReactionRating';
|
||||
import { IReactEmojiReactionRatingProps } from './components/IReactEmojiReactionRatingProps';
|
||||
import { PropertyFieldCollectionData, CustomCollectionFieldType } from '@pnp/spfx-property-controls/lib/PropertyFieldCollectionData';
|
||||
import { PropertyFieldColorPicker, PropertyFieldColorPickerStyle } from '@pnp/spfx-property-controls/lib/PropertyFieldColorPicker';
|
||||
|
||||
import spService from './components/services/spService';
|
||||
import { result } from 'lodash';
|
||||
|
||||
export interface IReactEmojiReactionRatingWebPartProps {
|
||||
propertyRatingText: string;
|
||||
propertyEmojisCollection: any[];
|
||||
propertyEnableComments: boolean;
|
||||
propertyEnableCount: boolean;
|
||||
propertySelectedColor: string;
|
||||
propertyListName: string;
|
||||
propertyListOperationMessage: string;
|
||||
}
|
||||
|
||||
|
||||
export default class ReactEmojiReactionRatingWebPart extends BaseClientSideWebPart<IReactEmojiReactionRatingWebPartProps> {
|
||||
|
||||
private _spService: spService = null;
|
||||
public render(): void {
|
||||
|
||||
const element: React.ReactElement<IReactEmojiReactionRatingProps> = React.createElement(
|
||||
ReactEmojiReactionRating,
|
||||
{
|
||||
ratingText: this.properties.propertyRatingText,
|
||||
emojisCollection: this.properties.propertyEmojisCollection,
|
||||
context: this.context,
|
||||
enableComments: this.properties.propertyEnableComments,
|
||||
enableCount: this.properties.propertyEnableCount,
|
||||
selectedColor: this.properties.propertySelectedColor,
|
||||
listName: this.properties.propertyListName,
|
||||
displayMode: this.displayMode,
|
||||
listMessage: this.properties.propertyListOperationMessage,
|
||||
}
|
||||
);
|
||||
|
||||
ReactDom.render(element, this.domElement);
|
||||
}
|
||||
|
||||
protected onDispose(): void {
|
||||
ReactDom.unmountComponentAtNode(this.domElement);
|
||||
}
|
||||
|
||||
protected get dataVersion(): Version {
|
||||
return Version.parse('1.0');
|
||||
}
|
||||
|
||||
private validateListName(value: string): string {
|
||||
if (value === null ||
|
||||
value.trim().length === 0) {
|
||||
return 'Provide a list name';
|
||||
}
|
||||
else {
|
||||
console.log("List Name: ", value);
|
||||
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public onInit(): Promise<void> {
|
||||
this._spService = new spService(this.context);
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
private btnListSchemaCreation(val: any): any {
|
||||
const colListColumns = ['Pagename', 'User', 'Rating1', 'Rating2', 'Rating3', 'Rating4', 'Rating5', 'Comments'];
|
||||
console.log("colListColumns: ", colListColumns);
|
||||
let listName = this.properties.propertyListName;
|
||||
console.log("listName: ", listName);
|
||||
|
||||
this._spService._createListwithColumns(listName, colListColumns).then((res) => {
|
||||
console.log(res);
|
||||
//this.properties.propertyListOperationMessage = result;
|
||||
//this.context.propertyPane.refresh();
|
||||
alert(res);
|
||||
|
||||
}).catch(error => {
|
||||
console.log("Something went wrong! please contact admin for more information.", error);
|
||||
// this.properties.propertyListOperationMessage = "Something went wrong! please contact admin for more information."
|
||||
// this.context.propertyPane.refresh();
|
||||
let errMessage = (error.mesaage || error.Mesaage);
|
||||
alert("Something went wrong! please contact admin for more information. "+ errMessage);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration {
|
||||
|
||||
return {
|
||||
pages: [
|
||||
{
|
||||
header: {
|
||||
description: strings.PropertyPaneDescription
|
||||
},
|
||||
groups: [
|
||||
{
|
||||
groupName: strings.BasicGroupName,
|
||||
groupFields: [
|
||||
PropertyPaneTextField('propertyListName', {
|
||||
label: strings.ListNameFieldLabel,
|
||||
description: "If you want to create new list, please enter list name and click on create list button",
|
||||
validateOnFocusOut: true,
|
||||
onGetErrorMessage: this.validateListName.bind(this),
|
||||
|
||||
}),
|
||||
PropertyPaneButton('propertyListSchemaButton',
|
||||
{
|
||||
text: strings.ListSchemaFieldLablel,
|
||||
buttonType: PropertyPaneButtonType.Primary,
|
||||
onClick: this.btnListSchemaCreation.bind(this)
|
||||
}),
|
||||
PropertyPaneTextField('propertyRatingText', {
|
||||
label: strings.RatingTextFieldLabel
|
||||
}),
|
||||
PropertyFieldCollectionData("propertyEmojisCollection", {
|
||||
key: "emojisCollection",
|
||||
label: strings.EmojisCollectionFieldLabel,//"Emojis Collection",
|
||||
panelHeader: "Emojis collection panel header",
|
||||
manageBtnLabel: "Manage emojis collection",
|
||||
value: this.properties.propertyEmojisCollection,
|
||||
fields: [
|
||||
{
|
||||
|
||||
id: "Title",
|
||||
title: "Title",
|
||||
type: CustomCollectionFieldType.string,
|
||||
required: true
|
||||
},
|
||||
{
|
||||
id: "ImageUrl",
|
||||
title: "ImageUrl",
|
||||
type: CustomCollectionFieldType.url,
|
||||
required: true
|
||||
|
||||
}
|
||||
],
|
||||
disabled: false,
|
||||
disableItemCreation: true,
|
||||
disableItemDeletion: true,
|
||||
}),
|
||||
PropertyPaneToggle('propertyEnableComments', {
|
||||
label: strings.EnableCommentsFieldLablel
|
||||
}),
|
||||
PropertyPaneToggle('propertyEnableCount', {
|
||||
label: strings.EnableCountFieldLablel
|
||||
}),
|
||||
PropertyFieldColorPicker('propertySelectedColor', {
|
||||
label: 'Select background color',
|
||||
selectedColor: this.properties.propertySelectedColor,
|
||||
onPropertyChange: this.onPropertyPaneFieldChanged,
|
||||
properties: this.properties,
|
||||
disabled: false,
|
||||
debounce: 1000,
|
||||
isHidden: false,
|
||||
alphaSliderHidden: false,
|
||||
style: PropertyFieldColorPickerStyle.Full,
|
||||
iconName: 'Precipitation',
|
||||
key: 'colorFieldId'
|
||||
}),
|
||||
|
||||
|
||||
]
|
||||
}
|
||||
|
||||
]
|
||||
}
|
||||
]
|
||||
};
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
import { WebPartContext } from "@microsoft/sp-webpart-base";
|
||||
|
||||
export interface IReactEmojiReactionRatingProps {
|
||||
ratingText: string;
|
||||
emojisCollection: any[];
|
||||
context: WebPartContext;
|
||||
enableComments: boolean;
|
||||
enableCount: boolean;
|
||||
selectedColor: string;
|
||||
listName: string;
|
||||
displayMode: any;
|
||||
listMessage: string;
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
export interface IReactEmojiReactionRatingState {
|
||||
selectedRatingIndex: Number | null;
|
||||
selectedRatingValue: string | null;
|
||||
0: Number | null;
|
||||
1: Number | null;
|
||||
2: Number | null;
|
||||
3: Number | null;
|
||||
4: Number | null;
|
||||
RatingComments: string;
|
||||
CustomMessage: string;
|
||||
configLoaded: boolean;
|
||||
isDialogHidden: boolean;
|
||||
dialogTitle: string;
|
||||
dialogBody: string;
|
||||
}
|
|
@ -0,0 +1,135 @@
|
|||
@import '~office-ui-fabric-react/dist/sass/References.scss';
|
||||
|
||||
.reactEmojiReactionRating {
|
||||
.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); */
|
||||
}
|
||||
|
||||
.row {
|
||||
@include ms-Grid-row;
|
||||
@include ms-fontColor-gray200;
|
||||
//background-color: $ms-color-themeDark;
|
||||
/* background-color: #F5EFDF !important; */
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.column10 {
|
||||
@include ms-Grid-col;
|
||||
@include ms-lg10;
|
||||
}
|
||||
|
||||
/* @include ms-xl8;
|
||||
@include ms-xlPush2;
|
||||
@include ms-lgPush1; */
|
||||
|
||||
.column2 {
|
||||
@include ms-Grid-col;
|
||||
@include ms-lg2;
|
||||
}
|
||||
|
||||
.title {
|
||||
/* @include ms-font-xl;
|
||||
@include ms-fontColor-gray200; */
|
||||
}
|
||||
|
||||
.selectedEmoji {
|
||||
background-color: firebrick !important;
|
||||
border-radius: 14px !important;
|
||||
cursor: pointer !important;
|
||||
}
|
||||
|
||||
.subTitle {
|
||||
/* @include ms-font-l;
|
||||
@include ms-fontColor-gray200; */
|
||||
}
|
||||
|
||||
.description {
|
||||
/* @include ms-font-l;
|
||||
@include ms-fontColor-gray200; */
|
||||
font-weight: 300;
|
||||
/* font-size: large; */
|
||||
}
|
||||
|
||||
|
||||
.lblCountClass {
|
||||
background-color: #ddd;
|
||||
border: none;
|
||||
color: black;
|
||||
padding: 10px 20px;
|
||||
text-align: center;
|
||||
text-decoration: none;
|
||||
display: inline-block;
|
||||
margin: 4px 2px;
|
||||
border-radius: 16px;
|
||||
|
||||
}
|
||||
|
||||
.btnCountClass {
|
||||
background-color: #ddd;
|
||||
border: none;
|
||||
color: black;
|
||||
padding: 10px 20px;
|
||||
text-align: center;
|
||||
text-decoration: none;
|
||||
display: inline-block;
|
||||
margin: 4px 2px;
|
||||
border-radius: 16px;
|
||||
cursor: default !important;
|
||||
}
|
||||
|
||||
.txtArea {
|
||||
color: grey !important;
|
||||
}
|
||||
|
||||
.txtArea label {
|
||||
color: grey !important;
|
||||
}
|
||||
|
||||
.stackImage {
|
||||
cursor: 'pointer' !important;
|
||||
border-radius: 20px !important;
|
||||
}
|
||||
|
||||
.labelClass {
|
||||
text-align: center !important;
|
||||
color: grey !important;
|
||||
}
|
||||
|
||||
|
||||
.button1 {
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,474 @@
|
|||
import * as React from 'react';
|
||||
import styles from './ReactEmojiReactionRating.module.scss';
|
||||
import { IReactEmojiReactionRatingProps } from './IReactEmojiReactionRatingProps';
|
||||
import { IReactEmojiReactionRatingState } from './IReactEmojiReactionRatingState';
|
||||
import { DisplayMode, Environment, EnvironmentType } from '@microsoft/sp-core-library';
|
||||
import spService from './services/spService';
|
||||
import {
|
||||
TextField, Stack, Label, PrimaryButton
|
||||
} from '@microsoft/office-ui-fabric-react-bundle';
|
||||
import Badge from '@material-ui/core/Badge/Badge';
|
||||
import { Placeholder } from "@pnp/spfx-controls-react/lib/Placeholder";
|
||||
import { Dialog, DialogFooter, DialogType } from 'office-ui-fabric-react';
|
||||
|
||||
export default class ReactEmojiReactionRating extends React.Component<IReactEmojiReactionRatingProps, IReactEmojiReactionRatingState> {
|
||||
private _spService: spService = null;
|
||||
private _message = null;
|
||||
private _currentContext = null;
|
||||
private listName = this.props.listName ? this.props.listName : "EmojiReactionRating";
|
||||
private existingRating: any;
|
||||
constructor(prop: IReactEmojiReactionRatingProps, state: IReactEmojiReactionRatingState) {
|
||||
super(prop);
|
||||
this.state = {
|
||||
selectedRatingIndex: null,
|
||||
selectedRatingValue: "",
|
||||
0: 0,
|
||||
1: 0,
|
||||
2: 0,
|
||||
3: 0,
|
||||
4: 0,
|
||||
RatingComments: "",
|
||||
CustomMessage: "",
|
||||
configLoaded: false,
|
||||
isDialogHidden: true,
|
||||
dialogTitle: "",
|
||||
dialogBody: "",
|
||||
};
|
||||
|
||||
|
||||
|
||||
this._currentContext = this.props.context;
|
||||
this._spService = new spService(this.props.context);
|
||||
if (Environment.type === EnvironmentType.SharePoint) {
|
||||
// this.getItems();
|
||||
// console.log("items: ", items);
|
||||
}
|
||||
else if (Environment.type === EnvironmentType.Local) {
|
||||
this._message = <div>Whoops! you are using local host...</div>;
|
||||
}
|
||||
|
||||
this.selectedRating = this.selectedRating.bind(this);
|
||||
this.submitRating = this.submitRating.bind(this);
|
||||
this.handleChange = this.handleChange.bind(this);
|
||||
this._onConfigure = this._onConfigure.bind(this);
|
||||
this.closeDialog = this.closeDialog.bind(this);
|
||||
}
|
||||
|
||||
public componentDidMount() {
|
||||
if (this.props.enableCount) {
|
||||
this.getItems();
|
||||
}
|
||||
if (this.props.listName && (this.props.emojisCollection.length > 0)) {
|
||||
this.setState({ configLoaded: true });
|
||||
}
|
||||
}
|
||||
|
||||
public componentDidUpdate(previousProps, previousState) {
|
||||
if (previousProps.listName !== this.props.listName) {
|
||||
if (this.props.listName && (this.props.emojisCollection.length > 0)) {
|
||||
this.setState({ configLoaded: true });
|
||||
//this.getItems();
|
||||
}
|
||||
}
|
||||
|
||||
if (previousProps.listMessage !== this.props.listMessage) {
|
||||
this.ShowDialogMessage("List Creation", this.props.listMessage);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private submitRating(event) {
|
||||
|
||||
let ratingCommnets = this.state.RatingComments ? (this.state.RatingComments).trim() : "";
|
||||
//let selectedRatingIndex = parseInt(event.target.id);
|
||||
//let selectedRatingIndex = event.target.tabIndex;
|
||||
// let selectedRatingValue = event.target.title;
|
||||
|
||||
let selectedRatingIndex = this.state.selectedRatingIndex;
|
||||
let selectedRatingValue = this.state.selectedRatingValue;
|
||||
let ratingField;
|
||||
|
||||
switch (selectedRatingIndex) {
|
||||
case 0:
|
||||
ratingField = "Rating1";
|
||||
break;
|
||||
case 1:
|
||||
ratingField = "Rating2";
|
||||
break;
|
||||
case 2:
|
||||
ratingField = "Rating3";
|
||||
break;
|
||||
case 3:
|
||||
ratingField = "Rating4";
|
||||
break;
|
||||
case 4:
|
||||
ratingField = "Rating5";
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
if (!(ratingField)) {
|
||||
console.log("Something went wrong! Please check with Admin.");
|
||||
return false;
|
||||
}
|
||||
|
||||
//let pageName = window.location.pathname.substring(window.location.pathname.lastIndexOf("/") + 1);
|
||||
/* let pageName = window.location.href;
|
||||
let body: IRatingNewItem = {
|
||||
Title: this._currentContext.pageContext.user.displayName,
|
||||
Pagename: pageName ? pageName : window.location.href,
|
||||
User: this._currentContext?.pageContext.user.loginName,
|
||||
Comment: this.props.enableComments ? ratingCommnets : "",
|
||||
|
||||
}
|
||||
//adding the right rating column and value
|
||||
body[ratingColumn] = selectedRatingValue;
|
||||
console.log("body object is: ", body); */
|
||||
|
||||
let pageName = window.location.href;
|
||||
let body: any = {
|
||||
Title: this._currentContext.pageContext.user.displayName,
|
||||
Pagename: pageName ? pageName : window.location.href,
|
||||
User: this._currentContext?.pageContext.user.loginName,
|
||||
Comments: this.props.enableComments ? ratingCommnets : "",
|
||||
Rating1: "",
|
||||
Rating2: "",
|
||||
Rating3: "",
|
||||
Rating4: "",
|
||||
Rating5: "",
|
||||
};
|
||||
|
||||
body[ratingField] = selectedRatingValue;
|
||||
console.log("body object is: ", body);
|
||||
|
||||
if (!this.existingRating) {
|
||||
this._spService._addRatingItem(this.listName, body)
|
||||
.then(value => {
|
||||
// alert("Rating submitted successfully, thank you!");
|
||||
//this.setState({ CustomMessage: "Rating submitted successfully, thank you!" });
|
||||
console.log("Rating submitted successfully, thank you!", value.data.id);
|
||||
|
||||
this.ShowDialogMessage("Rating submitted", "Your rating submitted successfully, thank you!");
|
||||
})
|
||||
.catch(error => {
|
||||
console.log("Something went wrong! please contact admin for more information.");
|
||||
this.ShowDialogError(error, "Something went wrong! please contact admin for more information.");
|
||||
});
|
||||
}
|
||||
else {
|
||||
this._spService._updateRatingItem(this.listName, body, this.existingRating.Id)
|
||||
.then(value => {
|
||||
console.log("Rating updated successfully, thank you!", value.data.id);
|
||||
this.ShowDialogMessage("Rating updated", "Your rating updated successfully, thank you!");
|
||||
})
|
||||
.catch(error => {
|
||||
console.log("Something went wrong! please contact admin for more information.");
|
||||
this.ShowDialogError(error, "Something went wrong! please contact admin for more information.");
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
private async getItems() {
|
||||
|
||||
console.log("getItems: ", this._currentContext);
|
||||
let ratingItems = await this._spService.getRatingListItems(this.listName);
|
||||
console.log("ratingItems: ", ratingItems);
|
||||
console.log("this.props.emojisCollection: ", this.props.emojisCollection.length);
|
||||
let column1ValIndex, column2ValIndex, column3ValIndex, column4ValIndex, column5ValIndex;
|
||||
|
||||
for (let i = this.props.emojisCollection.length; i > 0; i--) {
|
||||
switch (i) {
|
||||
case 5:
|
||||
column1ValIndex = this.props.emojisCollection.length - i;
|
||||
break;
|
||||
case 4:
|
||||
column2ValIndex = this.props.emojisCollection.length - i;
|
||||
break;
|
||||
case 3:
|
||||
column3ValIndex = this.props.emojisCollection.length - i;
|
||||
break;
|
||||
case 2:
|
||||
column4ValIndex = this.props.emojisCollection.length - i;
|
||||
break;
|
||||
case 1:
|
||||
column5ValIndex = this.props.emojisCollection.length - i;
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
let pageRatings = await ratingItems.filter((element)=> {
|
||||
return (element["Pagename"] == window.location.href
|
||||
);
|
||||
});
|
||||
|
||||
Promise.all([
|
||||
this.getRatingCount(pageRatings, 'Rating1', this.props.emojisCollection[column1ValIndex].Title),
|
||||
this.getRatingCount(pageRatings, 'Rating2', this.props.emojisCollection[column2ValIndex].Title),
|
||||
this.getRatingCount(pageRatings, 'Rating3', this.props.emojisCollection[column3ValIndex].Title),
|
||||
this.getRatingCount(pageRatings, 'Rating4', this.props.emojisCollection[column4ValIndex].Title),
|
||||
this.getRatingCount(pageRatings, 'Rating5', this.props.emojisCollection[column5ValIndex].Title),
|
||||
])
|
||||
.then(results => {
|
||||
console.log("countRating1: ", results[0]);
|
||||
console.log("countRating2: ", results[1]);
|
||||
console.log("countRating3: ", results[2]);
|
||||
console.log("countRating4: ", results[3]);
|
||||
console.log("countRating5: ", results[4]);
|
||||
|
||||
this.setState(
|
||||
{
|
||||
0: results[0],
|
||||
1: results[1],
|
||||
2: results[2],
|
||||
3: results[3],
|
||||
4: results[4]
|
||||
}
|
||||
);
|
||||
})
|
||||
.catch(error => {
|
||||
console.log("Error in getting the rating count!");
|
||||
});
|
||||
|
||||
let userLogin = this._currentContext.pageContext.user.loginName;
|
||||
let userSelectedRating = await ratingItems.filter((element)=> {
|
||||
return (element["Pagename"] == window.location.href
|
||||
&& (element["User"] == userLogin));
|
||||
});
|
||||
|
||||
console.log("userSelectedRating: ", userSelectedRating[0]);
|
||||
|
||||
this.existingRating = userSelectedRating[0];
|
||||
let currentUserRatingVal = "";
|
||||
let currentUserRatingColumn = "";
|
||||
//this.props.emojisCollection
|
||||
if (userSelectedRating[0]["Rating1"]) {
|
||||
currentUserRatingVal = userSelectedRating[0]["Rating1"];
|
||||
currentUserRatingColumn = "Rating1";
|
||||
|
||||
}
|
||||
else if (userSelectedRating[0]["Rating2"]) {
|
||||
currentUserRatingVal = userSelectedRating[0]["Rating2"];
|
||||
currentUserRatingColumn = "Rating2";
|
||||
|
||||
}
|
||||
else if (userSelectedRating[0]["Rating3"]) {
|
||||
currentUserRatingVal = userSelectedRating[0]["Rating3"];
|
||||
currentUserRatingColumn = "Rating3";
|
||||
|
||||
}
|
||||
else if (userSelectedRating[0]["Rating4"]) {
|
||||
currentUserRatingVal = userSelectedRating[0]["Rating4"];
|
||||
currentUserRatingColumn = "Rating4";
|
||||
|
||||
}
|
||||
else if (userSelectedRating[0]["Rating5"]) {
|
||||
currentUserRatingVal = userSelectedRating[0]["Rating5"];
|
||||
currentUserRatingColumn = "Rating5";
|
||||
|
||||
}
|
||||
|
||||
let userSelectedRatingIndex;
|
||||
await this.props.emojisCollection.filter((element, tabIndex)=> {
|
||||
if ((element["Title"] == currentUserRatingVal)) {
|
||||
userSelectedRatingIndex = tabIndex;
|
||||
return tabIndex;
|
||||
}
|
||||
});
|
||||
console.log("userSelectedRatingIndex: ", userSelectedRatingIndex);
|
||||
this.setState({
|
||||
selectedRatingIndex: userSelectedRatingIndex,
|
||||
selectedRatingValue: currentUserRatingVal
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
|
||||
private async getRatingCount(items: any[], colName: string, colValue: string) {
|
||||
let ratingCount = await items.filter((element)=> {
|
||||
return element[colName] == colValue;
|
||||
}).length;
|
||||
|
||||
return ratingCount;
|
||||
}
|
||||
|
||||
|
||||
private selectedRating(event) {
|
||||
let selectedRatingIndex = event.target.tabIndex;
|
||||
let selectedRatingValue = event.target.title;
|
||||
|
||||
this.setState({
|
||||
selectedRatingIndex: selectedRatingIndex,
|
||||
selectedRatingValue: selectedRatingValue
|
||||
});
|
||||
}
|
||||
|
||||
private handleChange(event: any, newValue: string) {
|
||||
let partialState = {};
|
||||
partialState[event.target.name] = newValue || "";
|
||||
this.setState(partialState);
|
||||
}
|
||||
|
||||
private _onConfigure = () => {
|
||||
this.props.context.propertyPane.open();
|
||||
}
|
||||
|
||||
private closeDialog(e: any) {
|
||||
this.setState({ isDialogHidden: true });
|
||||
window.location.reload();
|
||||
}
|
||||
|
||||
private ShowDialogMessage(title: string, body: string) {
|
||||
this.setState({
|
||||
//isRedirectDialogHidden: false,
|
||||
isDialogHidden: false,
|
||||
dialogTitle: title,
|
||||
dialogBody: body,
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
private ShowDialogError(
|
||||
error: any,
|
||||
customErrorMessage: string
|
||||
) {
|
||||
if (!customErrorMessage) {
|
||||
customErrorMessage = "";
|
||||
}
|
||||
this.setState({
|
||||
isDialogHidden: false,
|
||||
dialogTitle: "Error: Request failed.",
|
||||
dialogBody: customErrorMessage.concat(
|
||||
" Error message: ",
|
||||
(error.Message || error.message)
|
||||
),
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
public render(): React.ReactElement<IReactEmojiReactionRatingProps> {
|
||||
|
||||
/* if (this.props.listMessage) {
|
||||
this.ShowDialogMessage("List Creation", this.props.listMessage);
|
||||
} */
|
||||
|
||||
return !(this.state.configLoaded) ? (
|
||||
<Placeholder iconName='Edit'
|
||||
iconText='Configure your web part'
|
||||
description='Please configure the web part.'
|
||||
buttonLabel='Configure'
|
||||
hideButton={this.props.displayMode === DisplayMode.Read}
|
||||
onConfigure={this._onConfigure} />
|
||||
) : (this.props.listMessage ? (
|
||||
<div>{this.props.listMessage}</div>
|
||||
) :
|
||||
(
|
||||
<div className={styles.reactEmojiReactionRating} style={{
|
||||
backgroundColor: `${this.props.selectedColor
|
||||
}`
|
||||
}}>
|
||||
<div className={styles.container}>
|
||||
<div className={styles.row}>
|
||||
<Stack>
|
||||
<div className={styles.description}>{this.props.ratingText ? this.props.ratingText : ''}</div>
|
||||
</Stack>
|
||||
</div>
|
||||
|
||||
<div className={styles.row}>
|
||||
<Stack horizontal verticalAlign="center" horizontalAlign="space-between">
|
||||
{this.props.emojisCollection ? this.props.emojisCollection.map((ratingItem, tabIndex) => (
|
||||
<Stack.Item>
|
||||
{this.props.enableCount ? (
|
||||
<>
|
||||
<Badge color="secondary" overlap="circular" badgeContent={this.state[tabIndex]}>
|
||||
<img src={ratingItem.ImageUrl}
|
||||
className={this.state.selectedRatingIndex == tabIndex ? styles.selectedEmoji : styles.stackImage}
|
||||
title={ratingItem.Title}
|
||||
tabIndex={tabIndex}
|
||||
id={tabIndex.toString()}
|
||||
alt={ratingItem.Title}
|
||||
onClick={this.selectedRating}
|
||||
/>
|
||||
</Badge>
|
||||
<Label className={styles.labelClass}>{ratingItem.Title}</Label>
|
||||
</>) : (
|
||||
<>
|
||||
<img src={ratingItem.ImageUrl}
|
||||
className={this.state.selectedRatingIndex == tabIndex ? styles.selectedEmoji : styles.stackImage}
|
||||
title={ratingItem.Title}
|
||||
tabIndex={tabIndex}
|
||||
id={tabIndex.toString()}
|
||||
alt={ratingItem.Title}
|
||||
onClick={this.selectedRating} />
|
||||
<Label className={styles.labelClass}>{ratingItem.Title}</Label>
|
||||
</>
|
||||
)
|
||||
}
|
||||
</Stack.Item>
|
||||
)) :
|
||||
<Label>Rating list is empty...</Label>}
|
||||
</Stack>
|
||||
</div>
|
||||
|
||||
{this.props.enableComments ? (
|
||||
<div className={styles.row}>
|
||||
<TextField
|
||||
label={"Enter comments"}
|
||||
value={this.state.RatingComments}
|
||||
onChange={this.handleChange}
|
||||
name="RatingComments"
|
||||
rows={6}
|
||||
multiline={true}
|
||||
width={80}
|
||||
className={styles.txtArea}
|
||||
/>
|
||||
{this.state.RatingComments}
|
||||
</div>
|
||||
|
||||
) : ""
|
||||
}
|
||||
{this.state.CustomMessage ? (
|
||||
<div className={styles.row}>
|
||||
{this.state.CustomMessage}
|
||||
</div>
|
||||
) : ""
|
||||
}
|
||||
|
||||
{this._message}
|
||||
<div className={styles.row}>
|
||||
<div className={styles.column10}>
|
||||
</div>
|
||||
<div className={styles.column2}>
|
||||
<PrimaryButton text="Submit" onClick={this.submitRating} disabled={this.state.selectedRatingValue ? false : true} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Dialog
|
||||
hidden={this.state.isDialogHidden}
|
||||
onDismiss={this.closeDialog}
|
||||
dialogContentProps={{
|
||||
type: DialogType.normal,
|
||||
title: this.state.dialogTitle,
|
||||
subText: this.state.dialogBody
|
||||
}}
|
||||
modalProps={{
|
||||
isBlocking: true,
|
||||
styles: { main: { maxWidth: 450 } }
|
||||
}}
|
||||
>
|
||||
<DialogFooter>
|
||||
<PrimaryButton onClick={this.closeDialog} text="OK" />
|
||||
</DialogFooter>
|
||||
</Dialog>
|
||||
|
||||
</div >
|
||||
</div >
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
export interface IRatingNewItem {
|
||||
Id?: number;
|
||||
Title: string;
|
||||
Pagename: string;
|
||||
User: string;
|
||||
Comment: string;
|
||||
Rating1?: string;
|
||||
Rating2?: string;
|
||||
Rating3?: string;
|
||||
Rating4?: string;
|
||||
Rating5?: string;
|
||||
|
||||
}
|
|
@ -0,0 +1,153 @@
|
|||
import { WebPartContext } from "@microsoft/sp-webpart-base";
|
||||
import { sp } from "@pnp/sp";
|
||||
import "@pnp/sp/webs";
|
||||
import "@pnp/sp/lists";
|
||||
import "@pnp/sp/items";
|
||||
import "@pnp/sp/fields";
|
||||
import "@pnp/sp/views";
|
||||
import { IItemAddResult } from "@pnp/sp/items";
|
||||
import { IRatingNewItem } from "../models/IRatingNewItem";
|
||||
// Class Services
|
||||
export default class spService {
|
||||
|
||||
constructor(private context: WebPartContext) {
|
||||
// Setup Context to PnPjs
|
||||
sp.setup({
|
||||
spfxContext: this.context
|
||||
});
|
||||
// Init
|
||||
this.onInit();
|
||||
}
|
||||
// OnInit Function
|
||||
private async onInit() {
|
||||
|
||||
}
|
||||
|
||||
public async _getListItems(listName: string) {
|
||||
const allItems: any[] = await sp.web.lists.getByTitle(listName).items.getAll();
|
||||
console.log(allItems);
|
||||
return allItems;
|
||||
}
|
||||
|
||||
|
||||
public getRatingListItems(listName: string): Promise<any[]> {
|
||||
let promise: Promise<any[]> = new Promise<any[]>(
|
||||
(resolve, reject) => {
|
||||
sp.web.lists
|
||||
.getByTitle(listName)
|
||||
.items
|
||||
.getAll(4000)
|
||||
.then((data: any[]) => {
|
||||
resolve(data);
|
||||
})
|
||||
.catch((error: any) => {
|
||||
reject(error);
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
return promise;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public async _addRatingItemPnP(listName: string, RatingRequest: IRatingNewItem) {
|
||||
await sp.web.lists.getByTitle(listName).items.add(RatingRequest);
|
||||
}
|
||||
|
||||
public _addRatingItem(listName: string, RatingRequest: IRatingNewItem): Promise<IItemAddResult> {
|
||||
let promise: Promise<IItemAddResult> = new Promise<IItemAddResult>(
|
||||
(resolve, reject) => {
|
||||
sp.web.lists
|
||||
.getByTitle(listName)
|
||||
.items.add(
|
||||
RatingRequest
|
||||
)
|
||||
.then((iar: IItemAddResult) => {
|
||||
resolve(iar);
|
||||
})
|
||||
.catch(error => {
|
||||
reject(error);
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
return promise;
|
||||
}
|
||||
|
||||
public _updateRatingItem(listName: string, RatingRequest: IRatingNewItem, ExistingID: any): Promise<IItemAddResult> {
|
||||
let promise: Promise<IItemAddResult> = new Promise<IItemAddResult>(
|
||||
(resolve, reject) => {
|
||||
sp.web.lists
|
||||
.getByTitle(listName)
|
||||
.items.getById(ExistingID).update(
|
||||
RatingRequest
|
||||
)
|
||||
.then((iar: IItemAddResult) => {
|
||||
resolve(iar);
|
||||
})
|
||||
.catch(error => {
|
||||
reject(error);
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
return promise;
|
||||
}
|
||||
public async _createListwithColumns(listName: string, colListColumns: any[]) {
|
||||
|
||||
let listExist = await this._checkList(listName);
|
||||
console.log("List exist: ", listExist);
|
||||
if (!listExist) {
|
||||
const listAddResult = await sp.web.lists.add(listName);
|
||||
const list = await listAddResult.list.get();
|
||||
|
||||
const newList = await sp.web.lists.getByTitle(listName);
|
||||
const view = await newList.defaultView;
|
||||
|
||||
//checking columns are added to the collection or not
|
||||
if (colListColumns.length > 0) {
|
||||
const batch = sp.web.createBatch();
|
||||
colListColumns.forEach(fieldName => {
|
||||
if (fieldName == "Comments") {
|
||||
newList.fields.inBatch(batch).addMultilineText(fieldName, 6);
|
||||
}
|
||||
else {
|
||||
newList.fields.inBatch(batch).addText(fieldName, 255);
|
||||
}
|
||||
});
|
||||
|
||||
colListColumns.forEach(fieldName => {
|
||||
view.fields.inBatch(batch).add(fieldName);
|
||||
|
||||
});
|
||||
|
||||
batch.execute().then(_result => {
|
||||
console.log('List with columns created.');
|
||||
|
||||
}).catch(error => {
|
||||
console.log(error);
|
||||
});
|
||||
return "List with required columns created.";
|
||||
}
|
||||
}
|
||||
else {
|
||||
return "List alreay exist";
|
||||
}
|
||||
}
|
||||
|
||||
public async _checkList(listName: string) {
|
||||
let filterList = `Title eq '${listName}'`;
|
||||
let boolResult: boolean = false;
|
||||
let getList = await sp.web.lists.filter(filterList).get();
|
||||
if (getList.length > 0) {
|
||||
return boolResult = true;
|
||||
}
|
||||
else {
|
||||
return boolResult;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
14
samples/react-emoji-ratings/src/webparts/reactEmojiReactionRating/loc/en-us.js
vendored
Normal file
|
@ -0,0 +1,14 @@
|
|||
define([], function() {
|
||||
return {
|
||||
"PropertyPaneDescription": "This is a webpart to collect page ratings!",
|
||||
"BasicGroupName": "Rating WebPart Configuration",
|
||||
"RatingTextFieldLabel": "Rating text",
|
||||
"EmojisCollectionFieldLabel":"Emojis collection",
|
||||
"EnableCommentsFieldLablel":"Enable comments",
|
||||
"EnableCountFieldLablel":"Enable count",
|
||||
"ListSchemaFieldLablel":"Create List",
|
||||
"ListColumnsFieldLabel":"List Columns",
|
||||
"ListNameFieldLabel":"List Name",
|
||||
|
||||
}
|
||||
});
|
17
samples/react-emoji-ratings/src/webparts/reactEmojiReactionRating/loc/mystrings.d.ts
vendored
Normal file
|
@ -0,0 +1,17 @@
|
|||
declare interface IReactEmojiReactionRatingWebPartStrings {
|
||||
PropertyPaneDescription: string;
|
||||
BasicGroupName: string;
|
||||
RatingTextFieldLabel: string;
|
||||
EmojisCollectionFieldLabel:string;
|
||||
EnableCommentsFieldLablel:string;
|
||||
EnableCountFieldLablel:string;
|
||||
ListSchemaFieldLablel:string;
|
||||
ListColumnsFieldLabel:string;
|
||||
ListNameFieldLabel:string;
|
||||
ListSchemaFieldLabel:string;
|
||||
}
|
||||
|
||||
declare module 'ReactEmojiReactionRatingWebPartStrings' {
|
||||
const strings: IReactEmojiReactionRatingWebPartStrings;
|
||||
export = strings;
|
||||
}
|
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 383 B |
|
@ -0,0 +1,35 @@
|
|||
{
|
||||
"extends": "./node_modules/@microsoft/rush-stack-compiler-3.7/includes/tsconfig-web.json",
|
||||
"compilerOptions": {
|
||||
"target": "es5",
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"module": "esnext",
|
||||
"moduleResolution": "node",
|
||||
"jsx": "react",
|
||||
"declaration": true,
|
||||
"sourceMap": true,
|
||||
"experimentalDecorators": true,
|
||||
"skipLibCheck": true,
|
||||
"outDir": "lib",
|
||||
"inlineSources": false,
|
||||
"strictNullChecks": false,
|
||||
"noUnusedLocals": false,
|
||||
"typeRoots": [
|
||||
"./node_modules/@types",
|
||||
"./node_modules/@microsoft"
|
||||
],
|
||||
"types": [
|
||||
"webpack-env"
|
||||
],
|
||||
"lib": [
|
||||
"es5",
|
||||
"dom",
|
||||
"es2015.collection",
|
||||
"es2015.promise"
|
||||
]
|
||||
},
|
||||
"include": [
|
||||
"src/**/*.ts",
|
||||
"src/**/*.tsx"
|
||||
]
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
{
|
||||
"extends": "./node_modules/@microsoft/sp-tslint-rules/base-tslint.json",
|
||||
"rules": {
|
||||
"class-name": false,
|
||||
"export-name": false,
|
||||
"forin": false,
|
||||
"label-position": false,
|
||||
"member-access": true,
|
||||
"no-arg": false,
|
||||
"no-console": false,
|
||||
"no-construct": false,
|
||||
"no-duplicate-variable": true,
|
||||
"no-eval": false,
|
||||
"no-function-expression": true,
|
||||
"no-internal-module": true,
|
||||
"no-shadowed-variable": true,
|
||||
"no-switch-case-fall-through": true,
|
||||
"no-unnecessary-semicolons": true,
|
||||
"no-unused-expression": true,
|
||||
"no-use-before-declare": true,
|
||||
"no-with-statement": true,
|
||||
"semicolon": true,
|
||||
"trailing-comma": false,
|
||||
"typedef": false,
|
||||
"typedef-whitespace": false,
|
||||
"use-named-parameter": true,
|
||||
"variable-name": false,
|
||||
"whitespace": false
|
||||
}
|
||||
}
|
|
@ -0,0 +1,98 @@
|
|||
{
|
||||
"bundles": {
|
||||
"multi-screen-web-part": {
|
||||
"dependencies": [
|
||||
{
|
||||
"componentId": "7263c7d0-1d6a-45ec-8d85-d4d1d234171b",
|
||||
"componentName": "@microsoft/sp-core-library",
|
||||
"componentVersion": "1.12.1",
|
||||
"isDirectDependency": true
|
||||
},
|
||||
{
|
||||
"componentId": "01c4df03-e775-48cb-aa14-171ee5199a15",
|
||||
"componentName": "tslib",
|
||||
"componentVersion": "1.10.0",
|
||||
"isDirectDependency": false
|
||||
},
|
||||
{
|
||||
"componentId": "2e09fb9b-13bb-48f2-859f-97d6fff71176",
|
||||
"componentName": "@ms/odsp-core-bundle",
|
||||
"componentVersion": "1.1.13",
|
||||
"isDirectDependency": false
|
||||
},
|
||||
{
|
||||
"componentId": "73e1dc6c-8441-42cc-ad47-4bd3659f8a3a",
|
||||
"componentName": "@microsoft/sp-lodash-subset",
|
||||
"componentVersion": "1.12.1",
|
||||
"isDirectDependency": false
|
||||
},
|
||||
{
|
||||
"componentId": "974a7777-0990-4136-8fa6-95d80114c2e0",
|
||||
"componentName": "@microsoft/sp-webpart-base",
|
||||
"componentVersion": "1.12.1",
|
||||
"isDirectDependency": true
|
||||
},
|
||||
{
|
||||
"componentId": "8217e442-8ed3-41fd-957d-b112e841286a",
|
||||
"componentName": "@ms/sp-telemetry",
|
||||
"componentVersion": "0.19.2",
|
||||
"isDirectDependency": false
|
||||
},
|
||||
{
|
||||
"componentId": "467dc675-7cc5-4709-8aac-78e3b71bd2f6",
|
||||
"componentName": "@microsoft/sp-component-base",
|
||||
"componentVersion": "1.12.1",
|
||||
"isDirectDependency": false
|
||||
},
|
||||
{
|
||||
"componentId": "e40f8203-b39d-425a-a957-714852e33b79",
|
||||
"componentName": "@microsoft/sp-dynamic-data",
|
||||
"componentVersion": "1.12.1",
|
||||
"isDirectDependency": false
|
||||
},
|
||||
{
|
||||
"componentId": "78359e4b-07c2-43c6-8d0b-d060b4d577e8",
|
||||
"componentName": "@microsoft/sp-diagnostics",
|
||||
"componentVersion": "1.12.1",
|
||||
"isDirectDependency": false
|
||||
},
|
||||
{
|
||||
"componentId": "1c4541f7-5c31-41aa-9fa8-fbc9dc14c0a8",
|
||||
"componentName": "@microsoft/sp-page-context",
|
||||
"componentVersion": "1.12.1",
|
||||
"isDirectDependency": false
|
||||
},
|
||||
{
|
||||
"componentId": "229b8d08-79f3-438b-8c21-4613fc877abd",
|
||||
"componentName": "@microsoft/load-themed-styles",
|
||||
"componentVersion": "0.1.2",
|
||||
"isDirectDependency": false
|
||||
},
|
||||
{
|
||||
"componentId": "c07208f0-ea3b-4c1a-9965-ac1b825211a6",
|
||||
"componentName": "@microsoft/sp-http",
|
||||
"componentVersion": "1.12.1",
|
||||
"isDirectDependency": false
|
||||
},
|
||||
{
|
||||
"componentId": "1c6c9123-7aac-41f3-a376-3caea41ed83f",
|
||||
"componentName": "@microsoft/sp-loader",
|
||||
"componentVersion": "1.12.1",
|
||||
"isDirectDependency": false
|
||||
},
|
||||
{
|
||||
"componentId": "0d910c1c-13b9-4e1c-9aa4-b008c5e42d7d",
|
||||
"componentName": "react",
|
||||
"componentVersion": "16.9.0",
|
||||
"isDirectDependency": true
|
||||
},
|
||||
{
|
||||
"componentId": "aa0a46ec-1505-43cd-a44a-93f3a5aa460a",
|
||||
"componentName": "react-dom",
|
||||
"componentVersion": "16.9.0",
|
||||
"isDirectDependency": true
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
{
|
||||
"id": "f9a07202-7f8f-4944-a02c-1fd20b508207",
|
||||
"alias": "MultiScreenWebPart",
|
||||
"componentType": "WebPart",
|
||||
"version": "0.0.1",
|
||||
"manifestVersion": 2,
|
||||
"requiresCustomScript": false,
|
||||
"supportedHosts": [
|
||||
"SharePointWebPart",
|
||||
"SharePointFullPage",
|
||||
"TeamsTab"
|
||||
],
|
||||
"preconfiguredEntries": [
|
||||
{
|
||||
"groupId": "5c03119e-3074-46fd-976b-c60198311f70",
|
||||
"group": {
|
||||
"default": "Other"
|
||||
},
|
||||
"title": {
|
||||
"default": "MultiScreenWebPart"
|
||||
},
|
||||
"description": {
|
||||
"default": "MultiScreenWebPart description"
|
||||
},
|
||||
"officeFabricIconFontName": "Page",
|
||||
"properties": {
|
||||
"description": "MultiScreenWebPart"
|
||||
}
|
||||
}
|
||||
],
|
||||
"loaderConfig": {
|
||||
"internalModuleBaseUrls": [
|
||||
"<!-- PATH TO CDN -->"
|
||||
],
|
||||
"entryModuleId": "multi-screen-web-part",
|
||||
"scriptResources": {
|
||||
"multi-screen-web-part": {
|
||||
"type": "path",
|
||||
"path": "multi-screen-web-part.js"
|
||||
},
|
||||
"@microsoft/sp-core-library": {
|
||||
"type": "component",
|
||||
"id": "7263c7d0-1d6a-45ec-8d85-d4d1d234171b",
|
||||
"version": "1.12.1"
|
||||
},
|
||||
"@microsoft/sp-webpart-base": {
|
||||
"type": "component",
|
||||
"id": "974a7777-0990-4136-8fa6-95d80114c2e0",
|
||||
"version": "1.12.1"
|
||||
},
|
||||
"react": {
|
||||
"type": "component",
|
||||
"id": "0d910c1c-13b9-4e1c-9aa4-b008c5e42d7d",
|
||||
"version": "16.9.0"
|
||||
},
|
||||
"react-dom": {
|
||||
"type": "component",
|
||||
"id": "aa0a46ec-1505-43cd-a44a-93f3a5aa460a",
|
||||
"version": "16.9.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|