Abans de la col·lecció AvatarsRegistre
This commit is contained in:
parent
1cefb0b28e
commit
56a0b76c6d
@ -22,3 +22,4 @@ react-meteor-data # React higher-order component for reactively tracking M
|
||||
roles@1.0.1
|
||||
accounts-password@3.0.3
|
||||
react-meteor-accounts
|
||||
ostrio:files
|
||||
|
||||
@ -1 +1 @@
|
||||
METEOR@3.1.1
|
||||
METEOR@3.1.2
|
||||
|
||||
@ -23,7 +23,7 @@ ecmascript-runtime@0.8.3
|
||||
ecmascript-runtime-client@0.12.2
|
||||
ecmascript-runtime-server@0.11.1
|
||||
ejson@1.1.4
|
||||
email@3.1.1
|
||||
email@3.1.2
|
||||
es5-shim@4.8.1
|
||||
facts-base@1.0.2
|
||||
fetch@0.1.5
|
||||
@ -42,7 +42,7 @@ minifier-js@3.0.1
|
||||
minimongo@2.0.2
|
||||
mobile-experience@1.1.2
|
||||
mobile-status-bar@1.1.1
|
||||
modern-browsers@0.1.11
|
||||
modern-browsers@0.2.0
|
||||
modules@0.20.3
|
||||
modules-runtime@0.13.2
|
||||
modules-runtime-hot@0.14.3
|
||||
@ -52,6 +52,8 @@ mongo-dev-server@1.1.1
|
||||
mongo-id@1.0.9
|
||||
npm-mongo@6.10.2
|
||||
ordered-dict@1.2.0
|
||||
ostrio:cookies@2.8.1
|
||||
ostrio:files@3.0.0-beta.6
|
||||
promise@1.0.0
|
||||
random@1.2.2
|
||||
rate-limit@1.1.2
|
||||
@ -73,5 +75,5 @@ static-html-tools@1.0.0
|
||||
tracker@1.3.4
|
||||
typescript@5.6.3
|
||||
url@1.3.5
|
||||
webapp@2.0.4
|
||||
webapp@2.0.5
|
||||
webapp-hashing@1.1.2
|
||||
|
||||
275
imports/api/files.js
Normal file
275
imports/api/files.js
Normal file
@ -0,0 +1,275 @@
|
||||
import { Meteor } from 'meteor/meteor';
|
||||
import { FilesCollection } from 'meteor/ostrio:files';
|
||||
import { createBucket } from '/imports/api/lib/grid/createBucket.js';
|
||||
import { createObjectId } from '/imports/api/lib/grid/createObjectId.js';
|
||||
import fs from 'fs';
|
||||
|
||||
// import { Mongo } from 'meteor/mongo';
|
||||
|
||||
let filesBucket;
|
||||
|
||||
if (Meteor.isServer) {
|
||||
filesBucket = createBucket('allFiles');
|
||||
}
|
||||
|
||||
const FilesCol = new FilesCollection({
|
||||
collectionName: 'Files',
|
||||
allowClientCode: true,
|
||||
debug: Meteor.isServer && process.env.NODE_ENV === 'development',
|
||||
onBeforeUpload (file) {
|
||||
// if (file.size <= 10485760 && /png|jpg|jpeg/i.test(file.extension)) {
|
||||
// return true;
|
||||
// }
|
||||
// return 'Please upload image, with size equal or less than 10MB';
|
||||
return true;
|
||||
},
|
||||
|
||||
onAfterUpload(file) {
|
||||
const self = this;
|
||||
|
||||
// here you could manipulate your file
|
||||
// and create a new version, for example a scaled 'thumbnail'
|
||||
// ...
|
||||
|
||||
console.log("file_versions: ", file.versions);
|
||||
|
||||
// then we read all versions we have got so far
|
||||
Object.keys(file.versions).forEach(versionName => {
|
||||
const metadata = { ...file.meta, versionName, fileId: file._id };
|
||||
fs.createReadStream(file.versions[ versionName ].path)
|
||||
|
||||
// this is where we upload the binary to the bucket
|
||||
.pipe(filesBucket.openUploadStream(
|
||||
file.name,
|
||||
{
|
||||
contentType: file.type || 'binary/octet-stream',
|
||||
metadata
|
||||
}
|
||||
))
|
||||
|
||||
// and we unlink the file from the fs on any error
|
||||
// that occurred during the upload to prevent zombie files
|
||||
.on('error', async err => {
|
||||
console.error(err);
|
||||
self.unlink(await this.collection.findOneAsync(file._id), versionName); // Unlink files from FS
|
||||
})
|
||||
|
||||
// once we are finished, we attach the gridFS Object id on the
|
||||
// FilesCollection document's meta section and finally unlink the
|
||||
// upload file from the filesystem
|
||||
.on('finish', Meteor.bindEnvironment(async ver => {
|
||||
const property = `versions.${versionName}.meta.gridFsFileId`;
|
||||
await self.collection.updateAsync(file._id, {
|
||||
$set: {
|
||||
[ property ]: ver._id.toHexString()
|
||||
}
|
||||
});
|
||||
self.unlink(await this.collection.findOneAsync(file._id), versionName); // Unlink files from FS
|
||||
}))
|
||||
})
|
||||
},
|
||||
|
||||
interceptDownload (http, file, versionName) {
|
||||
const { gridFsFileId } = file.versions[ versionName ].meta || {};
|
||||
if (gridFsFileId) {
|
||||
const gfsId = createObjectId({ gridFsFileId });
|
||||
const readStream = filesBucket.openDownloadStream(gfsId);
|
||||
readStream.on('data', (data) => {
|
||||
http.response.write(data);
|
||||
})
|
||||
|
||||
readStream.on('end', () => {
|
||||
http.response.end('end');
|
||||
})
|
||||
|
||||
readStream.on('error', () => {
|
||||
// not found probably
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
http.response.statusCode = 404;
|
||||
http.response.end('not found');
|
||||
})
|
||||
|
||||
http.response.setHeader('Cache-Control', this.cacheControl);
|
||||
http.response.setHeader('Content-Disposition', `inline; filename="${file.name}"`);
|
||||
}
|
||||
return Boolean(gridFsFileId) // Serve file from either GridFS or FS if it wasn't uploaded yet
|
||||
},
|
||||
|
||||
onAfterRemove (files) {
|
||||
files.forEach(file => {
|
||||
Object.keys(file.versions).forEach(versionName => {
|
||||
const gridFsFileId = (file.versions[ versionName ].meta || {}).gridFsFileId;
|
||||
if (gridFsFileId) {
|
||||
const gfsId = createObjectId({ gridFsFileId });
|
||||
filesBucket.deleteAsync(gfsId, err => { if (err) console.error(err); });
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
// if (Meteor.isClient) {
|
||||
// Meteor.subscribe('files.all');
|
||||
// }
|
||||
|
||||
if (Meteor.isServer) {
|
||||
|
||||
Meteor.publish('files.all', () => {
|
||||
return FilesCol.collection.find({userId: Meteor.userId()});
|
||||
});
|
||||
|
||||
Meteor.publish('avatars.all', () => {
|
||||
return Avatars.collection.find({});
|
||||
});
|
||||
|
||||
// Meteor.publish('files.avatar', () => {
|
||||
// return FilesCol.collection.find({
|
||||
// userId: Meteor.userId(),
|
||||
// 'meta.type': 'avatar'
|
||||
// });
|
||||
// });
|
||||
|
||||
// Meteor.publish('files.avatarRegister', (avatarId) => {
|
||||
// if (avatarId) {
|
||||
// if (!Meteor.userId()) {
|
||||
// return FilesCol.collection.find({_id: avatarId});
|
||||
// }
|
||||
// } else {
|
||||
// return [];
|
||||
// }
|
||||
// });
|
||||
|
||||
// Meteor.publish('files.folderTree', () => {
|
||||
// //if (upId) {
|
||||
// if (Meteor.userId()) {
|
||||
// return FilesCol.collection.find({
|
||||
// userId: Meteor.userId(),
|
||||
// "meta.type": "folderTree"
|
||||
// });
|
||||
// } else {
|
||||
// return [];
|
||||
// }
|
||||
// });
|
||||
|
||||
// // files.cartellEventUpload
|
||||
// Meteor.publish('files.cartellEventUpload', (cartellId) => {
|
||||
// if (cartellId) {
|
||||
// //if (!Meteor.userId()) {
|
||||
// return FilesCol.collection.find({_id: cartellId});
|
||||
// } else {
|
||||
// return [];
|
||||
// }
|
||||
// });
|
||||
}
|
||||
|
||||
Meteor.methods({
|
||||
|
||||
'RenameFile'(data){
|
||||
// if (!Meteor.userId()){
|
||||
// throw new Meteor.Error('not-authorized');
|
||||
// }
|
||||
FilesCol.insertAsync({
|
||||
...data,
|
||||
createdAt: new Date(),
|
||||
user: Meteor.userId()
|
||||
});
|
||||
},
|
||||
|
||||
'ReassignaUserIdFile'(userIdProvisional, uid){
|
||||
// if (!Meteor.userId()){
|
||||
// throw new Meteor.Error('not-authorized');
|
||||
// }
|
||||
|
||||
FilesCol.collection.updateAsync({_id: userIdProvisional}, {
|
||||
$set: {
|
||||
meta: {
|
||||
userId: uid
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
'RemoveFile'(fileToRemoveId) {
|
||||
FilesCol.collection.removeAsync(fileToRemoveId);
|
||||
}
|
||||
|
||||
|
||||
// getFolderTreeFiles() {
|
||||
// return FilesCol.find({
|
||||
// // userId: Meteor.userId(),
|
||||
// // 'meta.type': 'folderTree'
|
||||
// }).fetch();
|
||||
// }
|
||||
// 'dates.update'(data){
|
||||
// // if (Meteor.userId() !== allcod.user){
|
||||
// // throw new Meteor.Error('not-authorized');
|
||||
// // }
|
||||
// DatesCollection.update(data._id, {
|
||||
// $set: {
|
||||
// ...data
|
||||
// }
|
||||
// });
|
||||
// },
|
||||
|
||||
// 'dates.delete'(data){
|
||||
// // if (Meteor.userId() !== allcod.user){
|
||||
// // throw new Meteor.Error('not-authorized');
|
||||
// // }
|
||||
// DatesCollection.remove(data._id);
|
||||
// },
|
||||
|
||||
// 'dates.remove'(id, context) {
|
||||
// DatesCollection.remove(id);
|
||||
// }
|
||||
|
||||
});
|
||||
|
||||
|
||||
// Create a new instance of the FilesCollection
|
||||
const Avatars = new FilesCollection({
|
||||
collectionName: 'Avatars',
|
||||
storagePath: 'assets/avatarStorage',
|
||||
downloadRoute: '/avatar',
|
||||
permissions: 0o755,
|
||||
cacheControl: 'public, max-age=31536000',
|
||||
allowClientCode: false, // Disallow remove files from Client
|
||||
});
|
||||
|
||||
Meteor.methods({
|
||||
|
||||
'registraUsuariAmbAvatar'(username, email, password, avatar) {
|
||||
// Check if the username and email are valid
|
||||
if (!username || !email || !password) {
|
||||
throw new Meteor.Error('invalid-input', 'Please fill in all fields');
|
||||
}
|
||||
|
||||
// Check if the avatar is a valid file
|
||||
if (!avatar || !avatar.file) {
|
||||
throw new Meteor.Error('invalid-avatar', 'Please select a valid avatar image');
|
||||
}
|
||||
|
||||
// Upload the avatar to GridFS
|
||||
const avatarId = Avatars.insert(avatar.file, (err, fileObj) => {
|
||||
if (err) {
|
||||
throw new Meteor.Error('avatar-upload-failed', 'Failed to upload avatar');
|
||||
}
|
||||
});
|
||||
|
||||
// Create the new user
|
||||
const userId = Accounts.createUser({
|
||||
username,
|
||||
email,
|
||||
password,
|
||||
profile: {
|
||||
avatar: avatarId,
|
||||
},
|
||||
});
|
||||
|
||||
// Return the new user's ID
|
||||
return userId;
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
export { FilesCol, Avatars };
|
||||
6
imports/api/lib/grid/createBucket.js
Normal file
6
imports/api/lib/grid/createBucket.js
Normal file
@ -0,0 +1,6 @@
|
||||
import { MongoInternals } from 'meteor/mongo';
|
||||
|
||||
export const createBucket = bucketName => {
|
||||
const options = bucketName ? {bucketName} : (void 0);
|
||||
return new MongoInternals.NpmModule.GridFSBucket(MongoInternals.defaultRemoteCollectionDriver().mongo.db, options);
|
||||
}
|
||||
3
imports/api/lib/grid/createObjectId.js
Normal file
3
imports/api/lib/grid/createObjectId.js
Normal file
@ -0,0 +1,3 @@
|
||||
import { MongoInternals } from 'meteor/mongo'
|
||||
|
||||
export const createObjectId = ({gridFsFileId}) => new MongoInternals.NpmModule.ObjectID(gridFsFileId);
|
||||
110
imports/api/lib/images.js
Normal file
110
imports/api/lib/images.js
Normal file
@ -0,0 +1,110 @@
|
||||
import { Meteor } from 'meteor/meteor';
|
||||
import { FilesCollection } from 'meteor/ostrio:files';
|
||||
import { createBucket } from '/imports/api/lib/grid/createBucket.js';
|
||||
import { createObjectId } from '/imports/api/lib/grid/createObjectId.js';
|
||||
import fs from 'fs';
|
||||
|
||||
let imagesBucket;
|
||||
if (Meteor.isServer) {
|
||||
imagesBucket = createBucket('allImages');
|
||||
}
|
||||
|
||||
const Images = new FilesCollection({
|
||||
collectionName: 'Images',
|
||||
allowClientCode: true,
|
||||
debug: Meteor.isServer && process.env.NODE_ENV === 'development',
|
||||
onBeforeUpload (file) {
|
||||
if (file.size <= 10485760 && /png|jpg|jpeg/i.test(file.extension)) {
|
||||
return true;
|
||||
}
|
||||
return 'Please upload image, with size equal or less than 10MB';
|
||||
},
|
||||
onAfterUpload (file) {
|
||||
const self = this;
|
||||
|
||||
// here you could manipulate your file
|
||||
// and create a new version, for example a scaled 'thumbnail'
|
||||
// ...
|
||||
|
||||
// then we read all versions we have got so far
|
||||
Object.keys(file.versions).forEach(versionName => {
|
||||
const metadata = { ...file.meta, versionName, fileId: file._id };
|
||||
fs.createReadStream(file.versions[ versionName ].path)
|
||||
|
||||
// this is where we upload the binary to the bucket
|
||||
.pipe(imagesBucket.openUploadStream(
|
||||
file.name,
|
||||
{
|
||||
contentType: file.type || 'binary/octet-stream',
|
||||
metadata
|
||||
}
|
||||
))
|
||||
|
||||
// and we unlink the file from the fs on any error
|
||||
// that occurred during the upload to prevent zombie files
|
||||
.on('error', err => {
|
||||
console.error(err);
|
||||
self.unlink(this.collection.findOne(file._id), versionName); // Unlink files from FS
|
||||
})
|
||||
|
||||
// once we are finished, we attach the gridFS Object id on the
|
||||
// FilesCollection document's meta section and finally unlink the
|
||||
// upload file from the filesystem
|
||||
.on('finish', Meteor.bindEnvironment(ver => {
|
||||
const property = `versions.${versionName}.meta.gridFsFileId`;
|
||||
self.collection.update(file._id, {
|
||||
$set: {
|
||||
[ property ]: ver._id.toHexString()
|
||||
}
|
||||
});
|
||||
self.unlink(this.collection.findOne(file._id), versionName); // Unlink files from FS
|
||||
}))
|
||||
})
|
||||
},
|
||||
interceptDownload (http, file, versionName) {
|
||||
const { gridFsFileId } = file.versions[ versionName ].meta || {};
|
||||
if (gridFsFileId) {
|
||||
const gfsId = createObjectId({ gridFsFileId });
|
||||
const readStream = imagesBucket.openDownloadStream(gfsId);
|
||||
readStream.on('data', (data) => {
|
||||
http.response.write(data);
|
||||
})
|
||||
|
||||
readStream.on('end', () => {
|
||||
http.response.end('end');
|
||||
})
|
||||
|
||||
readStream.on('error', () => {
|
||||
// not found probably
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
http.response.statusCode = 404;
|
||||
http.response.end('not found');
|
||||
})
|
||||
|
||||
http.response.setHeader('Cache-Control', this.cacheControl);
|
||||
http.response.setHeader('Content-Disposition', `inline; filename="${file.name}"`);
|
||||
}
|
||||
return Boolean(gridFsFileId) // Serve file from either GridFS or FS if it wasn't uploaded yet
|
||||
},
|
||||
onAfterRemove (files) {
|
||||
files.forEach(file => {
|
||||
Object.keys(file.versions).forEach(versionName => {
|
||||
const gridFsFileId = (file.versions[ versionName ].meta || {}).gridFsFileId;
|
||||
if (gridFsFileId) {
|
||||
const gfsId = createObjectId({ gridFsFileId });
|
||||
imagesBucket.delete(gfsId, err => { if (err) console.error(err); });
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
if (Meteor.isClient) {
|
||||
Meteor.subscribe('files.images.all');
|
||||
}
|
||||
|
||||
if (Meteor.isServer) {
|
||||
Meteor.publish('files.images.all', () => Images.collection.find({}));
|
||||
}
|
||||
|
||||
export { Images };
|
||||
62
imports/api/lib/persons.js
Normal file
62
imports/api/lib/persons.js
Normal file
@ -0,0 +1,62 @@
|
||||
import { Mongo } from 'meteor/mongo';
|
||||
import { Images } from './images.js';
|
||||
// import SimpleSchema from 'simpl-schema';
|
||||
|
||||
// SimpleSchema.extendOptions(['autoform']);
|
||||
// SimpleSchema.setDefaultMessages({
|
||||
// initialLanguage: 'en',
|
||||
// messages: {
|
||||
// en: {
|
||||
// uploadError: '{{{value}}}'
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
|
||||
const Persons = new Mongo.Collection('persons');
|
||||
|
||||
Persons.helpers({
|
||||
profilePic() {
|
||||
return Images.find({_id: this.profilePicId});
|
||||
},
|
||||
backgroundPic() {
|
||||
return Images.find({_id: this.backgroundPicId});
|
||||
}
|
||||
});
|
||||
|
||||
// Persons.attachSchema({
|
||||
// name: {
|
||||
// type: String,
|
||||
// label: 'Name'
|
||||
// },
|
||||
// profilePicId: {
|
||||
// type: String,
|
||||
// label: 'Profile Pic Id',
|
||||
// autoform: {
|
||||
// afFieldInput: {
|
||||
// type: 'fileUpload',
|
||||
// collection: 'Images',
|
||||
// insertConfig: {
|
||||
// transport: 'http'
|
||||
// },
|
||||
// uploadTemplate: 'uploadField', // <- Optional
|
||||
// previewTemplate: 'uploadPreview', // <- Optional,
|
||||
// }
|
||||
// }
|
||||
// },
|
||||
// backgroundPicId: {
|
||||
// type: String,
|
||||
// label: 'Background Pic Id',
|
||||
// autoform: {
|
||||
// afFieldInput: {
|
||||
// type: 'fileUpload',
|
||||
// collection: 'Images',
|
||||
// accept: '.png,.jpg,.jpeg', // use built-in accept config
|
||||
// insertConfig: {
|
||||
// transport: 'http'
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
|
||||
export { Persons };
|
||||
@ -47,7 +47,7 @@ const useLongPress = (mostraMenu, setMostraMenu) => {
|
||||
if (isPressed) {
|
||||
setIsPressed(false);
|
||||
// Clear any pending timeout
|
||||
clearTimeout(timeoutId?.current);
|
||||
// clearTimeout(timeoutId?.current);
|
||||
}
|
||||
};
|
||||
|
||||
@ -69,6 +69,7 @@ const useLongPress = (mostraMenu, setMostraMenu) => {
|
||||
|
||||
}
|
||||
}, 500);
|
||||
// return () => clearTimeout(timeoutId);
|
||||
}
|
||||
|
||||
return () => clearTimeout(timeoutId);
|
||||
@ -248,7 +249,7 @@ const UserStat = ({esAdministrador, setEsAdministrador}) => {
|
||||
left: 0,
|
||||
top: `5em`,
|
||||
padding: `.4em .5em`,
|
||||
border: `1px #aaa`,
|
||||
border: `1px solid #aaa`,
|
||||
cursor: `pointer`,
|
||||
zIndex: `200`
|
||||
}}
|
||||
|
||||
@ -1,14 +1,46 @@
|
||||
import React, { useState } from 'react';
|
||||
import React, { useState, useEffect, useRef } from 'react';
|
||||
import { Accounts } from 'meteor/accounts-base';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { Meteor } from 'meteor/meteor';
|
||||
import { useTracker, useSubscribe, useFind } from 'meteor/react-meteor-data/suspense';
|
||||
import { Roles } from 'meteor/roles';
|
||||
import { ROLS_GLOBALS } from '../roles';
|
||||
import { Avatars } from '/imports/api/files.js';
|
||||
import AvatarFileUpload from '/imports/ui/files/AvatarFileUpload';
|
||||
|
||||
|
||||
export const Login = () => {
|
||||
const [isLogin, setIsLogin] = useState( { initialState: true } );
|
||||
const navigate = useNavigate();
|
||||
|
||||
// const avatarinput = useRef();
|
||||
|
||||
// const [avatarId, setAvatarId] = useState();
|
||||
// const [avatarLink, setAvatarLink] = useState();
|
||||
|
||||
// const [novaImg, setNovaImg] = useState(false);
|
||||
|
||||
// const [avatar, setAvatar] = useState(null);
|
||||
|
||||
// let files;
|
||||
|
||||
// useEffect(() => {
|
||||
|
||||
// useSubscribe('avatars.all');
|
||||
|
||||
// files = useFind(Avatars, [
|
||||
// {},
|
||||
// { sort: { createdAt: -1 } },
|
||||
// ]);
|
||||
|
||||
// }, []);
|
||||
|
||||
// const files = useTracker("avatars", () => {
|
||||
// return Avatars.find({}).fetchAsync();
|
||||
// });
|
||||
|
||||
|
||||
|
||||
const handleLogin = (e) => {
|
||||
e.preventDefault();
|
||||
// console.dir(e);
|
||||
@ -74,6 +106,8 @@ export const Login = () => {
|
||||
</form>
|
||||
}
|
||||
|
||||
|
||||
|
||||
return (
|
||||
<form
|
||||
action={async d => {
|
||||
@ -109,7 +143,11 @@ export const Login = () => {
|
||||
password2
|
||||
};
|
||||
|
||||
Meteor.callAsync('creaUsuariAmbCodi', uObj, codi);
|
||||
// Meteor.callAsync('creaUsuariAmbCodi', uObj, codi);
|
||||
|
||||
|
||||
|
||||
Meteor.callAsync('registraUsuariAmbAvatarICodi', uObj, codi, avatarinput.current);
|
||||
|
||||
// userId = await Accounts.createUser({
|
||||
// username,
|
||||
@ -163,7 +201,8 @@ export const Login = () => {
|
||||
backgroundColor: `#eeed`
|
||||
}}
|
||||
>
|
||||
Avatar: <img
|
||||
{/* Avatar:
|
||||
<img
|
||||
style={{
|
||||
width: `3em`,
|
||||
height: `3em`,
|
||||
@ -179,6 +218,41 @@ export const Login = () => {
|
||||
|
||||
}}
|
||||
/>
|
||||
|
||||
<label
|
||||
htmlFor="avatarinput"
|
||||
style={{
|
||||
minWidth: `3em`,
|
||||
minHeight: `3em`,
|
||||
borderRadius: `50%`,
|
||||
border: `.6vh solid white`,
|
||||
display: `block`,
|
||||
// backgroundImage: `url(${link}), linear-gradient(to bottom right, transparent, #fffd)`,
|
||||
backgroundSize: `cover`,
|
||||
backgroundRepeat: `no-repeat`,
|
||||
margin: `0 auto -1.5em auto`,
|
||||
aspectRatio: `1/1`
|
||||
}}
|
||||
></label> */}
|
||||
|
||||
|
||||
{/* <input type="file"
|
||||
name="avatarinput"
|
||||
id="avatarinput"
|
||||
disabled={inProgress}
|
||||
ref={avatarinput}
|
||||
onChange={uploadIt}
|
||||
style={{
|
||||
position: `relative`,
|
||||
zIndex: `-1`,
|
||||
opacity: '0'
|
||||
}}
|
||||
accept="image/gif, image/jpeg, image/png"
|
||||
/> */}
|
||||
<hr />
|
||||
<AvatarFileUpload />
|
||||
<hr />
|
||||
|
||||
<br />
|
||||
<label htmlFor="username">Nom d'usuari: </label>
|
||||
<input id="username" name="username" type="text" required />
|
||||
|
||||
226
imports/ui/files/AvatarFileUpload.jsx
Normal file
226
imports/ui/files/AvatarFileUpload.jsx
Normal file
@ -0,0 +1,226 @@
|
||||
import { useTracker, useSubscribe, useFind } from 'meteor/react-meteor-data/suspense';
|
||||
import { Meteor } from 'meteor/meteor';
|
||||
import React, { useState, useRef, Suspense } from 'react';
|
||||
// import PropTypes from 'prop-types';
|
||||
import { Avatars } from '/imports/api/files.js';
|
||||
|
||||
import IndividualFileStart from '/imports/ui/files/IndividualFile.jsx'; // <-------------------------
|
||||
|
||||
import _ from 'lodash';
|
||||
|
||||
//const debug = require('debug')('demo:file');
|
||||
|
||||
const AvatarFileUpload = (props) => {
|
||||
|
||||
const [uploading, setUploading] = useState([]);
|
||||
const [progress, setProgress] = useState(0);
|
||||
const [inProgress, setInProgress] = useState(false);
|
||||
|
||||
const [preview, setPreview] = useState("");
|
||||
|
||||
// const reseter = useState(0);
|
||||
|
||||
// const refForm = useRef();
|
||||
const fileinput = useRef();
|
||||
|
||||
useSubscribe('avatars.all');
|
||||
|
||||
const files = useFind(Avatars, [
|
||||
{},
|
||||
{ sort: { createdAt: -1 } },
|
||||
]);
|
||||
|
||||
// const files = useTracker("avatars", async () => {
|
||||
// // const docsReadyYet = filesHandle.ready();
|
||||
// const files = await Avatars?.find({meta:{userId: props.uidProvisional || Meteor.userId(), entId: props.entId}}, {sort: {name: 1}})//.fetchAsync(); // Meteor.userId() ?? "nop"
|
||||
|
||||
// return files;
|
||||
// }, []);
|
||||
|
||||
function uploadIt(e) {
|
||||
e.preventDefault();
|
||||
|
||||
//let self = this;
|
||||
|
||||
if (e.currentTarget.files && e.currentTarget.files[0]) {
|
||||
// We upload only one file, in case
|
||||
// there was multiple files selected
|
||||
var file = e.currentTarget.files[0];
|
||||
|
||||
const reader = new FileReader();
|
||||
|
||||
reader.onload = (event) => {
|
||||
console.log("eventTarget: ", event.target);
|
||||
setPreview(event.target.result);
|
||||
};
|
||||
|
||||
reader.readAsDataURL(file);
|
||||
|
||||
// setPreview(file);
|
||||
|
||||
if (file) {
|
||||
let uploadInstance = Avatars.insert({
|
||||
file,
|
||||
meta: {
|
||||
locator: props.fileLocator,
|
||||
userId: props.uidProvisional || Meteor.userId(), // Optional, used to check on server for file tampering
|
||||
entId: props.entId
|
||||
},
|
||||
chunkSize: 'dynamic',
|
||||
allowWebWorkers: true // If you see issues with uploads, change this to false
|
||||
}, false)
|
||||
|
||||
setUploading(uploadInstance); // Keep track of this instance to use below
|
||||
setInProgress(true); // Show the progress bar now
|
||||
|
||||
// These are the event functions, don't need most of them, it shows where we are in the process
|
||||
uploadInstance.on('start', function () {
|
||||
console.log('Starting');
|
||||
})
|
||||
|
||||
uploadInstance.on('end', function (error, fileObj) {
|
||||
console.log('On end File Object: ', fileObj);
|
||||
})
|
||||
|
||||
uploadInstance.on('uploaded', function (error, fileObj) {
|
||||
console.log('uploaded: ', fileObj);
|
||||
|
||||
// props.setUpId(fileObj._id);
|
||||
|
||||
// Remove the filename from the upload box
|
||||
fileinput.current.value = '';
|
||||
|
||||
// Reset our state for the next file
|
||||
setUploading([]);
|
||||
setProgress(0);
|
||||
setInProgress(false);
|
||||
})
|
||||
|
||||
uploadInstance.on('error', function (error, fileObj) {
|
||||
console.log('Error during upload: ' + error)
|
||||
});
|
||||
|
||||
uploadInstance.on('progress', function (progress, fileObj) {
|
||||
console.log('Upload Percentage: ' + progress)
|
||||
// Update our progress bar
|
||||
setProgress(progress);
|
||||
});
|
||||
|
||||
uploadInstance.start(); // Must manually start the upload
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This is our progress bar, bootstrap styled
|
||||
// Remove this function if not needed
|
||||
function UploadingFile({preview}) {
|
||||
|
||||
// console.log('**********************************', uploading);
|
||||
|
||||
if (!_.isEmpty(uploading)) {
|
||||
// console.log("uploading: ", uploading);
|
||||
// console.log("preview: ", preview);
|
||||
return <div>
|
||||
<img
|
||||
src={preview}
|
||||
alt=""
|
||||
style={{
|
||||
border: `solid 3px #6666`,
|
||||
borderRadius: `50%`,
|
||||
width: `5rem`,
|
||||
margin: `0 auto`,
|
||||
display: `block`
|
||||
}}
|
||||
/>
|
||||
|
||||
<br />
|
||||
|
||||
{/* {uploading.file.name} */}
|
||||
|
||||
<div className="progress progress-bar-default">
|
||||
<div style={{width: progress + '%', backgroundColor: `lime`, borderRadius: `1rem`, textAlign: `center`, boxShadow: `inset 0 0 .5rem .5rem #4447`}} aria-valuemax="100"
|
||||
aria-valuemin="0"
|
||||
aria-valuenow={progress || 0} role="progressbar"
|
||||
className="progress-bar"
|
||||
>
|
||||
<span className="sr-only">{progress}% Complete (success)</span>
|
||||
{/* <span>{progress}%</span> */}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
|
||||
const Display = async () => await files?.map(async (aFile, key) => {
|
||||
|
||||
let link = await Avatars.findOneAsync({_id: aFile._id}); //The "view/download" link
|
||||
let linkOriginalURL = `${window.location.origin}${link._fileRef._downloadRoute}/${link._fileRef._collectionName}/${link._fileRef._id}/original/${link._fileRef._id}.${link._fileRef.extension}`;
|
||||
|
||||
// Send out components that show details of each file
|
||||
|
||||
return <Suspense fallback="<>Loading...</>">
|
||||
<div key={'file' + key}>
|
||||
<IndividualFileStart
|
||||
fileName={aFile.name}
|
||||
fileUrl={linkOriginalURL}
|
||||
fileId={aFile._id}
|
||||
fileSize={aFile.size}
|
||||
/>
|
||||
</div>
|
||||
</Suspense>
|
||||
}).reverse();
|
||||
|
||||
// Run through each file that the user has stored
|
||||
// (make sure the subscription only sends files owned by this user)
|
||||
// let display =
|
||||
|
||||
return <Suspense fallback="Loading...">
|
||||
|
||||
<button
|
||||
className='btArxiu'
|
||||
onClick={ev => {
|
||||
ev.preventDefault();
|
||||
|
||||
// refForm.current.reset();
|
||||
fileinput.current.click();
|
||||
//reseter[1](reseter[0] + 1);
|
||||
//refForm.current.reset();
|
||||
ev.target.value = null;
|
||||
}}
|
||||
>
|
||||
<span className="fa-solid fa-paperclip" >Add file</span>
|
||||
</button>
|
||||
|
||||
<input type="file"
|
||||
id="fileinput"
|
||||
disabled={inProgress}
|
||||
ref={fileinput}
|
||||
onChange={uploadIt}
|
||||
style={{display: `none`}}
|
||||
/>
|
||||
|
||||
<UploadingFile {...{preview}} />
|
||||
<Display />
|
||||
|
||||
</Suspense>
|
||||
// else return <div>Carregant llista d'arxius...</div>;
|
||||
};
|
||||
|
||||
//
|
||||
// This is the HOC - included in this file just for convenience, but usually kept
|
||||
// in a separate file to provide separation of concerns.
|
||||
//
|
||||
// export default withTracker( ( props ) => {
|
||||
|
||||
// const filesHandle = Meteor.subscribe('files.all');
|
||||
// const docsReadyYet = filesHandle.ready();
|
||||
// const files = Avatars.find({meta:{userId: props.uidProvisional || Meteor.userId()}}, {sort: {name: 1}}).fetch(); // Meteor.userId() ?? "nop"
|
||||
|
||||
// return {
|
||||
// docsReadyYet,
|
||||
// files,
|
||||
// };
|
||||
|
||||
// })(FileUploadComponent);
|
||||
|
||||
export default AvatarFileUpload;
|
||||
82
imports/ui/files/AvatarIndividualFile.jsx
Normal file
82
imports/ui/files/AvatarIndividualFile.jsx
Normal file
@ -0,0 +1,82 @@
|
||||
import React from 'react';
|
||||
// import PropTypes from 'prop-types';
|
||||
|
||||
const AvatarIndividualFile = props => {
|
||||
|
||||
// propTypes: {
|
||||
// fileName: PropTypes.string.isRequired,
|
||||
// fileSize: PropTypes.number.isRequired,
|
||||
// fileUrl: PropTypes.string,
|
||||
// fileId: PropTypes.string.isRequired
|
||||
// }
|
||||
|
||||
function removeFile(){
|
||||
let conf = confirm('Are you sure you want to delete the file?') || false;
|
||||
if (conf == true) {
|
||||
Meteor.call('RemoveFile', props.fileId, function (err, res) {
|
||||
if (err)
|
||||
console.log(err);
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
function renameFile(){
|
||||
|
||||
let validName = /[^a-zA-Z0-9 \.:\+()\-_%!&]/gi;
|
||||
let prompt = window.prompt('New file name?', props.fileName);
|
||||
|
||||
// Replace any non valid characters, also do this on the server
|
||||
if (prompt) {
|
||||
prompt = prompt.replace(validName, '-');
|
||||
prompt.trim();
|
||||
}
|
||||
|
||||
if (!_.isEmpty(prompt)) {
|
||||
Meteor.call('RenameFile', props.fileId, prompt, function (err, res) {
|
||||
if (err)
|
||||
console.log(err);
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return <div className="m-t-sm">
|
||||
<img
|
||||
src={props.fileUrl}
|
||||
alt={props.fileName}
|
||||
style={{maxWidth: `200px`, maxHeight: `200px`}}
|
||||
/>
|
||||
|
||||
<div className="row">
|
||||
<div className="col-md-12">
|
||||
<strong>{props.fileName}</strong>
|
||||
<div className="m-b-sm">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* <div className="row">
|
||||
<div className="col-md-3">
|
||||
<button onClick={renameFile} className="btn btn-outline btn-primary btn-sm">
|
||||
Rename
|
||||
</button>
|
||||
</div>
|
||||
|
||||
|
||||
<div className="col-md-3">
|
||||
<a href={props.fileUrl} className="btn btn-outline btn-primary btn-sm"
|
||||
target="_blank">View</a>
|
||||
</div>
|
||||
|
||||
<div className="col-md-2">
|
||||
<button onClick={removeFile} className="btn btn-outline btn-danger btn-sm">
|
||||
Delete
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="col-md-4">
|
||||
Size: {props.fileSize}
|
||||
</div>
|
||||
</div> */}
|
||||
</div>
|
||||
}
|
||||
export default AvatarIndividualFile;
|
||||
204
imports/ui/files/FileUpload.jsx
Normal file
204
imports/ui/files/FileUpload.jsx
Normal file
@ -0,0 +1,204 @@
|
||||
import { useSubscribe, useFind, useTracker } from 'meteor/react-meteor-data';
|
||||
import { Meteor } from 'meteor/meteor';
|
||||
import React, { useState, useRef } from 'react';
|
||||
// import PropTypes from 'prop-types';
|
||||
import { FilesCol } from '/imports/api/files.js';
|
||||
|
||||
import IndividualFile from '/imports/ui/files/IndividualFile.jsx';
|
||||
|
||||
import _ from 'lodash';
|
||||
|
||||
// const debug = require('debug')('demo:file');
|
||||
|
||||
const FileUploadComponent = (props) => {
|
||||
|
||||
const [uploading, setUploading] = useState([]);
|
||||
const [progress, setProgress] = useState(0);
|
||||
const [inProgress, setInProgress] = useState(false);
|
||||
|
||||
const fileinput = useRef();
|
||||
|
||||
const isLoading = useSubscribe('files.all');
|
||||
|
||||
const files = useTracker(() => {
|
||||
// const filesHandle = Meteor.subscribe('files.all');
|
||||
// const docsReadyYet = filesHandle.ready();
|
||||
//const files = FilesCol?.find({meta:{userId: props.uidProvisional || Meteor.userId()}}, {sort: {name: 1}}); // Meteor.userId() ?? "nop"
|
||||
|
||||
console.dir("files from FU: ", files.cursor);
|
||||
|
||||
return files;
|
||||
}, [isLoading()]);
|
||||
|
||||
|
||||
|
||||
console.dir("fufiles: ", files);
|
||||
|
||||
|
||||
function uploadIt(e) {
|
||||
e.preventDefault();
|
||||
|
||||
//let self = this;
|
||||
|
||||
if (e.currentTarget.files && e.currentTarget.files[0]) {
|
||||
// We upload only one file, in case
|
||||
// there was multiple files selected
|
||||
var file = e.currentTarget.files[0];
|
||||
|
||||
if (file) {
|
||||
let uploadInstance = FilesCol.insertAsync({
|
||||
file,
|
||||
meta: {
|
||||
locator: props.fileLocator,
|
||||
userId: props.uidProvisional || Meteor.userId() // Optional, used to check on server for file tampering
|
||||
},
|
||||
chunkSize: 'dynamic',
|
||||
allowWebWorkers: true // If you see issues with uploads, change this to false
|
||||
}, false)
|
||||
|
||||
setUploading(uploadInstance); // Keep track of this instance to use below
|
||||
setInProgress(true);// Show the progress bar now
|
||||
|
||||
// These are the event functions, don't need most of them, it shows where we are in the process
|
||||
uploadInstance.on('start', function () {
|
||||
console.log('Starting');
|
||||
})
|
||||
|
||||
uploadInstance.on('end', function (error, fileObj) {
|
||||
console.log('On end File Object: ', fileObj);
|
||||
})
|
||||
|
||||
uploadInstance.on('uploaded', function (error, fileObj) {
|
||||
// console.dir("uploaded: this ", this.config.fileId);
|
||||
// console.log('uploaded: ', fileObj);
|
||||
|
||||
// console.log("upError: ", error);
|
||||
props?.setUpId(fileObj?.config.fileId);
|
||||
|
||||
// Remove the filename from the upload box
|
||||
fileinput.current.value = '';
|
||||
|
||||
// Reset our state for the next file
|
||||
setUploading([]);
|
||||
setProgress(0);
|
||||
setInProgress(false);
|
||||
})
|
||||
|
||||
uploadInstance.on('error', function (error, fileObj) {
|
||||
console.log('Error during upload: ' + error)
|
||||
});
|
||||
|
||||
uploadInstance.on('progress', function (progress, fileObj) {
|
||||
console.log('Upload Percentage: ' + progress)
|
||||
// Update our progress bar
|
||||
setProgress(progress);
|
||||
});
|
||||
|
||||
uploadInstance.start(); // Must manually start the upload
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This is our progress bar, bootstrap styled
|
||||
// Remove this function if not needed
|
||||
function showUploads() {
|
||||
console.log('**********************************', uploading);
|
||||
|
||||
if (!_.isEmpty(uploading)) {
|
||||
return <div>
|
||||
{uploading.file.name}
|
||||
|
||||
<div className="progress progress-bar-default">
|
||||
<div style={{width: progress + '%'}} aria-valuemax="100"
|
||||
aria-valuemin="0"
|
||||
aria-valuenow={progress || 0} role="progressbar"
|
||||
className="progress-bar"
|
||||
>
|
||||
<span className="sr-only">{progress}% Complete (success)</span>
|
||||
<span>{progress}%</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
// debug("Rendering FileUpload",docsReadyYet);
|
||||
// if(!isLoading() && files)
|
||||
//if (files /* && docsReadyYet*/) {
|
||||
{
|
||||
console.dir("FUfiles: ", files);
|
||||
//let fileCursors = files;
|
||||
|
||||
// console.dir("fileCursors: ", fileCursors);
|
||||
|
||||
// Run through each file that the user has stored
|
||||
// (make sure the subscription only sends files owned by this user)
|
||||
let display = files?.map(async (aFile, key) => {
|
||||
console.log('A file: ', aFile.link(), aFile.get('name'))
|
||||
let link = await FilesCol.findOneAsync({_id: aFile._id}).link(); //The "view/download" link
|
||||
|
||||
console.log("link: ", link);
|
||||
|
||||
// Send out components that show details of each file
|
||||
return <div key={'file' + key}>
|
||||
<IndividualFile
|
||||
fileName={aFile.name}
|
||||
fileUrl={link}
|
||||
fileId={aFile._id}
|
||||
fileSize={aFile.size}
|
||||
/>
|
||||
</div>
|
||||
})
|
||||
|
||||
return <div>
|
||||
|
||||
<div className="row">
|
||||
<div className="col-md-12">
|
||||
<p>Upload New File:</p>
|
||||
<input type="file"
|
||||
id="fileinput"
|
||||
disabled={inProgress}
|
||||
ref={fileinput}
|
||||
onChange={uploadIt}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="row m-t-sm m-b-sm">
|
||||
<div className="col-md-6">
|
||||
|
||||
{showUploads()}
|
||||
|
||||
</div>
|
||||
<div className="col-md-6">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{display}
|
||||
|
||||
</div>
|
||||
}
|
||||
// else return <div>Loading file list</div>;
|
||||
}
|
||||
};
|
||||
|
||||
//
|
||||
// This is the HOC - included in this file just for convenience, but usually kept
|
||||
// in a separate file to provide separation of concerns.
|
||||
//
|
||||
// export default withTracker( ( props ) => {
|
||||
|
||||
// const filesHandle = Meteor.subscribe('files.all');
|
||||
// const docsReadyYet = filesHandle.ready();
|
||||
// const files = FilesCol.find({meta:{userId: props.uidProvisional || Meteor.userId()}}, {sort: {name: 1}}).fetch(); // Meteor.userId() ?? "nop"
|
||||
|
||||
// return {
|
||||
// docsReadyYet,
|
||||
// files,
|
||||
// };
|
||||
|
||||
// })(FileUploadComponent);
|
||||
|
||||
export default FileUploadComponent;
|
||||
208
imports/ui/files/FileUploadAdmin.jsx
Normal file
208
imports/ui/files/FileUploadAdmin.jsx
Normal file
@ -0,0 +1,208 @@
|
||||
import { useTracker } from 'meteor/react-meteor-data';
|
||||
import { Meteor } from 'meteor/meteor';
|
||||
import React, { useState, useRef } from 'react';
|
||||
// import PropTypes from 'prop-types';
|
||||
import { FilesCol } from '/imports/api/files.js';
|
||||
import IndividualFile from '/imports/ui/files/IndividualFile.jsx';
|
||||
import _ from 'lodash';
|
||||
// import { useUser } from 'meteor/react-meteor-accounts';
|
||||
// import { Roles } from 'meteor/alanning:roles';
|
||||
// import { GLOBAL_ROLES } from '../roles';
|
||||
// import { useTracker } from 'meteor/react-meteor-data';
|
||||
|
||||
//const debug = require('debug')('demo:file');
|
||||
|
||||
const FileUploadAdmin = (props) => {
|
||||
|
||||
// const user = useUser();
|
||||
// const isAdmin = useTracker(() => Roles.userIsInRole(user?._id, GLOBAL_ROLES.ADMIN));
|
||||
|
||||
const [uploading, setUploading] = useState([]);
|
||||
const [progress, setProgress] = useState(0);
|
||||
const [inProgress, setInProgress] = useState(false);
|
||||
|
||||
const reseter = useState(0);
|
||||
|
||||
const refForm = useRef();
|
||||
const fileinput = useRef();
|
||||
|
||||
const files = useTracker(() => {
|
||||
const filesHandle = Meteor.subscribe('files.all');
|
||||
// const docsReadyYet = filesHandle.ready();
|
||||
const files = FilesCol?.find({meta:{userId: props.uidProvisional || Meteor.userId(), entId: props.entId}}, {sort: {name: 1}}).fetch(); // Meteor.userId() ?? "nop"
|
||||
|
||||
return files;
|
||||
});
|
||||
|
||||
|
||||
|
||||
function uploadIt(e) {
|
||||
e.preventDefault();
|
||||
|
||||
//let self = this;
|
||||
|
||||
if (e.currentTarget.files && e.currentTarget.files[0]) {
|
||||
// We upload only one file, in case
|
||||
// there was multiple files selected
|
||||
var file = e.currentTarget.files[0];
|
||||
|
||||
if (file) {
|
||||
let uploadInstance = FilesCol.insert({
|
||||
file,
|
||||
meta: {
|
||||
locator: props.fileLocator,
|
||||
userId: props.uidProvisional || Meteor.userId(), // Optional, used to check on server for file tampering
|
||||
entId: props.entId
|
||||
},
|
||||
chunkSize: 'dynamic',
|
||||
allowWebWorkers: true // If you see issues with uploads, change this to false
|
||||
}, false)
|
||||
|
||||
setUploading(uploadInstance); // Keep track of this instance to use below
|
||||
setInProgress(true); // Show the progress bar now
|
||||
|
||||
// These are the event functions, don't need most of them, it shows where we are in the process
|
||||
uploadInstance.on('start', function () {
|
||||
console.log('Starting');
|
||||
})
|
||||
|
||||
uploadInstance.on('end', function (error, fileObj) {
|
||||
console.log('On end File Object: ', fileObj);
|
||||
})
|
||||
|
||||
uploadInstance.on('uploaded', function (error, fileObj) {
|
||||
console.log('uploaded: ', fileObj);
|
||||
|
||||
// props.setUpId(fileObj._id);
|
||||
|
||||
// Remove the filename from the upload box
|
||||
fileinput.current.value = '';
|
||||
|
||||
// Reset our state for the next file
|
||||
setUploading([]);
|
||||
setProgress(0);
|
||||
setInProgress(false);
|
||||
})
|
||||
|
||||
uploadInstance.on('error', function (error, fileObj) {
|
||||
console.log('Error during upload: ' + error)
|
||||
});
|
||||
|
||||
uploadInstance.on('progress', function (progress, fileObj) {
|
||||
console.log('Upload Percentage: ' + progress)
|
||||
// Update our progress bar
|
||||
setProgress(progress);
|
||||
});
|
||||
|
||||
uploadInstance.start(); // Must manually start the upload
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This is our progress bar, bootstrap styled
|
||||
// Remove this function if not needed
|
||||
function showUploads() {
|
||||
console.log('**********************************', uploading);
|
||||
|
||||
if (!_.isEmpty(uploading)) {
|
||||
return <div>
|
||||
{uploading.file.name}
|
||||
|
||||
<div className="progress progress-bar-default">
|
||||
<div style={{width: progress + '%'}} aria-valuemax="100"
|
||||
aria-valuemin="0"
|
||||
aria-valuenow={progress || 0} role="progressbar"
|
||||
className="progress-bar">
|
||||
<span className="sr-only">{progress}% Complete (success)</span>
|
||||
<span>{progress}%</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
// debug("Rendering FileUpload",docsReadyYet);
|
||||
if (files /* && docsReadyYet*/) {
|
||||
|
||||
let fileCursors = files;
|
||||
|
||||
// Run through each file that the user has stored
|
||||
// (make sure the subscription only sends files owned by this user)
|
||||
let display = fileCursors.map((aFile, key) => {
|
||||
// console.log('A file: ', aFile.link(), aFile.get('name'))
|
||||
let link = FilesCol.findOne({_id: aFile._id}).link(); //The "view/download" link
|
||||
|
||||
// Send out components that show details of each file
|
||||
return <div key={'file' + key}>
|
||||
<IndividualFile
|
||||
fileName={aFile.name}
|
||||
fileUrl={link}
|
||||
fileId={aFile._id}
|
||||
fileSize={aFile.size}
|
||||
/>
|
||||
</div>
|
||||
})
|
||||
|
||||
return <>
|
||||
|
||||
|
||||
<button
|
||||
className='btArxiu'
|
||||
onClick={ev => {
|
||||
ev.preventDefault();
|
||||
|
||||
// refForm.current.reset();
|
||||
fileinput.current.click();
|
||||
//reseter[1](reseter[0] + 1);
|
||||
//refForm.current.reset();
|
||||
ev.target.value = null;
|
||||
}}
|
||||
>
|
||||
<span className="fas fa-paperclip" />
|
||||
</button>
|
||||
|
||||
<input type="file"
|
||||
id="fileinput"
|
||||
disabled={inProgress}
|
||||
ref={fileinput}
|
||||
onChange={uploadIt}
|
||||
style={{display: `none`}}
|
||||
/>
|
||||
|
||||
|
||||
{/* <div className="row m-t-sm m-b-sm">
|
||||
<div className="col-md-6">
|
||||
|
||||
{showUploads()}
|
||||
|
||||
</div>
|
||||
</div> */}
|
||||
|
||||
{/* {display} */}
|
||||
|
||||
</>
|
||||
}
|
||||
else return <div>Carregant llista d'arxius...</div>;
|
||||
}
|
||||
};
|
||||
|
||||
//
|
||||
// This is the HOC - included in this file just for convenience, but usually kept
|
||||
// in a separate file to provide separation of concerns.
|
||||
//
|
||||
// export default withTracker( ( props ) => {
|
||||
|
||||
// const filesHandle = Meteor.subscribe('files.all');
|
||||
// const docsReadyYet = filesHandle.ready();
|
||||
// const files = FilesCol.find({meta:{userId: props.uidProvisional || Meteor.userId()}}, {sort: {name: 1}}).fetch(); // Meteor.userId() ?? "nop"
|
||||
|
||||
// return {
|
||||
// docsReadyYet,
|
||||
// files,
|
||||
// };
|
||||
|
||||
// })(FileUploadComponent);
|
||||
|
||||
export default FileUploadAdmin;
|
||||
203
imports/ui/files/FileUploadEnt.jsx
Normal file
203
imports/ui/files/FileUploadEnt.jsx
Normal file
@ -0,0 +1,203 @@
|
||||
import { useTracker } from 'meteor/react-meteor-data';
|
||||
import { Meteor } from 'meteor/meteor';
|
||||
import React, { useState, useRef } from 'react';
|
||||
// import PropTypes from 'prop-types';
|
||||
import { FilesCol } from '/imports/api/files.js';
|
||||
|
||||
import IndividualFile from '/imports/ui/files/IndividualFile.jsx';
|
||||
|
||||
import _ from 'lodash';
|
||||
|
||||
//const debug = require('debug')('demo:file');
|
||||
|
||||
const FileUploadEnt = (props) => {
|
||||
|
||||
const [uploading, setUploading] = useState([]);
|
||||
const [progress, setProgress] = useState(0);
|
||||
const [inProgress, setInProgress] = useState(false);
|
||||
|
||||
const reseter = useState(0);
|
||||
|
||||
const refForm = useRef();
|
||||
const fileinput = useRef();
|
||||
|
||||
const files = useTracker(() => {
|
||||
const filesHandle = Meteor.subscribe('files.all');
|
||||
// const docsReadyYet = filesHandle.ready();
|
||||
const files = FilesCol?.find({meta:{userId: props.uidProvisional || Meteor.userId(), entId: props.entId}}, {sort: {name: 1}}).fetch(); // Meteor.userId() ?? "nop"
|
||||
|
||||
return files;
|
||||
});
|
||||
|
||||
|
||||
|
||||
function uploadIt(e) {
|
||||
e.preventDefault();
|
||||
|
||||
//let self = this;
|
||||
|
||||
if (e.currentTarget.files && e.currentTarget.files[0]) {
|
||||
// We upload only one file, in case
|
||||
// there was multiple files selected
|
||||
var file = e.currentTarget.files[0];
|
||||
|
||||
if (file) {
|
||||
let uploadInstance = FilesCol.insert({
|
||||
file,
|
||||
meta: {
|
||||
locator: props.fileLocator,
|
||||
userId: props.uidProvisional || Meteor.userId(), // Optional, used to check on server for file tampering
|
||||
entId: props.entId
|
||||
},
|
||||
chunkSize: 'dynamic',
|
||||
allowWebWorkers: true // If you see issues with uploads, change this to false
|
||||
}, false)
|
||||
|
||||
setUploading(uploadInstance); // Keep track of this instance to use below
|
||||
setInProgress(true); // Show the progress bar now
|
||||
|
||||
// These are the event functions, don't need most of them, it shows where we are in the process
|
||||
uploadInstance.on('start', function () {
|
||||
console.log('Starting');
|
||||
})
|
||||
|
||||
uploadInstance.on('end', function (error, fileObj) {
|
||||
console.log('On end File Object: ', fileObj);
|
||||
})
|
||||
|
||||
uploadInstance.on('uploaded', function (error, fileObj) {
|
||||
console.log('uploaded: ', fileObj);
|
||||
|
||||
// props.setUpId(fileObj._id);
|
||||
|
||||
// Remove the filename from the upload box
|
||||
fileinput.current.value = '';
|
||||
|
||||
// Reset our state for the next file
|
||||
setUploading([]);
|
||||
setProgress(0);
|
||||
setInProgress(false);
|
||||
})
|
||||
|
||||
uploadInstance.on('error', function (error, fileObj) {
|
||||
console.log('Error during upload: ' + error)
|
||||
});
|
||||
|
||||
uploadInstance.on('progress', function (progress, fileObj) {
|
||||
console.log('Upload Percentage: ' + progress)
|
||||
// Update our progress bar
|
||||
setProgress(progress);
|
||||
});
|
||||
|
||||
uploadInstance.start(); // Must manually start the upload
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This is our progress bar, bootstrap styled
|
||||
// Remove this function if not needed
|
||||
function showUploads() {
|
||||
console.log('**********************************', uploading);
|
||||
|
||||
if (!_.isEmpty(uploading)) {
|
||||
return <div>
|
||||
{uploading.file.name}
|
||||
|
||||
<div className="progress progress-bar-default">
|
||||
<div style={{width: progress + '%'}} aria-valuemax="100"
|
||||
aria-valuemin="0"
|
||||
aria-valuenow={progress || 0} role="progressbar"
|
||||
className="progress-bar">
|
||||
<span className="sr-only">{progress}% Complete (success)</span>
|
||||
<span>{progress}%</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
// debug("Rendering FileUpload",docsReadyYet);
|
||||
if (files /* && docsReadyYet*/) {
|
||||
|
||||
let fileCursors = files;
|
||||
|
||||
// Run through each file that the user has stored
|
||||
// (make sure the subscription only sends files owned by this user)
|
||||
let display = fileCursors.map((aFile, key) => {
|
||||
// console.log('A file: ', aFile.link(), aFile.get('name'))
|
||||
let link = FilesCol.findOne({_id: aFile._id}).link(); //The "view/download" link
|
||||
|
||||
// Send out components that show details of each file
|
||||
return <div key={'file' + key}>
|
||||
<IndividualFile
|
||||
fileName={aFile.name}
|
||||
fileUrl={link}
|
||||
fileId={aFile._id}
|
||||
fileSize={aFile.size}
|
||||
/>
|
||||
</div>
|
||||
})
|
||||
|
||||
return <>
|
||||
|
||||
|
||||
<button
|
||||
className='btArxiu'
|
||||
onClick={ev => {
|
||||
ev.preventDefault();
|
||||
|
||||
// refForm.current.reset();
|
||||
fileinput.current.click();
|
||||
//reseter[1](reseter[0] + 1);
|
||||
//refForm.current.reset();
|
||||
ev.target.value = null;
|
||||
}}
|
||||
>
|
||||
<span className="fas fa-paperclip" />
|
||||
</button>
|
||||
|
||||
<input type="file"
|
||||
id="fileinput"
|
||||
disabled={inProgress}
|
||||
ref={fileinput}
|
||||
onChange={uploadIt}
|
||||
style={{display: `none`}}
|
||||
/>
|
||||
|
||||
|
||||
{/* <div className="row m-t-sm m-b-sm">
|
||||
<div className="col-md-6">
|
||||
|
||||
{showUploads()}
|
||||
|
||||
</div>
|
||||
</div> */}
|
||||
|
||||
{/* {display} */}
|
||||
|
||||
</>
|
||||
}
|
||||
else return <div>Carregant llista d'arxius...</div>;
|
||||
}
|
||||
};
|
||||
|
||||
//
|
||||
// This is the HOC - included in this file just for convenience, but usually kept
|
||||
// in a separate file to provide separation of concerns.
|
||||
//
|
||||
// export default withTracker( ( props ) => {
|
||||
|
||||
// const filesHandle = Meteor.subscribe('files.all');
|
||||
// const docsReadyYet = filesHandle.ready();
|
||||
// const files = FilesCol.find({meta:{userId: props.uidProvisional || Meteor.userId()}}, {sort: {name: 1}}).fetch(); // Meteor.userId() ?? "nop"
|
||||
|
||||
// return {
|
||||
// docsReadyYet,
|
||||
// files,
|
||||
// };
|
||||
|
||||
// })(FileUploadComponent);
|
||||
|
||||
export default FileUploadEnt;
|
||||
235
imports/ui/files/FileUploadPOI.jsx
Normal file
235
imports/ui/files/FileUploadPOI.jsx
Normal file
@ -0,0 +1,235 @@
|
||||
import { useTracker, useSubscribe, useFind } from 'meteor/react-meteor-data/suspense';
|
||||
import { Meteor } from 'meteor/meteor';
|
||||
import React, { useState, useRef, Suspense } from 'react';
|
||||
// import PropTypes from 'prop-types';
|
||||
import { FilesCol } from '/imports/api/files.js';
|
||||
|
||||
import IndividualFilePOI from '/imports/ui/files/IndividualFilePOI.jsx'; // <-------------------------
|
||||
|
||||
import _ from 'lodash';
|
||||
|
||||
//const debug = require('debug')('demo:file');
|
||||
|
||||
const useFiles = () => {
|
||||
useSubscribe('files.all');
|
||||
|
||||
const files = useTracker("files", () => FilesCol.find({}).fetchAsync(), []);
|
||||
|
||||
return files;
|
||||
};
|
||||
|
||||
|
||||
|
||||
const ShowUploads = ({uploading, progress, filePreviewURI, inProgress}) => {
|
||||
// console.log('**********************************', uploading);
|
||||
|
||||
if (!_.isEmpty(uploading)) {
|
||||
// console.log("uploading: ", uploading);
|
||||
return inProgress && <div style={{
|
||||
border: `1px solid`,
|
||||
borderRadius: `5px`,
|
||||
color: `#cccc`,
|
||||
padding: `1rem`,
|
||||
marginBottom: `1em`
|
||||
}}>
|
||||
{uploading.file.name}
|
||||
|
||||
<img src={filePreviewURI} />
|
||||
<div className="progress progress-bar-default">
|
||||
<div style={{width: progress + '%'}} aria-valuemax="100"
|
||||
aria-valuemin="0"
|
||||
aria-valuenow={progress || 0} role="progressbar"
|
||||
className="progress-bar"
|
||||
>
|
||||
<span className="sr-only">{progress}% Complete (success)</span>
|
||||
<span>{progress}%</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
const DisplayUploadFile = ({files}) => files?.map(async (aFile, key) => {
|
||||
|
||||
let link = await FilesCol.findOneAsync({_id: aFile._id}); //The "view/download" link
|
||||
let linkOriginalURL = `${window.location.origin}${link._fileRef._downloadRoute}/${link._fileRef._collectionName}/${link._fileRef._id}/original/${link._fileRef._id}.${link._fileRef.extension}`;
|
||||
|
||||
// Send out components that show details of each file
|
||||
|
||||
return <div key={'file' + key}>
|
||||
<IndividualFilePOI
|
||||
fileName={aFile.name}
|
||||
fileUrl={linkOriginalURL}
|
||||
fileId={aFile._id}
|
||||
fileSize={aFile.size}
|
||||
/>
|
||||
</div>;
|
||||
}).reverse();
|
||||
|
||||
|
||||
const FileUploadPOI = (props) => {
|
||||
|
||||
const [uploading, setUploading] = useState([]);
|
||||
const [progress, setProgress] = useState(0);
|
||||
const [inProgress, setInProgress] = useState(false);
|
||||
|
||||
const [filePreviewURI, setFilePreviewURI] = useState(null);
|
||||
|
||||
const fileinput = useRef();
|
||||
|
||||
const files = useFiles();
|
||||
|
||||
console.log("files: ", files);
|
||||
// console.log("fileinput: ", fileinput);
|
||||
|
||||
function uploadIt(e) {
|
||||
e.preventDefault();
|
||||
|
||||
console.log("UPLOADING IT");
|
||||
|
||||
if (e.currentTarget.files && e.currentTarget.files[0]) {
|
||||
// We upload only one file, in case
|
||||
// there was multiple files selected
|
||||
var file = e.currentTarget.files[0];
|
||||
|
||||
console.log("E: ", e);
|
||||
console.log("FILE: ", file);
|
||||
|
||||
if (file) {
|
||||
|
||||
let reader = new FileReader();
|
||||
|
||||
console.log("READER: ", reader);
|
||||
|
||||
// reader.onload = (evt) => {
|
||||
// console.log("ONLOAD: ", evt.target.result);
|
||||
// };
|
||||
reader.readAsDataURL(e.currentTarget.files[0]);
|
||||
|
||||
reader.onload = function(ev){
|
||||
|
||||
|
||||
console.log("ev.target.result: ", ev.target.result);
|
||||
|
||||
setFilePreviewURI(ev.target.result);
|
||||
|
||||
console.log("filePreviewURI: ", filePreviewURI);
|
||||
|
||||
|
||||
let uploadInstance = FilesCol.insert({
|
||||
file,
|
||||
meta: {
|
||||
locator: props.fileLocator,
|
||||
userId: props.uidProvisional || Meteor.userId(), // Optional, used to check on server for file tampering
|
||||
entId: props.entId
|
||||
},
|
||||
chunkSize: 'dynamic',
|
||||
allowWebWorkers: true // If you see issues with uploads, change this to false
|
||||
}, false)
|
||||
|
||||
setUploading(uploadInstance); // Keep track of this instance to use below
|
||||
console.log("setInProgress: true");
|
||||
setInProgress(true); // Show the progress bar now
|
||||
|
||||
// These are the event functions, don't need most of them, it shows where we are in the process
|
||||
uploadInstance.on('start', function () {
|
||||
console.log('Starting');
|
||||
console.log("file: ", file);
|
||||
})
|
||||
|
||||
uploadInstance.on('End', function (error, fileObj) {
|
||||
console.log('On end File Object: ', fileObj);
|
||||
setProgress(0);
|
||||
console.log("setInProgress: false");
|
||||
setInProgress(false);
|
||||
})
|
||||
|
||||
uploadInstance.on('uploaded', function (error, fileObj) {
|
||||
console.log('uploaded: ', fileObj);
|
||||
|
||||
// props.setUpId(fileObj._id);
|
||||
|
||||
// Remove the filename from the upload box
|
||||
fileinput.current.value = '';
|
||||
|
||||
// Reset our state for the next file
|
||||
setUploading([]);
|
||||
setProgress(0);
|
||||
console.log("setInProgress: false");
|
||||
setInProgress(false);
|
||||
})
|
||||
|
||||
uploadInstance.on('error', function (error, fileObj) {
|
||||
console.log('Error during upload: ' + error)
|
||||
console.log("setInProgress: false");
|
||||
setInProgress(false);
|
||||
});
|
||||
|
||||
uploadInstance.on('progress', function (progress, fileObj) {
|
||||
console.log('Upload Percentage: ' + progress)
|
||||
// Update our progress bar
|
||||
setProgress(progress);
|
||||
if (progress === 100) {
|
||||
console.log("setInProgress: false");
|
||||
setInProgress(false);
|
||||
}
|
||||
});
|
||||
|
||||
uploadInstance.start(); // Must manually start the upload
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return <>
|
||||
|
||||
<button
|
||||
className='btArxiu'
|
||||
onClick={ev => {
|
||||
ev.preventDefault();
|
||||
ev.stopPropagation();
|
||||
|
||||
// refForm.current.reset();
|
||||
fileinput.current.click();
|
||||
//reseter[1](reseter[0] + 1);
|
||||
//refForm.current.reset();
|
||||
// ev.target.value = null;
|
||||
}}
|
||||
>
|
||||
<span className="fa-solid fa-image" >Add file</span>
|
||||
</button>
|
||||
|
||||
<input type="file"
|
||||
id="fileinput"
|
||||
disabled={inProgress}
|
||||
ref={fileinput}
|
||||
onChange={() => {
|
||||
setInProgress(true);
|
||||
}}
|
||||
style={{display: `none`}}
|
||||
name="fileinput"
|
||||
onClick={(ev) => {
|
||||
// ev.preventDefault();
|
||||
ev.stopPropagation();
|
||||
}}
|
||||
/>
|
||||
|
||||
<br /><br />
|
||||
|
||||
<div className="row m-t-sm m-b-sm">
|
||||
<div className="col-md-6">
|
||||
|
||||
<ShowUploads progress={progress} filePreviewURI={filePreviewURI} uploading={uploading} inProgress={inProgress} />
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<DisplayUploadFile files={files} />
|
||||
|
||||
</>;
|
||||
// else return <div>Carregant llista d'arxius...</div>;
|
||||
};
|
||||
|
||||
export default FileUploadPOI;
|
||||
196
imports/ui/files/FileUploadStart.jsx
Normal file
196
imports/ui/files/FileUploadStart.jsx
Normal file
@ -0,0 +1,196 @@
|
||||
import { useTracker, useSubscribe, useFind } from 'meteor/react-meteor-data/suspense';
|
||||
import { Meteor } from 'meteor/meteor';
|
||||
import React, { useState, useRef, Suspense } from 'react';
|
||||
// import PropTypes from 'prop-types';
|
||||
import { FilesCol } from '/imports/api/files.js';
|
||||
|
||||
import IndividualFileStart from '/imports/ui/files/IndividualFile.jsx'; // <-------------------------
|
||||
|
||||
import _ from 'lodash';
|
||||
|
||||
//const debug = require('debug')('demo:file');
|
||||
|
||||
const FileUploadStart = (props) => {
|
||||
|
||||
const [uploading, setUploading] = useState([]);
|
||||
const [progress, setProgress] = useState(0);
|
||||
const [inProgress, setInProgress] = useState(false);
|
||||
|
||||
const reseter = useState(0);
|
||||
|
||||
const refForm = useRef();
|
||||
const fileinput = useRef();
|
||||
|
||||
useSubscribe('files.all');
|
||||
|
||||
const files = useTracker("files", async () => {
|
||||
// const docsReadyYet = filesHandle.ready();
|
||||
const files = await FilesCol?.find({meta:{userId: props.uidProvisional || Meteor.userId(), entId: props.entId}}, {sort: {name: 1}})//.fetchAsync(); // Meteor.userId() ?? "nop"
|
||||
|
||||
return files;
|
||||
}, []);
|
||||
|
||||
function uploadIt(e) {
|
||||
e.preventDefault();
|
||||
|
||||
//let self = this;
|
||||
|
||||
if (e.currentTarget.files && e.currentTarget.files[0]) {
|
||||
// We upload only one file, in case
|
||||
// there was multiple files selected
|
||||
var file = e.currentTarget.files[0];
|
||||
|
||||
if (file) {
|
||||
let uploadInstance = FilesCol.insert({
|
||||
file,
|
||||
meta: {
|
||||
locator: props.fileLocator,
|
||||
userId: props.uidProvisional || Meteor.userId(), // Optional, used to check on server for file tampering
|
||||
entId: props.entId
|
||||
},
|
||||
chunkSize: 'dynamic',
|
||||
allowWebWorkers: true // If you see issues with uploads, change this to false
|
||||
}, false)
|
||||
|
||||
setUploading(uploadInstance); // Keep track of this instance to use below
|
||||
setInProgress(true); // Show the progress bar now
|
||||
|
||||
// These are the event functions, don't need most of them, it shows where we are in the process
|
||||
uploadInstance.on('start', function () {
|
||||
console.log('Starting');
|
||||
})
|
||||
|
||||
uploadInstance.on('end', function (error, fileObj) {
|
||||
console.log('On end File Object: ', fileObj);
|
||||
})
|
||||
|
||||
uploadInstance.on('uploaded', function (error, fileObj) {
|
||||
console.log('uploaded: ', fileObj);
|
||||
|
||||
// props.setUpId(fileObj._id);
|
||||
|
||||
// Remove the filename from the upload box
|
||||
fileinput.current.value = '';
|
||||
|
||||
// Reset our state for the next file
|
||||
setUploading([]);
|
||||
setProgress(0);
|
||||
setInProgress(false);
|
||||
})
|
||||
|
||||
uploadInstance.on('error', function (error, fileObj) {
|
||||
console.log('Error during upload: ' + error)
|
||||
});
|
||||
|
||||
uploadInstance.on('progress', function (progress, fileObj) {
|
||||
console.log('Upload Percentage: ' + progress)
|
||||
// Update our progress bar
|
||||
setProgress(progress);
|
||||
});
|
||||
|
||||
uploadInstance.start(); // Must manually start the upload
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This is our progress bar, bootstrap styled
|
||||
// Remove this function if not needed
|
||||
function showUploads() {
|
||||
// console.log('**********************************', uploading);
|
||||
|
||||
if (!_.isEmpty(uploading)) {
|
||||
return <div>
|
||||
{uploading.file.name}
|
||||
|
||||
<div className="progress progress-bar-default">
|
||||
<div style={{width: progress + '%'}} aria-valuemax="100"
|
||||
aria-valuemin="0"
|
||||
aria-valuenow={progress || 0} role="progressbar"
|
||||
className="progress-bar"
|
||||
>
|
||||
<span className="sr-only">{progress}% Complete (success)</span>
|
||||
<span>{progress}%</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
|
||||
const Display = async () => await files?.map(async (aFile, key) => {
|
||||
|
||||
let link = await FilesCol.findOneAsync({_id: aFile._id}); //The "view/download" link
|
||||
let linkOriginalURL = `${window.location.origin}${link._fileRef._downloadRoute}/${link._fileRef._collectionName}/${link._fileRef._id}/original/${link._fileRef._id}.${link._fileRef.extension}`;
|
||||
|
||||
// Send out components that show details of each file
|
||||
|
||||
return <Suspense fallback="<>Loading...</>">
|
||||
<div key={'file' + key}>
|
||||
<IndividualFileStart
|
||||
fileName={aFile.name}
|
||||
fileUrl={linkOriginalURL}
|
||||
fileId={aFile._id}
|
||||
fileSize={aFile.size}
|
||||
/>
|
||||
</div>
|
||||
</Suspense>
|
||||
}).reverse();
|
||||
|
||||
// Run through each file that the user has stored
|
||||
// (make sure the subscription only sends files owned by this user)
|
||||
// let display =
|
||||
|
||||
return <Suspense fallback="Loading...">
|
||||
<button
|
||||
className='btArxiu'
|
||||
onClick={ev => {
|
||||
ev.preventDefault();
|
||||
|
||||
// refForm.current.reset();
|
||||
fileinput.current.click();
|
||||
//reseter[1](reseter[0] + 1);
|
||||
//refForm.current.reset();
|
||||
ev.target.value = null;
|
||||
}}
|
||||
>
|
||||
<span className="fa-solid fa-paperclip" >Add file</span>
|
||||
</button>
|
||||
|
||||
<input type="file"
|
||||
id="fileinput"
|
||||
disabled={inProgress}
|
||||
ref={fileinput}
|
||||
onChange={uploadIt}
|
||||
style={{display: `none`}}
|
||||
/>
|
||||
|
||||
<div className="row m-t-sm m-b-sm">
|
||||
<div className="col-md-6">
|
||||
|
||||
{showUploads()}
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Display />
|
||||
</Suspense>
|
||||
// else return <div>Carregant llista d'arxius...</div>;
|
||||
};
|
||||
|
||||
//
|
||||
// This is the HOC - included in this file just for convenience, but usually kept
|
||||
// in a separate file to provide separation of concerns.
|
||||
//
|
||||
// export default withTracker( ( props ) => {
|
||||
|
||||
// const filesHandle = Meteor.subscribe('files.all');
|
||||
// const docsReadyYet = filesHandle.ready();
|
||||
// const files = FilesCol.find({meta:{userId: props.uidProvisional || Meteor.userId()}}, {sort: {name: 1}}).fetch(); // Meteor.userId() ?? "nop"
|
||||
|
||||
// return {
|
||||
// docsReadyYet,
|
||||
// files,
|
||||
// };
|
||||
|
||||
// })(FileUploadComponent);
|
||||
|
||||
export default FileUploadStart;
|
||||
188
imports/ui/files/FileUpload_abans.jsx
Normal file
188
imports/ui/files/FileUpload_abans.jsx
Normal file
@ -0,0 +1,188 @@
|
||||
import { useTracker } from 'meteor/react-meteor-data';
|
||||
import { Meteor } from 'meteor/meteor';
|
||||
import React, { useState, useRef } from 'react';
|
||||
// import PropTypes from 'prop-types';
|
||||
import { FilesCol } from '/imports/api/files.js';
|
||||
|
||||
import IndividualFile from '/imports/ui/files/IndividualFile.jsx';
|
||||
|
||||
import _ from 'lodash';
|
||||
|
||||
const debug = require('debug')('demo:file');
|
||||
|
||||
const FileUploadComponent = (props) => {
|
||||
|
||||
const [uploading, setUploading] = useState([]);
|
||||
const [progress, setProgress] = useState(0);
|
||||
const [inProgress, setInProgress] = useState(false);
|
||||
|
||||
const fileinput = useRef();
|
||||
|
||||
const files = useTracker(() => {
|
||||
const filesHandle = Meteor.subscribe('files.all');
|
||||
// const docsReadyYet = filesHandle.ready();
|
||||
const files = FilesCol?.find({meta:{userId: props?.uidProvisional || Meteor.userId()}}, {sort: {name: 1}}).fetch(); // Meteor.userId() ?? "nop"
|
||||
|
||||
return files;
|
||||
});
|
||||
|
||||
|
||||
|
||||
function uploadIt(e) {
|
||||
e.preventDefault();
|
||||
|
||||
//let self = this;
|
||||
|
||||
if (e.currentTarget.files && e.currentTarget.files[0]) {
|
||||
// We upload only one file, in case
|
||||
// there was multiple files selected
|
||||
var file = e.currentTarget.files[0];
|
||||
|
||||
if (file) {
|
||||
let uploadInstance = FilesCol.insert({
|
||||
file,
|
||||
meta: {
|
||||
locator: props.fileLocator,
|
||||
userId: props.uidProvisional || Meteor.userId() // Optional, used to check on server for file tampering
|
||||
},
|
||||
chunkSize: 'dynamic',
|
||||
allowWebWorkers: true // If you see issues with uploads, change this to false
|
||||
}, false)
|
||||
|
||||
setUploading(uploadInstance); // Keep track of this instance to use below
|
||||
setInProgress(true);// Show the progress bar now
|
||||
|
||||
// These are the event functions, don't need most of them, it shows where we are in the process
|
||||
uploadInstance.on('start', function () {
|
||||
console.log('Starting');
|
||||
})
|
||||
|
||||
uploadInstance.on('end', function (error, fileObj) {
|
||||
console.log('On end File Object: ', fileObj);
|
||||
})
|
||||
|
||||
uploadInstance.on('uploaded', function (error, fileObj) {
|
||||
console.log('uploaded: ', fileObj);
|
||||
|
||||
props.setUpId(fileObj?._id);
|
||||
|
||||
// Remove the filename from the upload box
|
||||
fileinput.current.value = '';
|
||||
|
||||
// Reset our state for the next file
|
||||
setUploading([]);
|
||||
setProgress(0);
|
||||
setInProgress(false);
|
||||
})
|
||||
|
||||
uploadInstance.on('error', function (error, fileObj) {
|
||||
console.log('Error during upload: ' + error)
|
||||
});
|
||||
|
||||
uploadInstance.on('progress', function (progress, fileObj) {
|
||||
console.log('Upload Percentage: ' + progress)
|
||||
// Update our progress bar
|
||||
setProgress(progress);
|
||||
});
|
||||
|
||||
uploadInstance.start(); // Must manually start the upload
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This is our progress bar, bootstrap styled
|
||||
// Remove this function if not needed
|
||||
function showUploads() {
|
||||
console.log('**********************************', uploading);
|
||||
|
||||
if (!_.isEmpty(uploading)) {
|
||||
return <div>
|
||||
{uploading.file.name}
|
||||
|
||||
<div className="progress progress-bar-default">
|
||||
<div style={{width: progress + '%'}} aria-valuemax="100"
|
||||
aria-valuemin="0"
|
||||
aria-valuenow={progress || 0} role="progressbar"
|
||||
className="progress-bar">
|
||||
<span className="sr-only">{progress}% Complete (success)</span>
|
||||
<span>{progress}%</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
// debug("Rendering FileUpload",docsReadyYet);
|
||||
if (files /* && docsReadyYet*/) {
|
||||
|
||||
let fileCursors = files;
|
||||
|
||||
// Run through each file that the user has stored
|
||||
// (make sure the subscription only sends files owned by this user)
|
||||
let display = fileCursors.map((aFile, key) => {
|
||||
// console.log('A file: ', aFile.link(), aFile.get('name'))
|
||||
let link = FilesCol.findOne({_id: aFile._id}).link(); //The "view/download" link
|
||||
|
||||
// Send out components that show details of each file
|
||||
return <div key={'file' + key}>
|
||||
<IndividualFile
|
||||
fileName={aFile.name}
|
||||
fileUrl={link}
|
||||
fileId={aFile._id}
|
||||
fileSize={aFile.size}
|
||||
/>
|
||||
</div>
|
||||
})
|
||||
|
||||
return <div>
|
||||
|
||||
<div className="row">
|
||||
<div className="col-md-12">
|
||||
<p>Upload New File:</p>
|
||||
<input type="file"
|
||||
id="fileinput"
|
||||
disabled={inProgress}
|
||||
ref={fileinput}
|
||||
onChange={uploadIt}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="row m-t-sm m-b-sm">
|
||||
<div className="col-md-6">
|
||||
|
||||
{showUploads()}
|
||||
|
||||
</div>
|
||||
<div className="col-md-6">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{display}
|
||||
|
||||
</div>
|
||||
}
|
||||
else return <div>Loading file list</div>;
|
||||
}
|
||||
};
|
||||
|
||||
//
|
||||
// This is the HOC - included in this file just for convenience, but usually kept
|
||||
// in a separate file to provide separation of concerns.
|
||||
//
|
||||
// export default withTracker( ( props ) => {
|
||||
|
||||
// const filesHandle = Meteor.subscribe('files.all');
|
||||
// const docsReadyYet = filesHandle.ready();
|
||||
// const files = FilesCol.find({meta:{userId: props.uidProvisional || Meteor.userId()}}, {sort: {name: 1}}).fetch(); // Meteor.userId() ?? "nop"
|
||||
|
||||
// return {
|
||||
// docsReadyYet,
|
||||
// files,
|
||||
// };
|
||||
|
||||
// })(FileUploadComponent);
|
||||
|
||||
export default FileUploadComponent;
|
||||
186
imports/ui/files/FileUpload_ori.jsx
Normal file
186
imports/ui/files/FileUpload_ori.jsx
Normal file
@ -0,0 +1,186 @@
|
||||
import { withTracker } from 'meteor/react-meteor-data';
|
||||
import { Meteor } from 'meteor/meteor';
|
||||
import React, { Component } from 'react';
|
||||
// import PropTypes from 'prop-types';
|
||||
import { FilesCol } from '/imports/api/files.js';
|
||||
|
||||
import IndividualFile from '/imports/ui/files/IndividualFile.jsx';
|
||||
|
||||
import _ from 'lodash';
|
||||
|
||||
const debug = require('debug')('demo:file');
|
||||
|
||||
class FileUploadComponent extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
uploading: [],
|
||||
progress: 0,
|
||||
inProgress: false
|
||||
};
|
||||
|
||||
this.uploadIt = this.uploadIt.bind(this);
|
||||
}
|
||||
|
||||
uploadIt(e) {
|
||||
e.preventDefault();
|
||||
|
||||
let self = this;
|
||||
|
||||
if (e.currentTarget.files && e.currentTarget.files[0]) {
|
||||
// We upload only one file, in case
|
||||
// there was multiple files selected
|
||||
var file = e.currentTarget.files[0];
|
||||
|
||||
if (file) {
|
||||
let uploadInstance = FilesCol.insert({
|
||||
file: file,
|
||||
meta: {
|
||||
locator: self.props.fileLocator,
|
||||
userId: this.props.uidProvisional || Meteor.userId() // Optional, used to check on server for file tampering
|
||||
},
|
||||
chunkSize: 'dynamic',
|
||||
allowWebWorkers: true // If you see issues with uploads, change this to false
|
||||
}, false)
|
||||
|
||||
self.setState({
|
||||
uploading: uploadInstance, // Keep track of this instance to use below
|
||||
inProgress: true // Show the progress bar now
|
||||
});
|
||||
|
||||
// These are the event functions, don't need most of them, it shows where we are in the process
|
||||
uploadInstance.on('start', function () {
|
||||
console.log('Starting');
|
||||
})
|
||||
|
||||
uploadInstance.on('end', function (error, fileObj) {
|
||||
console.log('On end File Object: ', fileObj);
|
||||
//this.props?.setAvatarId(fileObj._id);
|
||||
})
|
||||
|
||||
uploadInstance.on('uploaded', function (error, fileObj) {
|
||||
console.log('uploaded: ', fileObj);
|
||||
//console.log(`setAvatarId: ${this.props?.setAvatarId}`);
|
||||
|
||||
// this.props.setUpId(fileObj._id);
|
||||
// Remove the filename from the upload box
|
||||
self.refs['fileinput'].value = '';
|
||||
|
||||
// Reset our state for the next file
|
||||
self.setState({
|
||||
uploading: [],
|
||||
progress: 0,
|
||||
inProgress: false
|
||||
});
|
||||
})
|
||||
|
||||
uploadInstance.on('error', function (error, fileObj) {
|
||||
console.log('Error during upload: ' + error)
|
||||
});
|
||||
|
||||
uploadInstance.on('progress', function (progress, fileObj) {
|
||||
console.log('Upload Percentage: ' + progress)
|
||||
// Update our progress bar
|
||||
self.setState({
|
||||
progress: progress
|
||||
});
|
||||
});
|
||||
|
||||
uploadInstance.start(); // Must manually start the upload
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This is our progress bar, bootstrap styled
|
||||
// Remove this function if not needed
|
||||
showUploads() {
|
||||
console.log('**********************************', this.state.uploading);
|
||||
|
||||
if (!_.isEmpty(this.state.uploading)) {
|
||||
return <div>
|
||||
{this.state.uploading.file.name}
|
||||
|
||||
<div className="progress progress-bar-default">
|
||||
<div style={{width: this.state.progress + '%'}} aria-valuemax="100"
|
||||
aria-valuemin="0"
|
||||
aria-valuenow={this.state.progress || 0} role="progressbar"
|
||||
className="progress-bar">
|
||||
<span className="sr-only">{this.state.progress}% Complete (success)</span>
|
||||
<span>{this.state.progress}%</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
debug("Rendering FileUpload",this.props.docsReadyYet);
|
||||
if (this.props.files && this.props.docsReadyYet) {
|
||||
|
||||
let fileCursors = this.props.files;
|
||||
|
||||
// Run through each file that the user has stored
|
||||
// (make sure the subscription only sends files owned by this user)
|
||||
let display = fileCursors.map((aFile, key) => {
|
||||
// console.log('A file: ', aFile.link(), aFile.get('name'))
|
||||
let link = FilesCol.findOne({_id: aFile._id}).link(); //The "view/download" link
|
||||
|
||||
// Send out components that show details of each file
|
||||
return <div key={'file' + key}>
|
||||
<IndividualFile
|
||||
fileName={aFile.name}
|
||||
fileUrl={link}
|
||||
fileId={aFile._id}
|
||||
fileSize={aFile.size}
|
||||
/>
|
||||
</div>
|
||||
})
|
||||
|
||||
return <div>
|
||||
<div className="row">
|
||||
<div className="col-md-12">
|
||||
<p>Upload New File:</p>
|
||||
<input type="file"
|
||||
id="fileinput"
|
||||
disabled={this.state.inProgress}
|
||||
ref="fileinput"
|
||||
onChange={this.uploadIt}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="row m-t-sm m-b-sm">
|
||||
<div className="col-md-6">
|
||||
|
||||
{this.showUploads()}
|
||||
|
||||
</div>
|
||||
<div className="col-md-6">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{display}
|
||||
|
||||
</div>
|
||||
}
|
||||
else return <div>Loading file list</div>;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// This is the HOC - included in this file just for convenience, but usually kept
|
||||
// in a separate file to provide separation of concerns.
|
||||
//
|
||||
export default withTracker( ( props ) => {
|
||||
const filesHandle = Meteor.subscribe('files.all');
|
||||
const docsReadyYet = filesHandle.ready();
|
||||
const files = FilesCol.find({meta:{userId: props.uidProvisional || Meteor.userId()}}, {sort: {name: 1}}).fetch(); // Meteor.userId() ?? "nop"
|
||||
// const setAvatarId = props.setAvatarId;
|
||||
|
||||
return {
|
||||
docsReadyYet,
|
||||
files,
|
||||
// setAvatarId
|
||||
};
|
||||
})(FileUploadComponent);
|
||||
34
imports/ui/files/Files.jsx
Normal file
34
imports/ui/files/Files.jsx
Normal file
@ -0,0 +1,34 @@
|
||||
// import { Meteor } from 'meteor/meteor';
|
||||
import React from 'react';
|
||||
import { useSubscribe, useFind, useTracker } from 'meteor/react-meteor-data/suspense';
|
||||
|
||||
// import { FilesCollection } from '/imports/api/files.js';
|
||||
import { FilesCol } from '/imports/api/files.js';
|
||||
import FileUploadStart from '/imports/ui/files/FileUploadStart.jsx';
|
||||
|
||||
|
||||
const Files = () => {
|
||||
|
||||
useSubscribe('files.all');
|
||||
|
||||
const files = useTracker("files", () => {
|
||||
const files = FilesCol.find({}).fetchAsync();
|
||||
return files;
|
||||
});
|
||||
|
||||
return <>
|
||||
<h1 style={{
|
||||
fontFamily: `cyber`,
|
||||
padding: `.7rem`,
|
||||
color: `#ff0c`,
|
||||
textShadow: `.02em .02em .1em black`
|
||||
}}>Files</h1>
|
||||
{
|
||||
|
||||
<FileUploadStart />
|
||||
|
||||
}
|
||||
</>;
|
||||
};
|
||||
|
||||
export { Files };
|
||||
217
imports/ui/files/FilesCartellEvent/FileUploadCartellEvent.jsx
Normal file
217
imports/ui/files/FilesCartellEvent/FileUploadCartellEvent.jsx
Normal file
@ -0,0 +1,217 @@
|
||||
import { useTracker } from 'meteor/react-meteor-data';
|
||||
import { Meteor } from 'meteor/meteor';
|
||||
import React, { useState, useRef } from 'react';
|
||||
// import PropTypes from 'prop-types';
|
||||
import { FilesCol } from '/imports/api/files.js';
|
||||
|
||||
import { IndividualFileCartellEvent } from '/imports/ui/files/FilesCartellEvent/IndividualFileCartellEvent.jsx';
|
||||
|
||||
import _ from 'lodash';
|
||||
|
||||
//const debug = require('debug')('demo:file');
|
||||
|
||||
const FileUploadCartellEvent = (props) => {
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
const cartellId = new Mongo.ObjectID();
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
///////////////////////////////////////////////
|
||||
const [upId, setUpId] = useState(null);
|
||||
|
||||
const [uploading, setUploading] = useState([]);
|
||||
const [progress, setProgress] = useState(0);
|
||||
const [inProgress, setInProgress] = useState(false);
|
||||
|
||||
const fileinput = useRef();
|
||||
|
||||
const files = useTracker(() => {
|
||||
const filesHandle = Meteor.subscribe('files.cartellEventUpload', upId);
|
||||
// const docsReadyYet = filesHandle.ready();
|
||||
const files = FilesCol?.find(upId).fetch(); // Meteor.userId() ?? "nop" //"meta.avatarId": avatarId
|
||||
|
||||
return files;
|
||||
});
|
||||
|
||||
|
||||
function uploadIt(e) {
|
||||
e.preventDefault();
|
||||
|
||||
//let self = this;
|
||||
|
||||
if (e.currentTarget.files && e.currentTarget.files[0]) {
|
||||
// We upload only one file, in case
|
||||
// there was multiple files selected
|
||||
var file = e.currentTarget.files[0];
|
||||
|
||||
if (file) {
|
||||
let uploadInstance = FilesCol.insert({
|
||||
file,
|
||||
meta: {
|
||||
// locator: props.fileLocator,
|
||||
// userId: props.uidProvisional || Meteor.userId(), // Optional, used to check on server for file tampering
|
||||
// eventId: props.eventId
|
||||
},
|
||||
chunkSize: 'dynamic',
|
||||
allowWebWorkers: true // If you see issues with uploads, change this to false
|
||||
}, false)
|
||||
|
||||
setUploading(uploadInstance); // Keep track of this instance to use below
|
||||
setInProgress(true); // Show the progress bar now
|
||||
|
||||
// These are the event functions, don't need most of them, it shows where we are in the process
|
||||
uploadInstance.on('start', function () {
|
||||
console.log('Starting');
|
||||
})
|
||||
|
||||
uploadInstance.on('end', function (error, fileObj) {
|
||||
console.log('On end File Object: ', fileObj);
|
||||
|
||||
props.setCartellId(fileObj._id);
|
||||
})
|
||||
|
||||
uploadInstance.on('uploaded', function (error, fileObj) {
|
||||
console.log('uploaded: ', fileObj);
|
||||
|
||||
setUpId(fileObj._id);
|
||||
|
||||
// Remove the filename from the upload box
|
||||
fileinput.current.value = '';
|
||||
|
||||
// Reset our state for the next file
|
||||
setUploading([]);
|
||||
setProgress(0);
|
||||
setInProgress(false);
|
||||
|
||||
props.setNovaImg(true);
|
||||
})
|
||||
|
||||
uploadInstance.on('error', function (error, fileObj) {
|
||||
console.log('Error during upload: ' + error)
|
||||
});
|
||||
|
||||
uploadInstance.on('progress', function (progress, fileObj) {
|
||||
console.log('Upload Percentage: ' + progress)
|
||||
// Update our progress bar
|
||||
setProgress(progress);
|
||||
});
|
||||
|
||||
uploadInstance.start(); // Must manually start the upload
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This is our progress bar, bootstrap styled
|
||||
// Remove this function if not needed
|
||||
function showUploads() {
|
||||
console.log('**********************************', uploading);
|
||||
|
||||
if (!_.isEmpty(uploading)) {
|
||||
return <div>
|
||||
{uploading.file.name}
|
||||
|
||||
<div className="progress progress-bar-default">
|
||||
<div style={{width: progress + '%', background: "white"}} aria-valuemax="100"
|
||||
aria-valuemin="0"
|
||||
aria-valuenow={progress || 0} role="progressbar"
|
||||
className="progress-bar">
|
||||
<span className="sr-only">{progress}% Complete (success)</span>
|
||||
<span>{progress}%</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//{
|
||||
// debug("Rendering FileUpload",docsReadyYet);
|
||||
// if (files /* && docsReadyYet*/) {
|
||||
|
||||
// let fileCursors = files;
|
||||
|
||||
// Run through each file that the user has stored
|
||||
// (make sure the subscription only sends files owned by this user)
|
||||
let display = files?.map((aFile, key) => {
|
||||
// console.log('A file: ', aFile.link(), aFile.get('name'))
|
||||
let link = FilesCol.findOne({_id: upId})?.link(); //The "view/download" link
|
||||
|
||||
props.setCartellLink(link);
|
||||
|
||||
// Send out components that show details of each file
|
||||
return <div key={'file' + key}>
|
||||
<IndividualFileCartellEvent
|
||||
fileName={aFile.name}
|
||||
fileUrl={link}
|
||||
fileId={aFile._id}
|
||||
fileSize={aFile.size}
|
||||
/>
|
||||
{/* <button onClick={ev => {
|
||||
ev.preventDefault();
|
||||
ev.stopPropagation();
|
||||
|
||||
Meteor.call('userAvatarUpdate', avatarId, avatarLink, () => {
|
||||
setNovaImg(false);
|
||||
});
|
||||
|
||||
// alert(`
|
||||
// avatarId: ${avatarId}
|
||||
// avatarLink: ${avatarLink}`);
|
||||
|
||||
}}>Estableix</button>*/}
|
||||
</div>
|
||||
})
|
||||
|
||||
return <div>
|
||||
|
||||
<div className="row">
|
||||
<div className="col-md-12">
|
||||
<p>Upload New File:</p>
|
||||
<label htmlFor="fileinput">Tria la imatge de l'event: </label>
|
||||
<br />
|
||||
<input type="file"
|
||||
id="fileinput"
|
||||
disabled={inProgress}
|
||||
ref={fileinput}
|
||||
onChange={uploadIt}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="row m-t-sm m-b-sm">
|
||||
<div className="col-md-6">
|
||||
|
||||
{showUploads()}
|
||||
|
||||
</div>
|
||||
<div className="col-md-6">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{display}
|
||||
|
||||
</div>
|
||||
// }
|
||||
// else return <div>Loading file list</div>;
|
||||
// }
|
||||
};
|
||||
|
||||
//
|
||||
// This is the HOC - included in this file just for convenience, but usually kept
|
||||
// in a separate file to provide separation of concerns.
|
||||
//
|
||||
// export default withTracker( ( props ) => {
|
||||
|
||||
// const filesHandle = Meteor.subscribe('files.all');
|
||||
// const docsReadyYet = filesHandle.ready();
|
||||
// const files = FilesCol.find({meta:{userId: props.uidProvisional || Meteor.userId()}}, {sort: {name: 1}}).fetch(); // Meteor.userId() ?? "nop"
|
||||
|
||||
// return {
|
||||
// docsReadyYet,
|
||||
// files,
|
||||
// };
|
||||
|
||||
// })(FileUploadComponent);
|
||||
|
||||
export { FileUploadCartellEvent };
|
||||
@ -0,0 +1,84 @@
|
||||
import React from 'react';
|
||||
// import PropTypes from 'prop-types';
|
||||
|
||||
const IndividualFileCartellEvent = props => {
|
||||
|
||||
// propTypes: {
|
||||
// fileName: PropTypes.string.isRequired,
|
||||
// fileSize: PropTypes.number.isRequired,
|
||||
// fileUrl: PropTypes.string,
|
||||
// fileId: PropTypes.string.isRequired
|
||||
// }
|
||||
|
||||
function removeFile(){
|
||||
let conf = confirm('Are you sure you want to delete the file?') || false;
|
||||
if (conf == true) {
|
||||
Meteor.call('RemoveFile', props.fileId, function (err, res) {
|
||||
if (err)
|
||||
console.log(err);
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
function renameFile(){
|
||||
|
||||
let validName = /[^a-zA-Z0-9 \.:\+()\-_%!&]/gi;
|
||||
let prompt = window.prompt('New file name?', props.fileName);
|
||||
|
||||
// Replace any non valid characters, also do this on the server
|
||||
if (prompt) {
|
||||
prompt = prompt.replace(validName, '-');
|
||||
prompt.trim();
|
||||
}
|
||||
|
||||
if (!_.isEmpty(prompt)) {
|
||||
Meteor.call('RenameFile', props.fileId, prompt, function (err, res) {
|
||||
if (err)
|
||||
console.log(err);
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return <div className="m-t-sm">
|
||||
<a href={props.fileUrl} target="_blank" >
|
||||
<img
|
||||
src={props.fileUrl}
|
||||
alt={props.fileName}
|
||||
style={{maxWidth: `200px`, maxHeight: `200px`}}
|
||||
/>
|
||||
</a>
|
||||
|
||||
{/* <div className="row">
|
||||
<div className="col-md-12">
|
||||
<strong>{props.fileName}</strong>
|
||||
<div className="m-b-sm">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="row">
|
||||
<div className="col-md-3">
|
||||
<button onClick={renameFile} className="btn btn-outline btn-primary btn-sm">
|
||||
Rename
|
||||
</button>
|
||||
</div>
|
||||
|
||||
|
||||
<div className="col-md-3">
|
||||
<a href={props.fileUrl} className="btn btn-outline btn-primary btn-sm"
|
||||
target="_blank">View</a>
|
||||
</div>
|
||||
|
||||
<div className="col-md-2">
|
||||
<button onClick={removeFile} className="btn btn-outline btn-danger btn-sm">
|
||||
Delete
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="col-md-4">
|
||||
Size: {props.fileSize}
|
||||
</div>
|
||||
</div> */}
|
||||
</div>
|
||||
}
|
||||
export { IndividualFileCartellEvent };
|
||||
210
imports/ui/files/FolderTreeFileUpload.jsx
Normal file
210
imports/ui/files/FolderTreeFileUpload.jsx
Normal file
@ -0,0 +1,210 @@
|
||||
import { useTracker } from 'meteor/react-meteor-data';
|
||||
import { Meteor } from 'meteor/meteor';
|
||||
import { Mongo } from 'meteor/mongo';
|
||||
import React, { useState, useRef } from 'react';
|
||||
// import PropTypes from 'prop-types';
|
||||
import { FilesCol } from '/imports/api/files.js';
|
||||
|
||||
import FolderTreeIndividualFile from '/imports/ui/files/FolderTreeIndividualFile.jsx';
|
||||
|
||||
import _, { upperCase } from 'lodash';
|
||||
|
||||
const debug = require('debug')('demo:file');
|
||||
|
||||
|
||||
const FolderTreeFileUpload = (props) => {
|
||||
////////////////////////////////////////////////////////////////////////////////////////////
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
const treeFileId = new Mongo.ObjectID();
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
const [upId, setUpId] = useState(null);
|
||||
|
||||
const [uploading, setUploading] = useState([]);
|
||||
const [progress, setProgress] = useState(0);
|
||||
const [inProgress, setInProgress] = useState(false);
|
||||
|
||||
const fileinput = useRef();
|
||||
|
||||
const files = useTracker(() => {
|
||||
const filesHandle = Meteor.subscribe('files.folderTree', upId);
|
||||
// const docsReadyYet = filesHandle.ready();
|
||||
const files = FilesCol?.find(upId).fetch(); // Meteor.userId() ?? "nop" //"meta.avatarId": avatarId
|
||||
|
||||
return files;
|
||||
});
|
||||
|
||||
function uploadIt(e) {
|
||||
e.preventDefault();
|
||||
|
||||
//let self = this;
|
||||
|
||||
if (e.currentTarget.files && e.currentTarget.files[0]) {
|
||||
// We upload only one file, in case
|
||||
// there was multiple files selected
|
||||
var file = e.currentTarget.files[0];
|
||||
|
||||
if (file) {
|
||||
console.log("IfFile: ", file);
|
||||
let uploadInstance = FilesCol.insert({
|
||||
file,
|
||||
meta: {
|
||||
//locator: file.link(),
|
||||
userId: Meteor.userId(), // Optional, used to check on server for file tampering
|
||||
type: "folderTree"
|
||||
//avatarId
|
||||
},
|
||||
chunkSize: 'dynamic',
|
||||
allowWebWorkers: true // If you see issues with uploads, change this to false
|
||||
}, false);
|
||||
|
||||
setUploading(uploadInstance); // Keep track of this instance to use below
|
||||
setInProgress(true); // Show the progress bar now
|
||||
|
||||
// These are the event functions, don't need most of them, it shows where we are in the process
|
||||
uploadInstance.on('start', function () {
|
||||
console.log('Starting');
|
||||
});
|
||||
|
||||
uploadInstance.on('end', function (error, fileObj) {
|
||||
console.log('On end File Object: ', fileObj);
|
||||
|
||||
props.setFolderTreeId(fileObj._id);
|
||||
|
||||
|
||||
});
|
||||
|
||||
uploadInstance.on('uploaded', function (error, fileObj) {
|
||||
console.log('uploaded: ', fileObj);
|
||||
|
||||
setUpId(fileObj._id);
|
||||
|
||||
// Remove the filename from the upload box
|
||||
fileinput.current.value = '';
|
||||
|
||||
// Reset our state for the next file
|
||||
setUploading([]);
|
||||
setProgress(0);
|
||||
setInProgress(false);
|
||||
|
||||
props.setNouFolderTree(true);
|
||||
});
|
||||
|
||||
uploadInstance.on('error', function (error, fileObj) {
|
||||
console.log('Error during upload: ' + error)
|
||||
});
|
||||
|
||||
uploadInstance.on('progress', function (progress, fileObj) {
|
||||
console.log('Upload Percentage: ' + progress)
|
||||
// Update our progress bar
|
||||
setProgress(progress);
|
||||
});
|
||||
|
||||
uploadInstance.start(); // Must manually start the upload
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This is our progress bar, bootstrap styled
|
||||
// Remove this function if not needed
|
||||
function showUploads() {
|
||||
console.log('**********************************', uploading);
|
||||
|
||||
if (!_.isEmpty(uploading)) {
|
||||
return <div>
|
||||
{uploading.file.name}
|
||||
|
||||
<div className="progress progress-bar-default">
|
||||
<div style={{width: progress + '%'}} aria-valuemax="100"
|
||||
aria-valuemin="0"
|
||||
aria-valuenow={progress || 0} role="progressbar"
|
||||
className="progress-bar">
|
||||
<span className="sr-only">{progress}% Complete (success)</span>
|
||||
<span>{progress}%</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
// debug("Rendering FileUpload",docsReadyYet);
|
||||
//if (files.length /* && docsReadyYet*/) {
|
||||
|
||||
//let fileCursors = files;
|
||||
|
||||
// Run through each file that the user has stored
|
||||
// (make sure the subscription only sends files owned by this user)
|
||||
let display = files?.map((aFile, key) => {
|
||||
// console.log('A file: ', aFile.link(), aFile.get('name'))
|
||||
let link = FilesCol?.findOne({_id: upId})?.link(); //The "view/download" link
|
||||
|
||||
alert(`Enllaç a l'arxiu: ${link}`);
|
||||
|
||||
props.setFolderTreeLink(link);
|
||||
|
||||
// Send out components that show details of each file
|
||||
return <div key={'file' + key}>
|
||||
{props.nouFolderTree && <FolderTreeIndividualFile
|
||||
fileName={aFile.name}
|
||||
fileUrl={link}
|
||||
fileId={aFile._id}
|
||||
fileSize={aFile.size}
|
||||
/>}
|
||||
</div>
|
||||
})
|
||||
|
||||
return <div>
|
||||
<div className="row">
|
||||
<div className="col-md-12">
|
||||
<p>Adjunta un arxiu FolderTree*:</p>
|
||||
<input type="file"
|
||||
id="fileinput"
|
||||
disabled={inProgress}
|
||||
ref={fileinput}
|
||||
onChange={uploadIt}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="row m-t-sm m-b-sm">
|
||||
<div className="col-md-6">
|
||||
|
||||
{showUploads()}
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
{display}
|
||||
|
||||
<p>* Un FolderTree és un arxiu en format JSON generat per un commandament 'treedump'** o 'treedumpl'*** </p>
|
||||
<p>{`** treedump () {
|
||||
tree -J -s -f \${@[$#]}
|
||||
}`}</p>
|
||||
|
||||
</div>
|
||||
// }
|
||||
// return null;
|
||||
}
|
||||
};
|
||||
|
||||
//
|
||||
// This is the HOC - included in this file just for convenience, but usually kept
|
||||
// in a separate file to provide separation of concerns.
|
||||
//
|
||||
// export default withTracker( ( props ) => {
|
||||
|
||||
// const filesHandle = Meteor.subscribe('files.all');
|
||||
// const docsReadyYet = filesHandle.ready();
|
||||
// const files = FilesCol.find({meta:{userId: props.uidProvisional || Meteor.userId()}}, {sort: {name: 1}}).fetch(); // Meteor.userId() ?? "nop"
|
||||
|
||||
// return {
|
||||
// docsReadyYet,
|
||||
// files,
|
||||
// };
|
||||
|
||||
// })(FileUploadComponent);
|
||||
|
||||
export default FolderTreeFileUpload;
|
||||
78
imports/ui/files/FolderTreeIndividualFile.jsx
Normal file
78
imports/ui/files/FolderTreeIndividualFile.jsx
Normal file
@ -0,0 +1,78 @@
|
||||
import React from 'react';
|
||||
// import PropTypes from 'prop-types';
|
||||
|
||||
const FolderTreeIndividualFile = props => {
|
||||
|
||||
// propTypes: {
|
||||
// fileName: PropTypes.string.isRequired,
|
||||
// fileSize: PropTypes.number.isRequired,
|
||||
// fileUrl: PropTypes.string,
|
||||
// fileId: PropTypes.string.isRequired
|
||||
// }
|
||||
|
||||
function removeFile(){
|
||||
let conf = confirm('Are you sure you want to delete the file?') || false;
|
||||
if (conf == true) {
|
||||
Meteor.call('RemoveFile', props.fileId, function (err, res) {
|
||||
if (err)
|
||||
console.log(err);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function renameFile(){
|
||||
|
||||
let validName = /[^a-zA-Z0-9 \.:\+()\-_%!&]/gi;
|
||||
let prompt = window.prompt('New file name?', props.fileName);
|
||||
|
||||
// Replace any non valid characters, also do this on the server
|
||||
if (prompt) {
|
||||
prompt = prompt.replace(validName, '-');
|
||||
prompt.trim();
|
||||
}
|
||||
|
||||
if (!_.isEmpty(prompt)) {
|
||||
Meteor.call('RenameFile', props.fileId, prompt, function (err, res) {
|
||||
if (err)
|
||||
console.log(err);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return <div className="m-t-sm">
|
||||
<a href={props.fileUrl} ><img src={props.fileUrl} alt={props.fileName} style={{maxWidth: `200px`, maxHeight: `200px`}}/></a>
|
||||
|
||||
<div className="row">
|
||||
<div className="col-md-12">
|
||||
<strong>{props.fileName}</strong>
|
||||
<div className="m-b-sm">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* <div className="row">
|
||||
<div className="col-md-3">
|
||||
<button onClick={renameFile} className="btn btn-outline btn-primary btn-sm">
|
||||
Rename
|
||||
</button>
|
||||
</div>
|
||||
|
||||
|
||||
<div className="col-md-3">
|
||||
<a href={props.fileUrl} className="btn btn-outline btn-primary btn-sm"
|
||||
target="_blank">View</a>
|
||||
</div>
|
||||
|
||||
<div className="col-md-2">
|
||||
<button onClick={removeFile} className="btn btn-outline btn-danger btn-sm">
|
||||
Delete
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="col-md-4">
|
||||
Size: {props.fileSize}
|
||||
</div>
|
||||
</div> */}
|
||||
</div>
|
||||
}
|
||||
export default FolderTreeIndividualFile;
|
||||
79
imports/ui/files/IndividualFile.jsx
Normal file
79
imports/ui/files/IndividualFile.jsx
Normal file
@ -0,0 +1,79 @@
|
||||
import React from 'react';
|
||||
import { Meteor } from 'meteor/meteor';
|
||||
// import PropTypes from 'prop-types';
|
||||
|
||||
const IndividualFile = props => {
|
||||
|
||||
// propTypes: {
|
||||
// fileName: PropTypes.string.isRequired,
|
||||
// fileSize: PropTypes.number.isRequired,
|
||||
// fileUrl: PropTypes.string,
|
||||
// fileId: PropTypes.string.isRequired
|
||||
// }
|
||||
|
||||
function removeFile(){
|
||||
let conf = confirm('Are you sure you want to delete the file?') || false;
|
||||
if (conf == true) {
|
||||
Meteor.call('RemoveFile', props.fileId, function (err, res) {
|
||||
if (err)
|
||||
console.log(err);
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
function renameFile(){
|
||||
|
||||
let validName = /[^a-zA-Z0-9 \.:\+()\-_%!&]/gi;
|
||||
let prompt = window.prompt('New file name?', props.fileName);
|
||||
|
||||
// Replace any non valid characters, also do this on the server
|
||||
if (prompt) {
|
||||
prompt = prompt.replace(validName, '-');
|
||||
prompt.trim();
|
||||
}
|
||||
|
||||
if (!_.isEmpty(prompt)) {
|
||||
Meteor.call('RenameFile', props.fileId, prompt, function (err, res) {
|
||||
if (err)
|
||||
console.log(err);
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return <div className="m-t-sm">
|
||||
<img src={props.fileUrl} alt={props.fileName} style={{maxWidth: `200px`, maxHeight: `200px`}}/>
|
||||
|
||||
<div className="row">
|
||||
<div className="col-md-12">
|
||||
<strong>{props.fileName}</strong>
|
||||
<div className="m-b-sm">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="row">
|
||||
<div className="col-md-3">
|
||||
<button onClick={renameFile} className="btn btn-outline btn-primary btn-sm">
|
||||
Rename
|
||||
</button>
|
||||
</div>
|
||||
|
||||
|
||||
<div className="col-md-3">
|
||||
<a href={props.fileUrl} className="btn btn-outline btn-primary btn-sm"
|
||||
target="_blank">View</a>
|
||||
</div>
|
||||
|
||||
<div className="col-md-2">
|
||||
<button onClick={removeFile} className="btn btn-outline btn-danger btn-sm">
|
||||
Delete
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="col-md-4">
|
||||
Size: {props.fileSize}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
export default IndividualFile;
|
||||
85
imports/ui/files/IndividualFileEnt.jsx
Normal file
85
imports/ui/files/IndividualFileEnt.jsx
Normal file
@ -0,0 +1,85 @@
|
||||
import React from 'react';
|
||||
// import PropTypes from 'prop-types';
|
||||
|
||||
const IndividualFileEnt = props => {
|
||||
|
||||
// propTypes: {
|
||||
// fileName: PropTypes.string.isRequired,
|
||||
// fileSize: PropTypes.number.isRequired,
|
||||
// fileUrl: PropTypes.string,
|
||||
// fileId: PropTypes.string.isRequired
|
||||
// }
|
||||
|
||||
function removeFile(){
|
||||
let conf = confirm('Are you sure you want to delete the file?') || false;
|
||||
if (conf == true) {
|
||||
Meteor.call('RemoveFile', props.fileId, function (err, res) {
|
||||
if (err)
|
||||
console.log(err);
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
function renameFile(){
|
||||
|
||||
let validName = /[^a-zA-Z0-9 \.:\+()\-_%!&]/gi;
|
||||
let prompt = window.prompt('New file name?', props.fileName);
|
||||
|
||||
// Replace any non valid characters, also do this on the server
|
||||
if (prompt) {
|
||||
prompt = prompt.replace(validName, '-');
|
||||
prompt.trim();
|
||||
}
|
||||
|
||||
if (!_.isEmpty(prompt)) {
|
||||
Meteor.call('RenameFile', props.fileId, prompt, function (err, res) {
|
||||
if (err)
|
||||
console.log(err);
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return <div className="m-t-sm">
|
||||
<a href={props.fileUrl} target="_blank" >
|
||||
<img
|
||||
className='imgEnt'
|
||||
src={props.fileUrl}
|
||||
alt={props.fileName}
|
||||
style={{maxWidth: `200px`, maxHeight: `200px`, transform: `rotate(${((Math.random() * 4) - 2)}deg`}}
|
||||
/>
|
||||
</a>
|
||||
|
||||
{/* <div className="row">
|
||||
<div className="col-md-12">
|
||||
<strong>{props.fileName}</strong>
|
||||
<div className="m-b-sm">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="row">
|
||||
<div className="col-md-3">
|
||||
<button onClick={renameFile} className="btn btn-outline btn-primary btn-sm">
|
||||
Rename
|
||||
</button>
|
||||
</div>
|
||||
|
||||
|
||||
<div className="col-md-3">
|
||||
<a href={props.fileUrl} className="btn btn-outline btn-primary btn-sm"
|
||||
target="_blank">View</a>
|
||||
</div>
|
||||
|
||||
<div className="col-md-2">
|
||||
<button onClick={removeFile} className="btn btn-outline btn-danger btn-sm">
|
||||
Delete
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="col-md-4">
|
||||
Size: {props.fileSize}
|
||||
</div>
|
||||
</div> */}
|
||||
</div>
|
||||
}
|
||||
export default IndividualFileEnt;
|
||||
81
imports/ui/files/IndividualFilePOI.jsx
Normal file
81
imports/ui/files/IndividualFilePOI.jsx
Normal file
@ -0,0 +1,81 @@
|
||||
import React from 'react';
|
||||
import { Meteor } from 'meteor/meteor';
|
||||
// import PropTypes from 'prop-types';
|
||||
|
||||
const IndividualFile = props => {
|
||||
|
||||
// propTypes: {
|
||||
// fileName: PropTypes.string.isRequired,
|
||||
// fileSize: PropTypes.number.isRequired,
|
||||
// fileUrl: PropTypes.string,
|
||||
// fileId: PropTypes.string.isRequired
|
||||
// }
|
||||
|
||||
function removeFile(ev) {
|
||||
// ev.preventDefault();
|
||||
ev.stopPropagation();
|
||||
|
||||
let conf = confirm('Are you sure you want to delete the file?') || false;
|
||||
if (conf == true) {
|
||||
Meteor.callAsync('RemoveFile', props.fileId)
|
||||
.catch (err => {
|
||||
console.log(err);
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
async function renameFile() {
|
||||
let validName = /[^a-zA-Z0-9 \.:\+()\-_%!&]/gi;
|
||||
let prompt = window.prompt('New file name?', props.fileName);
|
||||
|
||||
// Replace any non valid characters, also do this on the server
|
||||
if (prompt) {
|
||||
prompt = prompt.replace(validName, '-');
|
||||
prompt.trim();
|
||||
}
|
||||
|
||||
if (!_.isEmpty(prompt)) {
|
||||
await Meteor.callAsync('RenameFile', props.fileId, prompt)
|
||||
.catch(err => {
|
||||
console.log(err);
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return <div className="m-t-sm">
|
||||
<img src={props.fileUrl} alt={props.fileName} style={{maxWidth: `200px`, maxHeight: `200px`}}/>
|
||||
|
||||
<div className="row">
|
||||
<div className="col-md-12">
|
||||
<strong>{props.fileName}</strong>
|
||||
<div className="m-b-sm">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="row">
|
||||
<div className="col-md-3">
|
||||
<button onClick={renameFile} className="btn btn-outline btn-primary btn-sm">
|
||||
Rename
|
||||
</button>
|
||||
</div>
|
||||
|
||||
|
||||
<div className="col-md-3">
|
||||
<a href={props.fileUrl} className="btn btn-outline btn-primary btn-sm"
|
||||
target="_blank">View</a>
|
||||
</div>
|
||||
|
||||
<div className="col-md-2">
|
||||
<button onClick={removeFile} className="btn btn-outline btn-danger btn-sm">
|
||||
Delete
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="col-md-4">
|
||||
Size: {props.fileSize}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
export default IndividualFile;
|
||||
86
imports/ui/files/IndividualFileStart.jsx
Normal file
86
imports/ui/files/IndividualFileStart.jsx
Normal file
@ -0,0 +1,86 @@
|
||||
import React from 'react';
|
||||
import { Meteor } from 'meteor/meteor';
|
||||
// import PropTypes from 'prop-types';
|
||||
|
||||
const IndividualFileStart = props => {
|
||||
|
||||
// propTypes: {
|
||||
// fileName: PropTypes.string.isRequired,
|
||||
// fileSize: PropTypes.number.isRequired,
|
||||
// fileUrl: PropTypes.string,
|
||||
// fileId: PropTypes.string.isRequired
|
||||
// }
|
||||
|
||||
function removeFile() {
|
||||
let conf = confirm('Are you sure you want to delete the file?') || false;
|
||||
if (conf == true) {
|
||||
Meteor.callAsync('RemoveFile', props.fileId, function (err, res) {
|
||||
if (err)
|
||||
console.log(err);
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
function renameFile() {
|
||||
|
||||
let validName = /[^a-zA-Z0-9 \.:\+()\-_%!&]/gi;
|
||||
let prompt = window.prompt('New file name?', props.fileName);
|
||||
|
||||
// Replace any non valid characters, also do this on the server
|
||||
if (prompt) {
|
||||
prompt = prompt.replace(validName, '-');
|
||||
prompt.trim();
|
||||
}
|
||||
|
||||
if (!_.isEmpty(prompt)) {
|
||||
Meteor.callAsync('RenameFile', props.fileId, prompt, function (err, res) {
|
||||
if (err)
|
||||
console.log(err);
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return <div className="m-t-sm">
|
||||
<a href={props.fileUrl} target="_blank" >
|
||||
<img
|
||||
className='imgEnt'
|
||||
src={props.fileUrl}
|
||||
alt={props.fileName}
|
||||
style={{maxWidth: `200px`, maxHeight: `200px`, transform: `rotate(${((Math.random() * 4) - 2)}deg`}}
|
||||
/>
|
||||
</a>
|
||||
|
||||
{/* <div className="row">
|
||||
<div className="col-md-12">
|
||||
<strong>{props.fileName}</strong>
|
||||
<div className="m-b-sm">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="row">
|
||||
<div className="col-md-3">
|
||||
<button onClick={renameFile} className="btn btn-outline btn-primary btn-sm">
|
||||
Rename
|
||||
</button>
|
||||
</div>
|
||||
|
||||
|
||||
<div className="col-md-3">
|
||||
<a href={props.fileUrl} className="btn btn-outline btn-primary btn-sm" target="_blank">View</a>
|
||||
</div>
|
||||
*/}
|
||||
|
||||
<div className="col-md-2">
|
||||
<button onClick={removeFile} className="btn btn-outline btn-danger btn-sm">
|
||||
Delete
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="col-md-4">
|
||||
Size: {props.fileSize}
|
||||
</div>
|
||||
{/* </div> */}
|
||||
</div>
|
||||
}
|
||||
export default IndividualFileStart;
|
||||
26
imports/ui/files/ListPersons.jsx
Normal file
26
imports/ui/files/ListPersons.jsx
Normal file
@ -0,0 +1,26 @@
|
||||
import React from 'react';
|
||||
import { useTracker } from 'meteor/react-meteor-data';
|
||||
|
||||
const ListPersons = () => {
|
||||
|
||||
return <ul class="list-group">
|
||||
{
|
||||
persons.map((person, i) => {
|
||||
return <li class="list-group-item">
|
||||
{{#if update _id}}
|
||||
{{> quickForm type="update" collection="Persons" doc=this id=getFormId}}
|
||||
<button data-button-update class="btn btn-danger">Cancel</button>
|
||||
{{else}}
|
||||
<div class="jumbotron" style='background-image: url("{{#each backgroundPic.each}}{{link}}{{/each}}");'>
|
||||
<h2>{{name}}</h2>
|
||||
{{#each profilePic.each}}
|
||||
<img style="max-width:150px;max-height:150px" src="{{link}}"/>
|
||||
{{/each}}
|
||||
</div>
|
||||
<button data-button-update class="btn btn-default">Update</button>
|
||||
{{/if}}
|
||||
</li>
|
||||
})
|
||||
}
|
||||
</ul>
|
||||
}
|
||||
87
imports/ui/files/LlistaArxiusEnt.jsx
Normal file
87
imports/ui/files/LlistaArxiusEnt.jsx
Normal file
@ -0,0 +1,87 @@
|
||||
import { useTracker } from 'meteor/react-meteor-data';
|
||||
import { Meteor } from 'meteor/meteor';
|
||||
import React, { useState, useRef } from 'react';
|
||||
// import PropTypes from 'prop-types';
|
||||
import { FilesCol } from '/imports/api/files.js';
|
||||
|
||||
import IndividualFileEnt from '/imports/ui/files/IndividualFileEnt.jsx';
|
||||
|
||||
import _ from 'lodash';
|
||||
|
||||
|
||||
|
||||
const LlistaArxiusEnt = (props) => {
|
||||
|
||||
const files = useTracker(() => {
|
||||
const filesHandle = Meteor.subscribe('files.all');
|
||||
// const docsReadyYet = filesHandle.ready();
|
||||
const files = FilesCol?.find({meta:{userId: props.uidProvisional || Meteor.userId(), entId: props.entId}}, {sort: {name: 1}}).fetch(); // Meteor.userId() ?? "nop"
|
||||
|
||||
return files;
|
||||
});
|
||||
|
||||
// This is our progress bar, bootstrap styled
|
||||
// Remove this function if not needed
|
||||
// function showUploads() {
|
||||
// //console.log('**********************************', uploading);
|
||||
|
||||
// if (!_.isEmpty(uploading)) {
|
||||
// return <div>
|
||||
// {uploading.file.name}
|
||||
|
||||
// <div className="progress progress-bar-default">
|
||||
// <div style={{width: progress + '%'}} aria-valuemax="100"
|
||||
// aria-valuemin="0"
|
||||
// aria-valuenow={progress || 0} role="progressbar"
|
||||
// className="progress-bar">
|
||||
// <span className="sr-only">{progress}% Complete (success)</span>
|
||||
// <span>{progress}%</span>
|
||||
// </div>
|
||||
// </div>
|
||||
// </div>
|
||||
// }
|
||||
// }
|
||||
|
||||
{
|
||||
// debug("Rendering FileUpload",docsReadyYet);
|
||||
if (files /* && docsReadyYet*/) {
|
||||
|
||||
let fileCursors = files;
|
||||
|
||||
// Run through each file that the user has stored
|
||||
// (make sure the subscription only sends files owned by this user)
|
||||
let display = fileCursors.map((aFile, key) => {
|
||||
// console.log('A file: ', aFile.link(), aFile.get('name'))
|
||||
let link = FilesCol.findOne({_id: aFile._id}).link(); //The "view/download" link
|
||||
|
||||
// Send out components that show details of each file
|
||||
return <div
|
||||
key={'file' + key}
|
||||
>
|
||||
<IndividualFileEnt
|
||||
fileName={aFile.name}
|
||||
fileUrl={link}
|
||||
fileId={aFile._id}
|
||||
fileSize={aFile.size}
|
||||
/>
|
||||
</div>
|
||||
})
|
||||
|
||||
return <div
|
||||
style={{
|
||||
display: `flex`,
|
||||
justifyContent: `space-evenly`,
|
||||
alignItems: `center`,
|
||||
flexWrap: `wrap`
|
||||
}}
|
||||
>
|
||||
|
||||
{display}
|
||||
|
||||
</div>
|
||||
}
|
||||
else return <div>Loading file list</div>;
|
||||
}
|
||||
};
|
||||
|
||||
export default LlistaArxiusEnt;
|
||||
187
imports/ui/files/LlistaArxiusFolderTM.jsx
Normal file
187
imports/ui/files/LlistaArxiusFolderTM.jsx
Normal file
@ -0,0 +1,187 @@
|
||||
import { useTracker } from 'meteor/react-meteor-data';
|
||||
import { Meteor } from 'meteor/meteor';
|
||||
import React, { useState, useRef } from 'react';
|
||||
// import PropTypes from 'prop-types';
|
||||
import { FilesCol } from '/imports/api/files.js';
|
||||
|
||||
import FolderTreeIndividualFile from '/imports/ui/files/FolderTreeIndividualFile.jsx';
|
||||
|
||||
import _ from 'lodash';
|
||||
|
||||
import * as d3 from 'd3';
|
||||
|
||||
|
||||
const TreeMap = ({data, link}) => {
|
||||
|
||||
console.table(data);
|
||||
console.log("Link: ", link);
|
||||
|
||||
fetch(link)
|
||||
.then(x => x.text())
|
||||
.then(x => {
|
||||
if(x.lastIndexOf("\n")>0) {
|
||||
return x.substring(0, x.lastIndexOf("\n"));
|
||||
} else {
|
||||
return x;
|
||||
}
|
||||
//console.log(x);
|
||||
})
|
||||
// .then(x => x.json())
|
||||
.then(x => JSON.parse(x))
|
||||
|
||||
.then(x => {
|
||||
const dataset = x[0];
|
||||
|
||||
// Necessitem canviar el format de l'arbre i substituir "contents" per "children". De moment.
|
||||
function tmFormat(arbre) {
|
||||
|
||||
if (arbre.hasOwnProperty("contents")) {
|
||||
|
||||
arbre.contents.forEach(node => {
|
||||
|
||||
let nodeMod;
|
||||
|
||||
if (node.hasOwnProperty("children")) {
|
||||
nodeMod = {
|
||||
...node,
|
||||
children: node.contents,
|
||||
value: node.size
|
||||
};
|
||||
} else {
|
||||
nodeMod = {
|
||||
...node,
|
||||
value: node.size
|
||||
}
|
||||
;
|
||||
}
|
||||
|
||||
return tmFormat(nodeMod);
|
||||
});
|
||||
|
||||
} else {
|
||||
|
||||
const nouArbre = {
|
||||
...arbre,
|
||||
value: arbre.size
|
||||
};
|
||||
|
||||
return nouArbre;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
const tmData = tmFormat(dataset);
|
||||
|
||||
const hierarchyTree = d3.hierarchy(tmData)
|
||||
.sum(d => d.value) //sum every child's values
|
||||
.sort((a, b) => b.value - a.value)
|
||||
;
|
||||
|
||||
//const hierarchyTree = d3.hierarchy(tmData);
|
||||
|
||||
console.log("Dataset: ", dataset);
|
||||
console.log("TMData: ", tmData);
|
||||
console.log("Hierarchy: ", hierarchyTree);
|
||||
})
|
||||
// .then(x => x.json())
|
||||
// .then(x => console.log(x))
|
||||
//.then(x => console.table(x))
|
||||
|
||||
;
|
||||
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
const LlistaArxiusFolderTM = (props) => {
|
||||
|
||||
const files = useTracker(() => {
|
||||
const filesHandle = Meteor.subscribe('files.folderTree');
|
||||
// const docsReadyYet = filesHandle.ready();
|
||||
const files = FilesCol?.find({'meta.type': 'folderTree'}, {sort: {name: 1}}).fetch(); // Meteor.userId() ?? "nop"
|
||||
|
||||
return files;
|
||||
});
|
||||
|
||||
|
||||
// const methodCall = (methodName, ...args) =>
|
||||
// new Promise((resolve, reject) => {
|
||||
// Meteor.call(methodName, ...args, (error, result) => {
|
||||
// if (error) reject(error);
|
||||
// else resolve(result);
|
||||
// });
|
||||
// });
|
||||
// ;
|
||||
|
||||
// const files = await methodCall('getFolderTreeFiles');
|
||||
|
||||
// This is our progress bar, bootstrap styled
|
||||
// Remove this function if not needed
|
||||
// function showUploads() {
|
||||
// //console.log('**********************************', uploading);
|
||||
|
||||
// if (!_.isEmpty(uploading)) {
|
||||
// return <div>
|
||||
// {uploading.file.name}
|
||||
|
||||
// <div className="progress progress-bar-default">
|
||||
// <div style={{width: progress + '%'}} aria-valuemax="100"
|
||||
// aria-valuemin="0"
|
||||
// aria-valuenow={progress || 0} role="progressbar"
|
||||
// className="progress-bar">
|
||||
// <span className="sr-only">{progress}% Complete (success)</span>
|
||||
// <span>{progress}%</span>
|
||||
// </div>
|
||||
// </div>
|
||||
// </div>
|
||||
// }
|
||||
// }
|
||||
|
||||
{
|
||||
// debug("Rendering FileUpload",docsReadyYet);
|
||||
if (files /* && docsReadyYet*/) {
|
||||
|
||||
let fileCursors = files;
|
||||
|
||||
// Run through each file that the user has stored
|
||||
// (make sure the subscription only sends files owned by this user)
|
||||
let display = fileCursors.map((aFile, key) => {
|
||||
// console.log('A file: ', aFile.link(), aFile.get('name'))
|
||||
let link = FilesCol.findOne({_id: aFile._id}).link(); //The "view/download" link
|
||||
|
||||
// Send out components that show details of each file
|
||||
return <>
|
||||
<div
|
||||
key={'file' + key}
|
||||
>
|
||||
<FolderTreeIndividualFile
|
||||
fileName={aFile.name}
|
||||
fileUrl={link}
|
||||
fileId={aFile._id}
|
||||
fileSize={aFile.size}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<TreeMap data={aFile} link={link} />
|
||||
</>
|
||||
})
|
||||
|
||||
return <div
|
||||
style={{
|
||||
display: `flex`,
|
||||
justifyContent: `space-evenly`,
|
||||
alignItems: `center`,
|
||||
flexWrap: `wrap`
|
||||
}}
|
||||
>
|
||||
|
||||
{display}
|
||||
|
||||
</div>
|
||||
}
|
||||
else return <div>Loading file list</div>;
|
||||
}
|
||||
};
|
||||
|
||||
export default LlistaArxiusFolderTM;
|
||||
191
server/main.js
191
server/main.js
@ -1,12 +1,13 @@
|
||||
import { Meteor } from 'meteor/meteor';
|
||||
import { PoblesCollection } from '/imports/api/pobles.js';
|
||||
import { check } from "meteor/check";
|
||||
// import { check } from "meteor/check";
|
||||
|
||||
import { Roles } from 'meteor/roles';
|
||||
import { ROLS_GLOBALS, ROLS_DE_POBLE } from '../imports/roles';
|
||||
import { NecessitatsCollection } from '../imports/api/necessitats';
|
||||
import { TipusCollection } from '../imports/api/tipus';
|
||||
import { CodisCollection } from '../imports/api/codis';
|
||||
import { Avatars } from '../imports/api/files';
|
||||
// import { Codis } from '../imports/ui/Codis';
|
||||
|
||||
async function insertPoble({ nomPoble, cp, comarca }) {
|
||||
@ -439,11 +440,11 @@ Meteor.methods({
|
||||
const ara = new Date();
|
||||
let dataIni, dataFi;
|
||||
|
||||
console.log("codiObj.periode_validesa_ini: ", await codiObj.periode_validesa_ini);
|
||||
console.log("codiObj.condIni: ", await codiObj.condIni);
|
||||
|
||||
if (codiObj.act_cond === "on") {
|
||||
dataIni = new Date(await codiObj.periode_validesa_ini);
|
||||
dataFi = new Date(await codiObj.periode_validesa_fi);
|
||||
if (codiObj.absCond === "cond") {
|
||||
dataIni = new Date(await codiObj.condIni);
|
||||
dataFi = new Date(await codiObj.condFi);
|
||||
}
|
||||
// const dataIni = codiObj.act_cond === "on" ? new Date(codiObj.periode_validesa_ini) : null;
|
||||
// const dataFi = codiObj.act_cond === "on" ? new Date(codiObj.periode_validesa_fi) : null;
|
||||
@ -452,12 +453,12 @@ Meteor.methods({
|
||||
console.log("ara: ", ara);
|
||||
console.log("dataIni: ", dataIni);
|
||||
console.log("dataFi: ", dataFi);
|
||||
console.log(`codiObj.act_cond === "on"`, codiObj.act_cond === "on");
|
||||
console.log(`codiObj.absCond`, codiObj.absCond);
|
||||
|
||||
try {
|
||||
console.log(`APLICANT CODI "${codi}" sobre "${userId}".`); // Comprovant si ${Meteor.userId()} és Admin: `, esAdmin);
|
||||
|
||||
if ((codiObj.act_cond==="on" && (ara >= dataIni && ara <= dataFi)) || codiObj.act_abs) {
|
||||
if ((codiObj.absCond==="cond" && (ara >= dataIni && ara <= dataFi)) || codiObj.actAbs ) {
|
||||
Roles.addUsersToRolesAsync(userId, codiObj.rol, codiObj.ambit);
|
||||
}
|
||||
|
||||
@ -467,6 +468,182 @@ Meteor.methods({
|
||||
|
||||
},
|
||||
|
||||
async 'registraUsuariAmbAvatarICodi'(uObj, codi, avatar) {
|
||||
|
||||
if (codi) {
|
||||
|
||||
console.log("+codi");
|
||||
|
||||
if (avatar) {
|
||||
|
||||
console.log("+avatar");
|
||||
|
||||
// Upload the avatar to GridFS
|
||||
const avatarId = Avatars.insert(avatar.file, (err, fileObj) => {
|
||||
if (err) {
|
||||
throw new Meteor.Error('avatar-upload-failed', 'Failed to upload avatar');
|
||||
}
|
||||
});
|
||||
|
||||
const codiObj = await CodisCollection.findOneAsync({codi});
|
||||
|
||||
// Create the new user
|
||||
const userId = Accounts.createUserAsync({
|
||||
...uObj,
|
||||
profile: {
|
||||
avatar: avatarId,
|
||||
},
|
||||
});
|
||||
|
||||
// Return the new user's ID
|
||||
// return userId;
|
||||
|
||||
// const userId = await Accounts.createUserAsync(uObj);
|
||||
|
||||
const ara = new Date();
|
||||
let dataIni, dataFi;
|
||||
|
||||
console.log("codiObj.condIni: ", await codiObj.condIni);
|
||||
|
||||
if (codiObj.absCond === "cond") {
|
||||
dataIni = new Date(await codiObj.condIni);
|
||||
dataFi = new Date(await codiObj.condFi);
|
||||
}
|
||||
// const dataIni = codiObj.act_cond === "on" ? new Date(codiObj.periode_validesa_ini) : null;
|
||||
// const dataFi = codiObj.act_cond === "on" ? new Date(codiObj.periode_validesa_fi) : null;
|
||||
|
||||
console.log("codiObj: ", codiObj);
|
||||
console.log("ara: ", ara);
|
||||
console.log("dataIni: ", dataIni);
|
||||
console.log("dataFi: ", dataFi);
|
||||
console.log(`codiObj.absCond`, codiObj.absCond);
|
||||
|
||||
try {
|
||||
console.log(`APLICANT CODI "${codi}" sobre "${userId}".`); // Comprovant si ${Meteor.userId()} és Admin: `, esAdmin);
|
||||
|
||||
if ((codiObj.absCond === "cond" && (ara >= dataIni && ara <= dataFi)) || codiObj.absActiu) {
|
||||
Roles.addUsersToRolesAsync(userId, codiObj.rol, codiObj.ambit);
|
||||
}
|
||||
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
console.log("-avatar");
|
||||
|
||||
const codiObj = await CodisCollection.findOneAsync({codi});
|
||||
|
||||
const userId = await Accounts.createUserAsync({
|
||||
...uObj,
|
||||
profile: {
|
||||
avatar: null
|
||||
}
|
||||
});
|
||||
|
||||
const ara = new Date();
|
||||
let dataIni, dataFi;
|
||||
|
||||
console.log("codiObj.condIni: ", await codiObj.condIni);
|
||||
|
||||
if (codiObj.absCond === "cond") {
|
||||
dataIni = new Date(await codiObj.condIni);
|
||||
dataFi = new Date(await codiObj.condFi);
|
||||
}
|
||||
// const dataIni = codiObj.act_cond === "on" ? new Date(codiObj.periode_validesa_ini) : null;
|
||||
// const dataFi = codiObj.act_cond === "on" ? new Date(codiObj.periode_validesa_fi) : null;
|
||||
|
||||
console.log("codiObj: ", codiObj);
|
||||
console.log("ara: ", ara);
|
||||
console.log("dataIni: ", dataIni);
|
||||
console.log("dataFi: ", dataFi);
|
||||
console.log(`codiObj.absCond`, codiObj.absCond);
|
||||
|
||||
try {
|
||||
console.log(`APLICANT CODI "${codi}" sobre "${userId}".`); // Comprovant si ${Meteor.userId()} és Admin: `, esAdmin);
|
||||
|
||||
if ((codiObj.absCond === "cond" && (ara >= dataIni && ara <= dataFi)) || codiObj.absActiu) {
|
||||
Roles.addUsersToRolesAsync(userId, codiObj.rol, codiObj.ambit);
|
||||
}
|
||||
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
// const codiObj = await CodisCollection.findOneAsync({codi});
|
||||
|
||||
console.log("-codi");
|
||||
|
||||
const userId = await Accounts.createUserAsync(uObj);
|
||||
|
||||
// const ara = new Date();
|
||||
// let dataIni, dataFi;
|
||||
|
||||
// console.log("codiObj.periode_validesa_ini: ", await codiObj.periode_validesa_ini);
|
||||
|
||||
// if (codiObj.act_cond === "on") {
|
||||
// dataIni = new Date(await codiObj.periode_validesa_ini);
|
||||
// dataFi = new Date(await codiObj.periode_validesa_fi);
|
||||
// }
|
||||
// const dataIni = codiObj.act_cond === "on" ? new Date(codiObj.periode_validesa_ini) : null;
|
||||
// const dataFi = codiObj.act_cond === "on" ? new Date(codiObj.periode_validesa_fi) : null;
|
||||
|
||||
// console.log("codiObj: ", codiObj);
|
||||
// console.log("ara: ", ara);
|
||||
// console.log("dataIni: ", dataIni);
|
||||
// console.log("dataFi: ", dataFi);
|
||||
// console.log(`codiObj.act_cond === "on"`, codiObj.act_cond === "on");
|
||||
|
||||
try {
|
||||
// console.log(`APLICANT CODI "${codi}" sobre "${userId}".`); // Comprovant si ${Meteor.userId()} és Admin: `, esAdmin);
|
||||
|
||||
// if ((codiObj.act_cond==="on" && (ara >= dataIni && ara <= dataFi)) || codiObj.act_abs) {
|
||||
Roles.addUsersToRolesAsync(userId, 'usuari', 'GENERAL');
|
||||
// }
|
||||
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// Check if the username and email are valid
|
||||
// if (!username || !email || !password) {
|
||||
// throw new Meteor.Error('invalid-input', 'Please fill in all fields');
|
||||
// }
|
||||
|
||||
// // Check if the avatar is a valid file
|
||||
// if (!avatar || !avatar.file) {
|
||||
// throw new Meteor.Error('invalid-avatar', 'Please select a valid avatar image');
|
||||
// }
|
||||
|
||||
// // Upload the avatar to GridFS
|
||||
// const avatarId = Avatars.insert(avatar.file, (err, fileObj) => {
|
||||
// if (err) {
|
||||
// throw new Meteor.Error('avatar-upload-failed', 'Failed to upload avatar');
|
||||
// }
|
||||
// });
|
||||
|
||||
console.log("-avatar-codi");
|
||||
|
||||
// Create the new user
|
||||
const userId = Accounts.createUserAsync({
|
||||
...uObj,
|
||||
profile: {
|
||||
avatar: null
|
||||
}
|
||||
});
|
||||
|
||||
// Return the new user's ID
|
||||
return userId;
|
||||
},
|
||||
|
||||
'usaCodiAmbUsuari': async function (userId, codi) {
|
||||
// const esAdmin = await Roles.userIsInRoleAsync(Meteor.userId(), "admin");
|
||||
const codiObj = await CodisCollection.find({codi}).fetchAsync();
|
||||
|
||||
Loading…
Reference in New Issue
Block a user