How to draw separater in giftedchat? - javascript

I would like to draw separator such like "---- alredy read ----" with
giftedchat (https://github.com/FaridSafi/react-native-gifted-chat).
I think it is basic function for chat program, and can do with giftedchat.
I googled a lot, but can't find the way.
Would you teach me how to? I wolud like to draw like below.
|----------|
| Hello |
|----------|
--------- alredy read --------
|----------|
| Hi |
|----------|

I think you may use System Message to achieve this. The example is already shows in the React-Native-Gifted-Chat.
e.g. System Message
{
_id: 1,
text: 'This is a system message',
createdAt: new Date(Date.UTC(2016, 5, 11, 17, 20, 0)),
system: true,
// Any additional custom parameters are passed through
}
Then you may use the props renderSystemMessage to style your message.
const renderSystemMessage = (props) => {
return <Text>-----{props.currentMessage.text}-----</Text>;
};

Related

Angular #Input type accepts faulty model

I am trying to make #Input to my component with a model that looks something like this
interface Car {
sail?: never
tires: number
weight: number
}
interface Boat {
tires?: never
sail: boolean
weight: number
}
export type Vehicle = Car | Boat;
Goal is to accept inputs like this: (this works and does not give me any error)
#Input() Car: Vehicle = {weight: 2500, tires: 4}
#Input() Boat: Vehicle = {weight: 2500, sail: true}
This gives me error as expected
#Input() Mixed: Vehicle = {weight: 2500, tires: 4, sail: true}
And in my html file i have this (should only be able to input tires or sail not booth, should throw error)
<component [car]="{weight: 2500, tires: 4, sail: true}"></component >
And the Input from the html file doesn't give me any error as expected from Angular. But what I am not understanding is how the Vehicle type can be populated with faulty data. What is the best way to deal with this?
In the HTML there is no type-checking, since this is specific to Typescript.
However, you can declare the Vehicle in your .ts file and use the variable within your HTML, this way you should get an error as expected.

Event data not being populated dynamically in Fullcalendar 4

I have a db which contains all the events for a month/period. I've used http.get and got the JSON file. This file has additional data which has to be modified or formatted before it can be used as an event. Eg: For event title: name +id .
So I've formatted it accordingly and storing it as a string in a local variable. I'm trying to assign this variable as event data. But this is not being populated.
I've already tried converting the string to Array,by using Array.to(var). The result is still the same. Ive also tried to store it in a uri and passing the same as event data, url: uri. This also failed to display the event.
Read in fullcalendar docs about addEvent method. But Im relatively new to Angular 8 so have no idea how to implement that.
So, rn theres no errors, but i seem to be missing the big picture. Ill put out all the things im doing.
Theres an interface evtdata:
export interface Evtdata {
startRecur?: any,
endRecur?: any,
startTime?: any,
endTime?: any,
title?: any,
daysOfWeek?: any
}
Updated Component:
this.options$ = this.evts.getEventDat().pipe(
map(data => {
for (var i = 0; i < this.data.length; i++) {
this.eventdat[i].startRecur = "\""+data[i].startDate+"\"";
this.eventdat[i].endRecur = "\""+data[i].endDate+"\"";
this.eventdat[i].startTime ="\""+ data[i].startTime+"\"";
this.eventdat[i].endTime = "\""+data[i].endTime+"\"";
this.eventdat[i].title ="\""+ data[i].name + " " + data[i].wwid+" "+data[i].sId+"\"";
this.eventdat[i].daysOfWeek ="\""+ "[" + data[i].workDays + "]"+"\"";
}
return {
businessHours: {
daysOfWeek: [1, 2, 3, 4, 5],
startTime: '00:00',
endTime: '24:00',
},
editable: true,
customButtons: {
},
header: {
left: 'prev,next',
center: 'title',
right: 'dayGridMonth,listView,timeGridWeek,timeGridDay'
},
plugins: [dayGridPlugin, interactionPlugin, listPlugin, bootstrapPlugin, timeGrigPlugin],
events: this.eventdat
}
})
);
calendar.html
<full-calendar
*ngIf="options$ | async"
#fullcalendar
themeSystem="bootstrap"
[businessHours]="(options$ | async).businessHours"
[editable]="true"
[events]="(options$ | async).events"
[header]="(options$ | async).header"
[customButtons]="(options$ | async).customButtons"
[plugins]="(options$ | async).plugins"
(addEventSource)="addEventSource($event)"
(eventClick)="eventClick($event)"
(setProp)="setProp($event)"
></full-calendar>
Ive added multiple logs to display the data, data is getting saved and is being executed in the required order. Events are still not being populated.
You're doing all kinds of manipulations of the data, few of which I really understand. If you're doing an HTTP call, it returns an Observable. You can then pipe in a map operator where you add/remove/modify anything you need to. You can then use the async pipe in the template to avoid all of the subscription problems.
ngOnInit() {
this.options = this.evts.getEventDat().pipe(
map(data => {
// format your options object here, using the data object as needed
// don't forget that this map operator is NOT the same as Array map
// you can of course do an Array map in here as well if you need to
})
);
}
Then, in the template:
<full-calendar
*ngIf="options | async"
#fullcalendar
themeSystem="bootstrap"
[businessHours]="(options | async).businessHours"
[editable]="true"
[events]="(options | async).events"
[header]="(options | async).header"
[customButtons]="(options | async).customButtons"
[plugins]="(options | async).plugins"
(eventClick)="eventClick($event)"
(setProp)="setProp($event)"
></full-calendar>
I still don't understand a lot of your formatting. It feels like you're trying to manipulate JSON as a string, which you don't need to do. You can manipulate it as an object, which is kinda the whole point.
P.S. If you need to go back and forth between JSON and string notation, use JSON.parse(myString) and JSON.stringify(myObject).

Strongly typed Immutable.js Records in TypeScript

I'm unable to find a good resource for this question. Essentially I want to describe types for my data using an interface in TypeScript, but my data is Immutable.js records which appears to complicate matters, please see my example below.
interface tree extends Immutable.Map<string, any> {
readonly id: number,
readonly type: number
}
let trees = Immutable.List<tree[]>([
Map<tree>({
id: 101,
type: 1
}),
Map<tree>({
id: 201,
type: 3
})
])
Questions with the above:
Why do I have to repeat the type of each map in my list? Shouldn't the type be simply be declared by the <tree[]> when creating the list? And then any Map added to the list be type checked against this?
At present this example errors, stating that "property 'id' is incompatible with index signature. Type 'number' is not assignable to type 'tree'. Which makes sense! However, reading the documentation, I can't work out how to get it to work? Reading the docs it states I need an ID but I want an array of maps, my signature in this case is just standard array ID's if I not much mistaken?
I've been working on this for days and I simply can't get it to work, it should be this simple according to everything I've read.
Any help would be greatly appreciated.
You are creating a List of arrays of trees, which is an extended Map. This is what it should look like:
let trees = Immutable.List<tree[]>(
[ // List
[ // Array
<tree>Immutable.Map<any>({
id: 101,
type: 1
}),
<tree>Immutable.Map<any>({
id: 201,
type: 3
})
]
]
);
Answering your questions:
You are not repeating the type of each map. Actually, you are calling a method Map that builds a map from an object. I added the <tree> cast because it is an array of trees, not maps.
You are trying something like:
var singleTree: tree = Immutable.Map<tree>(
{ id: 101, type: 1 }
);
But your tree is a map of the any type. So, this is the right syntax:
let singleTree: tree = <tree>Immutable.Map<any>(
{ id: 101, type: 1 }
);
For the code above, we can simplify and force a type check if we create a tree function to wrap the Map function, so, the final solution would be:
function tree(obj: { [key: string]: any, id: number, type: number }): tree {
return <tree>Immutable.Map<any>(obj);
}
let trees = Immutable.List<tree[]>(
[ // List
[ // Array
tree({
id: 101,
type: 1
}),
tree({
id: 201,
type: 3
})
]
]
);

How to use/define Enums with Flow type checking?

I'm trying to migrate an existing codebase to use Flow. Since this project started without Flow, I'm using a pretty typical JS pattern for enums and such.
Here are a few definitions I want to
export const LOAN_STATUS = {
PENDING: 'pending',
CURRENT: 'current',
DUE: 'due',
OVERDUE: 'overdue',
PENDING_PAYMENT: 'pending_payment',
CHARGED_OFF: 'charged_off',
VOIDED: 'voided',
DISPUTED: 'disputed',
REFUNDED: 'refunded',
SETTLED: 'settled',
}
export const ACTIVE_LOAN_STATUS = [
LOAN_STATUS.OVERDUE,
LOAN_STATUS.CURRENT,
LOAN_STATUS.DUE,
LOAN_STATUS.PENDING_PAYMENT,
]
Flow works fine until I import this file and it says I need to add type annotations. This seems odd -- why should I have to annotate objects that are entirely static and easily inferred?
Is there any way that define its type as "static" or "literal"?
So then I go about thinking how I'm going to add annotations to this. My first thought is just {[key: string]: string} and Array<string>. Flow works, but I'm realizing that these type definitions are totally worthless. So then I try this other approach:
type LoanStatusValues =
'pending' |
'current' |
'due' |
'overdue' |
'pending_payment' |
'charged_off' |
'voided' |
'disputed' |
'refunded' |
'settled'
type LoanStatusKeys =
'PENDING' |
'CURRENT' |
'DUE' |
'OVERDUE' |
'PENDING_PAYMENT' |
'CHARGED_OFF' |
'VOIDED' |
'DISPUTED' |
'REFUNDED' |
'SETTLED'
type ActiveLoanStatus =
"current" |
"due" |
"overdue" |
"pending_payment"
And I use the type annotations {[key: LoanStatusKeys]: LoanStatusValues} and Array<ActiveLoanStatus>. But even these annotations loose the fact that this is static!
It just seems so odd that I'm having to write this much duplicate code. And then if I want to convert just to Flow I can't actually use the types in JS. For example I might do this:
if (defs.ACTIVE_LOAN_STATUS.indexOf(loan.status) !== -1) {
}
Now if I want to use Flow types, I can't do anything like this:
type ActiveLoanStatus =
"current" |
"due" |
"overdue" |
"pending_payment"
if (loan.status isTypeOf ActiveLoanStatus) {
}
So how am I supposed to use these static enums? I must be doing this wrong!
To express an enum with flow you can use $Values utility in conjunction with frozen object type:
export const LOAN_STATUS = Object.freeze({
PENDING: 'pending',
CURRENT: 'current',
DUE: 'due',
OVERDUE: 'overdue',
PENDING_PAYMENT: 'pending_payment',
CHARGED_OFF: 'charged_off',
VOIDED: 'voided',
DISPUTED: 'disputed',
REFUNDED: 'refunded',
SETTLED: 'settled',
});
type LoanStatus = $Values<typeof LOAN_STATUS>;
export const ACTIVE_LOAN_STATUS: LoanStatus[] = [
LOAN_STATUS.OVERDUE,
LOAN_STATUS.CURRENT,
LOAN_STATUS.DUE,
LOAN_STATUS.PENDING_PAYMENT,
]
This works starting from 0.60.0 version.
Here is the most concise way to achieve this:
const activeLoanStatuses = {
current: 'current',
due: 'due',
overdue: 'overdue',
pending_payment: 'pending_payment'
};
const otherLoanStatuses = {
pending: 'pending',
charged_off: 'charged_off',
voided: 'voided',
disputed: 'disputed',
refunded: 'refunded',
settled: 'settled',
};
type ActiveLoanStatus = $Keys<typeof activeLoanStatuses>;
type LoanStatus = $Keys<typeof otherLoanStatuses> | ActiveLoanStatus;
const activeLoanStatusesMap: { [key: LoanStatus]: ?ActiveLoanStatus} = activeLoanStatuses;
if (activeLoanStatusesMap[loan.status]) {
}
While incredibly verbose, and non-scalable, this falls into Flow's "Disjoint Unions" case and such can be implemented using ===. As they mention on that page, Case Analysis is done via that operator, as javascript naturally does with switch-case statements.
In your case, that equates to:
switch(loan.status) {
'pending':
'current':
'due':
'overdue':
'pending_payment':
'charged_off':
'voided':
'disputed':
'refunded':
'settled':
// your behavior here
}
As I mentioned, this is highly verbose in code which uses your types, but to counter that, it has the benefit of defining your types without creating a boilerplate object- you simply define your literal options and union them together (your second implementation).
This has the obvious downside of coupling your type definition with your implementations of its consumers, so use with caution.

How to test an Ember model's computed property that has relations dependencies?

I'm writing Qunit tests to test An Ember model, but having a hard time testing computed properties that have a relation dependency (the computed property triggers another model's computed property).
The model that am testing (CoffeeScript):
Customer = DS.Model.extend
firstName: DS.attr('string')
lastName: DS.attr('string')
phones: DS.attr('embedded-list')
phone: (->
#get('phones.firstObject.number')
).property('phones.firstObject.number')
fullName: (->
[#get('lastName'), #get('firstName')].join(' ') )
).property('firstName','lastName')
The meeting Model:
Meeting = DS.Model.extend
customers: DS.hasMany('customer')
startAt: DS.attr('isodate')
status: DS.attr()
objective: DS.attr()
customerPhones: (->
phones = []
#get('customers').forEach (c) ->
c.get('phones').forEach (ph) ->
phones.push(ph.number)
phones
).property('customers.#each.phones')
firstCustomer: (->
#get('customers.firstObject')
).property('customers.firstObject')
firstCustomerFullName: (->
#get('firstCustomer.fullName')
).property('firstCustomer.fullName')
Now, testing customerPhones, and firstCustomerFullName is giving me a real hard time...
My test looks as follows:
`import { test, moduleForModel } from 'ember-qunit';`
moduleForModel('meeting', 'App.Meeting',{
needs: ['model:customer']
setup: ->
Ember.run do (t = #)->
->
customer = t.store().createRecord 'customer', firstName: 'John', lastName: 'Smith', phones:[]
customer.get('phones').addObject(Ember.Object.create({tag: 'home', number: '111222333'}))
customer.get('phones').addObject(Ember.Object.create({tag: 'work', number: '444555666'}))
t.subject().set('customers.content', Ember.ArrayProxy.create({content: []}));
t.subject().get('customers.content').pushObject(customer)
teardown: ->
},(container, context) ->
container.register 'store:main', DS.Store
container.register 'adapter:application', DS.FixtureAdapter
context.__setup_properties__.store = -> container.lookup('store:main')
)
test "it's a DS.Model", -> ok(#subject())
test "attributes: can be created with valid values", ->
meeting = #subject({objective: 'Follow up'})
Ember.run ->
equal(meeting.get('objective', 'Follow up'))
test "properties: firstCustomer & firstCustomerFullName & firstCustomerPhone", ->
meeting = #subject()
Ember.run ->
equal(meeting.get('firstCustomer.fullName'), 'Smith John')
equal(meeting.get('firstCustomer.phone'), '111222333')
Now, I used some techniques in this test, that I found in an answer here on Stack Overflow, but I can't seem to find it now.
That worked perfectly few days ago, now (it seems nonsense I know) whenever I run the test, it errors:
Assertion Failed: You cannot add 'meeting' records to this relationship (only 'meeting' allowed)
I don't know where the error is, nor how to fix it. Spent all the day monkeying around, No outcome.
How can I resolve this?
Okay, what I have so far is too much for a comment, so I'm going to do a WIP Answer.
I removed most of the run loops, they are only necessary for async processes.
I changed some of your computed properties to computed.alias properties
i.e.
phone: (->
#get('phones.firstObject.number')
).property('phones.firstObject.number')
to
phone: Ember.computed.alias('phones.firstObject.number')
I ripped out most of the setup, Ember Data eagerly loads the store on its own and will use fixture ids etc without specifying it. (this part can be put back it, it just isn't necessary in this context).
i.e.
},(container, context) ->
container.register 'store:main', DS.Store
container.register 'adapter:application', DS.FixtureAdapter
context.__setup_properties__.store = -> container.lookup('store:main')
And I apologize in advance, I'm not a fan of coffeescript, so I put it all in js. Now the question is, if you're still seeing any issues we may need to find out what versions of Ember, ED, and Ember Qunit you are using.
http://emberjs.jsbin.com/OxIDiVU/625/edit
I found this question looking for 'how to unit test a computed property that uses a hasMany'.
Here is a simple example of how I did it (thanks to Kitler):
Fridge Model:
foods: DS.hasMany('food', {async: true}),
inDateFoods: Ember.computed('foods.#each.{ignoreEndDate,endDate}', function() {
let foods = this.get('foods');
let now = moment();
return foods.filter(f => f.get(ignoreEndDate) || moment(c.get('endDate')).isAfter(now));
})
So say we now want to test inDateFoods in a unit test? Then do this in your fridge model test file:
import Ember from 'ember';
import { moduleForModel, test } from 'ember-qunit';
import Fridge from '../../../models/fridge';
Fridge.reopen({
foods: Ember.computed(() => [])
});
moduleForModel('fridge', 'Unit | Model | fridge', {
// Specify the other units that are required for this test.
needs: ['model:food']
});
test('filters correctly', function(assert) {
assert.expect(1);
let model = this.subject();
model.pushObject(Ember.Object.create({foods: [{id: 1, ignoreEndDate: false, endDate: '2050-03-08T00:00:00'});
assert.equal(model.get('inDateFoods.length'), 1);
});
They key here is to reopen your model to remove the has many, and push the object after doing this.subject. Before doing the reopen we were getting the error All elements of a hasMany relationship must be instances of DS.Model, you passed [[object Object]] error.

Categories