-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
8 changed files
with
324 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
/// | ||
/// IMPORTS | ||
/// | ||
|
||
import { DynamoDB, RCError, ResourceController, SES, EmailData, S3 } from 'idea-aws'; | ||
|
||
import { Message } from '../models/message'; | ||
import { UserProfile } from '../models/userProfile'; | ||
|
||
/// | ||
/// CONSTANTS, ENVIRONMENT VARIABLES, HANDLER | ||
/// | ||
|
||
const PROJECT = process.env.PROJECT; | ||
|
||
const DDB_TABLES = { messages: process.env.DDB_TABLE_messages, profiles: process.env.DDB_TABLE_userProfiles }; | ||
|
||
const SES_CONFIG = { | ||
sourceName: 'EGM', | ||
source: process.env.SES_SOURCE_ADDRESS, | ||
sourceArn: process.env.SES_IDENTITY_ARN, | ||
region: process.env.SES_REGION | ||
}; | ||
|
||
const S3_BUCKET_MEDIA = process.env.S3_BUCKET_MEDIA; | ||
const S3_USERS_CV_FOLDER = process.env.S3_USERS_CV_FOLDER; | ||
|
||
const ddb = new DynamoDB(); | ||
const ses = new SES(); | ||
const s3 = new S3(); | ||
|
||
export const handler = (ev: any, _: any, cb: any) => new Messages(ev, cb).handleRequest(); | ||
|
||
/// | ||
/// RESOURCE CONTROLLER | ||
/// | ||
|
||
class Messages extends ResourceController { | ||
message: Message; | ||
|
||
constructor(event: any, callback: any) { | ||
super(event, callback, { resourceId: 'messageId' }); | ||
} | ||
|
||
protected async checkAuthBeforeRequest(): Promise<void> { | ||
if (!this.resourceId) return; | ||
|
||
try { | ||
this.message = new Message( | ||
await ddb.get({ TableName: DDB_TABLES.messages, Key: { organizationId: this.resourceId } }) | ||
); | ||
} catch (err) { | ||
throw new RCError('Organization not found'); | ||
} | ||
} | ||
|
||
protected async getResource(): Promise<Message> { | ||
return this.message; | ||
} | ||
|
||
protected async putResource(): Promise<Message> { | ||
const oldResource = new Message(this.message); | ||
this.message.safeLoad(this.body, oldResource); | ||
|
||
return await this.putSafeResource(); | ||
} | ||
private async putSafeResource(opts: { noOverwrite?: boolean } = {}): Promise<Message> { | ||
const errors = this.message.validate(); | ||
if (errors.length) throw new RCError(`Invalid fields: ${errors.join(', ')}`); | ||
|
||
try { | ||
const putParams: any = { TableName: DDB_TABLES.messages, Item: this.message }; | ||
if (opts.noOverwrite) putParams.ConditionExpression = 'attribute_not_exists(messageId)'; | ||
await ddb.put(putParams); | ||
|
||
return this.message; | ||
} catch (err) { | ||
throw new RCError('Operation failed'); | ||
} | ||
} | ||
|
||
protected async patchResource(): Promise<void> { | ||
switch (this.body.action) { | ||
case 'SEND_USER_CONTACTS': | ||
return ; //await this.likeMessage() | ||
default: | ||
throw new RCError('Unsupported action'); | ||
} | ||
} | ||
|
||
protected async deleteResource(): Promise<void> { | ||
if (!this.cognitoUser.isAdmin()) throw new RCError('Unauthorized'); | ||
|
||
try { | ||
await ddb.delete({ TableName: DDB_TABLES.messages, Key: { messageId: this.resourceId } }); | ||
} catch (err) { | ||
throw new RCError('Delete failed'); | ||
} | ||
} | ||
|
||
protected async postResources(): Promise<Message> { | ||
this.message = new Message(this.body); | ||
this.message.messageId = await ddb.IUNID(PROJECT); | ||
|
||
return await this.putSafeResource({ noOverwrite: true }); | ||
} | ||
|
||
protected async getResources(): Promise<Message[]> { | ||
try { | ||
return (await ddb.scan({ TableName: DDB_TABLES.messages })) | ||
.map((x: Message) => new Message(x)); | ||
} catch (err) { | ||
throw new RCError('Operation failed'); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
import { isEmpty, Resource } from 'idea-toolbox'; | ||
|
||
export class Message extends Resource { | ||
messageId: string; | ||
senderId: string; | ||
senderName: string; | ||
text: string; | ||
|
||
load(x: any): void { | ||
super.load(x); | ||
this.messageId = this.clean(x.messageId, String); | ||
this.senderId = this.clean(x.senderId, String); | ||
this.senderName = this.clean(x.senderName, String); | ||
this.text = this.clean(x.text, String); | ||
} | ||
safeLoad(newData: any, safeData: any): void { | ||
super.safeLoad(newData, safeData); | ||
this.messageId = safeData.messageId; | ||
} | ||
validate(): string[] { | ||
const e = super.validate(); | ||
if (isEmpty(this.text)) e.push('message'); | ||
if (this.senderName && isEmpty(this.senderName)) e.push('sender'); | ||
return e; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,140 @@ | ||
import { Auth } from '@aws-amplify/auth'; | ||
import { | ||
IonContent, | ||
IonHeader, | ||
IonIcon, | ||
IonItem, | ||
IonItemDivider, | ||
IonLabel, | ||
IonList, | ||
IonPage, | ||
IonTitle, | ||
IonToolbar, | ||
useIonAlert, | ||
IonNote, | ||
IonTextarea, | ||
IonButton, | ||
IonText, | ||
IonItemGroup, | ||
} from '@ionic/react'; | ||
import { | ||
close, | ||
heartOutline, | ||
send, | ||
} from 'ionicons/icons'; | ||
import { useEffect, useState } from 'react'; | ||
|
||
import { UserProfile } from 'models/userProfile'; | ||
import { Message } from 'models/message'; | ||
|
||
import { isMobileMode } from '../utils'; | ||
import { | ||
isUserAdmin, getUserProfile, getMessages, | ||
sendMessage, | ||
deleteMessage, | ||
} from '../utils/data'; | ||
|
||
// TODO placeholder | ||
const allMessages = [{ | ||
messageId: "1234-uuid", | ||
senderId: "3456-uuid", | ||
senderName: "Jose Gonzalez", | ||
text: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam viverra diam quis odio hendrerit molestie. Nam iaculis nunc eget urna tincidunt, sit amet fringilla ex aliquet. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam malesuada molestie condimentum. Duis placerat enim vel ipsum gravida pellentesque sit amet ut sapien.", | ||
} as Message] | ||
|
||
const AppreciationPage: React.FC = () => { | ||
const [showAlert] = useIonAlert(); | ||
|
||
const [userIsAdmin, setUserIsAdmin] = useState(false); | ||
const [userProfile, setUserProfile] = useState<UserProfile>(); | ||
|
||
const [text, setText] = useState<string>(); | ||
const [messages, setMessages] = useState<Message[]>(); | ||
|
||
|
||
console.log(userProfile); | ||
useEffect(() => { | ||
const loadData = async () => { | ||
const userProfile = await getUserProfile(); | ||
setUserProfile(userProfile); | ||
|
||
setUserIsAdmin(await isUserAdmin()); | ||
|
||
|
||
setMessages(allMessages); // setMessages(await getMessages()); | ||
}; | ||
loadData(); | ||
}, []); | ||
|
||
|
||
const handleSendMessage = async () => { | ||
const message = { | ||
senderId: userProfile?.userId, | ||
senderName: userProfile?.getName(), | ||
text: text, | ||
} | ||
|
||
await sendMessage(message as Message); | ||
setText(""); | ||
} | ||
|
||
const handleDeleteMessage = async (message: Message) => { | ||
await deleteMessage(message); | ||
} | ||
|
||
return ( | ||
<IonPage> | ||
<IonHeader> | ||
{isMobileMode() ? ( | ||
<IonToolbar color="ideaToolbar"> | ||
<IonTitle>Appreciation</IonTitle> | ||
</IonToolbar> | ||
) : ( | ||
'' | ||
)} | ||
</IonHeader> | ||
<IonContent> | ||
<IonList style={{ maxWidth: isMobileMode() ? "100%" : "50%", margin: '0 auto' }}> | ||
{messages?.map(message => ( | ||
<IonItemGroup> | ||
<IonItem color="white"> | ||
<IonNote slot="start">{message.senderName}</IonNote> | ||
|
||
<IonButton fill="solid" slot="end" color="white"> | ||
<IonIcon icon={heartOutline} /> | ||
<IonNote style={{ marginLeft: '4px' }} slot="end">{0}</IonNote> | ||
</IonButton> | ||
|
||
{userIsAdmin && <IonButton fill="solid" slot="end" color="white" onClick={() => handleDeleteMessage(message)}> | ||
<IonIcon icon={close} /> | ||
<IonNote style={{ marginLeft: '4px' }} slot="end">Delete</IonNote> | ||
</IonButton>} | ||
|
||
</IonItem> | ||
<IonItem color="white" > | ||
<IonText style={{ paddingBottom: '12px' }}>{message.text}</IonText> | ||
</IonItem> | ||
</IonItemGroup> | ||
))} | ||
|
||
<IonItemDivider> | ||
<IonLabel>Write a Message</IonLabel> | ||
</IonItemDivider> | ||
|
||
<IonItemGroup color="white"> | ||
<IonItem color="white" > | ||
<IonTextarea value={text} onIonChange={e => setText(e.detail.value!)}></IonTextarea> | ||
<IonButton size="default" style={{ alignSelf: 'center' }} onClick={() => handleSendMessage()} > | ||
Send | ||
<IonIcon icon={send} slot="end"></IonIcon> | ||
</IonButton> | ||
</IonItem> | ||
</IonItemGroup> | ||
|
||
</IonList> | ||
</IonContent> | ||
</IonPage> | ||
); | ||
}; | ||
|
||
export default AppreciationPage; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.