Toggle navigation
Toggle navigation
This project
Loading...
Sign in
mobile
/
YH_RNComponent
·
Commits
Go to a project
GitLab
Go to group
Project
Activity
Files
Commits
Pipelines
0
Builds
0
Graphs
Milestones
Issues
0
Merge Requests
0
Members
Labels
Wiki
Forks
Network
Create a new issue
Download as
Email Patches
Plain Diff
Browse Files
Authored by
shangjf
8 years ago
Commit
d1c032699fbbebd484cd248edab4a73d96f704b9
1 parent
d789ccb0
站内信添加复制删除功能 review by 于良
Hide whitespace changes
Inline
Side-by-side
Showing
14 changed files
with
282 additions
and
82 deletions
js/message/components/list/EmptyContent.js
js/message/components/list/MessageList.js
js/message/components/list/MessageListBigIconCell.js
js/message/components/list/MessageListOrderCell.js
js/message/components/list/MessageListSmallIconCell.js
js/message/components/list/MessageListTextCell.js
js/message/components/message/Message.js
js/message/components/message/MessageCell.js
js/message/constants/actionTypes.js
js/message/containers/MessageListContainer.js
js/message/reducers/list/listActions.js
js/message/reducers/list/listReducer.js
js/message/reducers/message/messageInitialState.js
js/message/services/MessageListService.js
js/message/components/list/EmptyContent.js
View file @
d1c0326
...
...
@@ -24,7 +24,7 @@ export default class EmptyContent extends Component {
text
=
'会员等级变更提醒、会员生日福利'
;
break
;
case
'2'
:
text
=
'
新注册用户提示新人专享优惠券信息
'
;
text
=
'
我的优惠券、红包、有货币
'
;
break
;
case
'3'
:
text
=
'没有收到任何关于你的消息'
;
...
...
js/message/components/list/MessageList.js
View file @
d1c0326
...
...
@@ -10,6 +10,7 @@ import ReactNative, {
Dimensions
,
InteractionManager
,
Platform
,
Clipboard
,
}
from
'react-native'
;
import
LoadMoreIndicator
from
'../../../common/components/LoadMoreIndicator'
;
...
...
@@ -20,6 +21,7 @@ import MessageListSmallIconCell from './MessageListSmallIconCell';
import
MessageListBigIconCell
from
'./MessageListBigIconCell'
;
import
MessageListTextCell
from
'./MessageListTextCell'
;
import
MessageListOrderCell
from
'./MessageListOrderCell'
;
import
YH_ToolTips
from
'../../../common/components/YH_ToolTips'
export
default
class
MessageList
extends
Component
{
constructor
(
props
)
{
...
...
@@ -29,8 +31,19 @@ export default class MessageList extends Component {
rowHasChanged
:
(
r1
,
r2
)
=>
!
Immutable
.
is
(
r1
,
r2
),
});
this
.
loadMessageListCell
=
this
.
loadMessageListCell
.
bind
(
this
);
this
.
onLongPressListItem
=
this
.
onLongPressListItem
.
bind
(
this
);
this
.
_copy
=
this
.
_copy
.
bind
(
this
);
this
.
_delete
=
this
.
_delete
.
bind
(
this
);
this
.
showToolTip
=
this
.
showToolTip
.
bind
(
this
);
this
.
state
=
{
showToolTips
:
false
,
index
:
0
}
}
componentDidMount
()
{
}
onLongPressListItem
(
itemData
,
index
)
{
this
.
setState
({
showToolTips
:
true
,
index
:
index
});
}
loadMessageListCell
(
rowData
,
rowID
)
{
...
...
@@ -46,15 +59,21 @@ export default class MessageList extends Component {
case
205
:
case
206
:
case
207
:
case
208
:
case
209
:
{
return
(
<
MessageListSmallIconCell
itemData
=
{
rowData
}
onPressListItem
=
{(
itemData
)
=>
{
this
.
props
.
onPressListItem
&&
this
.
props
.
onPressListItem
(
itemData
,
rowID
)
<
MessageListSmallIconCell
itemData
=
{
rowData
}
onPressListItem
=
{(
itemData
)
=>
{
this
.
setState
({
showToolTips
:
false
});
this
.
props
.
onPressListItem
&&
this
.
props
.
onPressListItem
(
itemData
,
rowID
)
}
}
}
/
>
onLongPressListItem
=
{(
itemData
)
=>
{
this
.
onLongPressListItem
(
itemData
,
rowID
);
}}
/
>
);
}
break
;
...
...
@@ -66,9 +85,13 @@ export default class MessageList extends Component {
<
MessageListBigIconCell
itemData
=
{
rowData
}
onPressListItem
=
{(
itemData
)
=>
{
this
.
setState
({
showToolTips
:
false
});
this
.
props
.
onPressListItem
&&
this
.
props
.
onPressListItem
(
itemData
,
rowID
)
}
}
onLongPressListItem
=
{(
itemData
)
=>
{
this
.
onLongPressListItem
(
itemData
,
rowID
);
}}
/
>
);
}
...
...
@@ -80,14 +103,19 @@ export default class MessageList extends Component {
case
304
:
case
305
:
case
402
:
case
404
:
{
return
(
<
MessageListOrderCell
itemData
=
{
rowData
}
onPressListItem
=
{(
itemData
)
=>
{
this
.
setState
({
showToolTips
:
false
});
this
.
props
.
onPressListItem
&&
this
.
props
.
onPressListItem
(
itemData
,
rowID
)
}
}
onLongPressListItem
=
{(
itemData
)
=>
{
this
.
onLongPressListItem
(
itemData
,
rowID
);
}}
/
>
);
}
...
...
@@ -99,6 +127,9 @@ export default class MessageList extends Component {
return
(
<
MessageListTextCell
itemData
=
{
rowData
}
onLongPressListItem
=
{(
itemData
)
=>
{
this
.
onLongPressListItem
(
itemData
);
}}
/
>
);
}
...
...
@@ -110,13 +141,47 @@ export default class MessageList extends Component {
}
}
_copy
(
rowData
)
{
this
.
setState
({
showToolTips
:
false
});
let
copyString
=
rowData
.
get
(
'title'
,
''
)
+
' '
+
rowData
.
get
(
'body'
,{}).
get
(
'content'
,
''
);
Clipboard
.
setString
(
copyString
);
}
_delete
(
rowData
)
{
this
.
setState
({
showToolTips
:
false
});
this
.
props
.
deleteListItem
&&
this
.
props
.
deleteListItem
(
rowData
);
}
showToolTip
(
rowID
,
rowData
)
{
let
{
showToolTips
,
index
}
=
this
.
state
;
let
show
=
(
index
==
rowID
)
&&
showToolTips
;
if
(
show
)
{
return
(
<
YH_ToolTips
style
=
{
styles
.
tips
}
actions
=
{[{
text
:
'复制'
,
onPress
:()
=>
{
this
.
_copy
(
rowData
);
}},
{
text
:
'删除'
,
onPress
:()
=>
{
this
.
_delete
(
rowData
);
}}]}
isShow
=
{
showToolTips
}
itemData
=
{
rowData
}
/
>
);
}
else
{
<
View
/>
}
}
renderRow
(
rowData
,
sectionID
,
rowID
)
{
return
(
<
View
style
=
{
styles
.
cellContainer
}
>
<
MessageListCellHeader
timestamp
=
{
rowData
.
get
(
'create_date'
)}
/
>
{
this
.
loadMessageListCell
(
rowData
,
rowID
)}
{
this
.
loadMessageListCell
(
rowData
,
rowID
)}
{
this
.
showToolTip
(
rowID
,
rowData
)}
<
/View
>
);
}
...
...
@@ -180,5 +245,10 @@ let styles = StyleSheet.create({
backgroundColor
:
'transparent'
,
flexDirection
:
'column'
,
justifyContent
:
'flex-start'
,
},
tips
:
{
position
:
'absolute'
,
top
:
10
,
left
:
0
}
});
...
...
js/message/components/list/MessageListBigIconCell.js
View file @
d1c0326
...
...
@@ -8,6 +8,7 @@ import ReactNative, {
StyleSheet
,
Dimensions
,
Platform
,
TouchableOpacity
,
}
from
'react-native'
;
import
MessageListCellFooter
from
'./MessageListCellFooter'
...
...
@@ -25,26 +26,32 @@ export default class MessageListBigIconCell extends Component {
imageUri
=
imageUri
.
replace
(
'{width}'
,
width
).
replace
(
'{height}'
,
iconHeight
).
replace
(
'{mode}'
,
2
);
return
(
<
View
style
=
{
styles
.
container
}
>
<
View
style
=
{
styles
.
titleContainer
}
>
<
Text
numberOfLines
=
{
2
}
style
=
{
styles
.
titleStyle
}
>
{
itemData
.
get
(
'title'
)}
<
/Text
>
<
/View
>
<
Image
style
=
{
styles
.
iconStyle
}
source
=
{{
uri
:
imageUri
}}
/
>
<
View
style
=
{
styles
.
descContainer
}
>
<
Text
numberOfLines
=
{
2
}
style
=
{
styles
.
detail
}
>
{
content
}
<
/Text
>
<
/View
>
<
TouchableOpacity
onLongPress
=
{()
=>
{
this
.
props
.
onLongPressListItem
&&
this
.
props
.
onLongPressListItem
(
itemData
);
}}
>
<
View
style
=
{
styles
.
titleContainer
}
>
<
Text
numberOfLines
=
{
2
}
style
=
{
styles
.
titleStyle
}
>
{
itemData
.
get
(
'title'
)}
<
/Text
>
<
/View
>
<
Image
style
=
{
styles
.
iconStyle
}
source
=
{{
uri
:
imageUri
}}
/
>
<
View
style
=
{
styles
.
descContainer
}
>
<
Text
numberOfLines
=
{
2
}
style
=
{
styles
.
detail
}
>
{
content
}
<
/Text
>
<
/View
>
<
/TouchableOpacity
>
<
MessageListCellFooter
onPressListItem
=
{
this
.
props
.
onPressListItem
}
itemData
=
{
itemData
}
...
...
js/message/components/list/MessageListOrderCell.js
View file @
d1c0326
...
...
@@ -8,6 +8,7 @@ import ReactNative, {
StyleSheet
,
Dimensions
,
Platform
,
TouchableOpacity
,
}
from
'react-native'
;
import
MessageListCellFooter
from
'./MessageListCellFooter'
...
...
@@ -25,26 +26,32 @@ export default class MessageListOrderCell extends Component {
return
(
<
View
style
=
{
styles
.
container
}
>
<
View
style
=
{
styles
.
contentContainer
}
>
<
Text
numberOfLines
=
{
2
}
style
=
{
styles
.
titleStyle
}
>
{
itemData
.
get
(
'title'
)}
<
/Text
>
<
View
style
=
{
styles
.
descStyle
}
>
<
Image
style
=
{
styles
.
iconStyle
}
source
=
{{
uri
:
imageUri
}}
/
>
<
TouchableOpacity
onLongPress
=
{()
=>
{
this
.
props
.
onLongPressListItem
&&
this
.
props
.
onLongPressListItem
(
itemData
);
}}
>
<
View
style
=
{
styles
.
contentContainer
}
>
<
Text
style
=
{
styles
.
detail
}
numberOfLines
=
{
3
}
numberOfLines
=
{
2
}
style
=
{
styles
.
titleStyle
}
>
{
content
}
{
itemData
.
get
(
'title'
)
}
<
/Text
>
<
View
style
=
{
styles
.
descStyle
}
>
<
Image
style
=
{
styles
.
iconStyle
}
source
=
{{
uri
:
imageUri
}}
/
>
<
Text
style
=
{
styles
.
detail
}
numberOfLines
=
{
3
}
>
{
content
}
<
/Text
>
<
/View
>
<
/View
>
<
/
View
>
<
/
TouchableOpacity
>
<
MessageListCellFooter
onPressListItem
=
{
this
.
props
.
onPressListItem
}
itemData
=
{
itemData
}
...
...
js/message/components/list/MessageListSmallIconCell.js
View file @
d1c0326
...
...
@@ -8,14 +8,18 @@ import ReactNative, {
StyleSheet
,
Dimensions
,
Platform
,
TouchableOpacity
,
}
from
'react-native'
;
import
MessageListCellFooter
from
'./MessageListCellFooter'
import
YH_ToolTips
from
'../../../common/components/YH_ToolTips'
export
default
class
MessageListSmallIconCell
extends
Component
{
constructor
(
props
)
{
super
(
props
);
}
render
()
{
let
itemData
=
this
.
props
.
itemData
;
let
body
=
itemData
.
get
(
'body'
);
...
...
@@ -24,26 +28,32 @@ export default class MessageListSmallIconCell extends Component {
imageUri
=
imageUri
.
replace
(
'{width}'
,
50
).
replace
(
'{height}'
,
50
).
replace
(
'{mode}'
,
2
);
return
(
<
View
style
=
{
styles
.
container
}
>
<
View
style
=
{
styles
.
contentContainer
}
>
<
Text
numberOfLines
=
{
2
}
style
=
{
styles
.
titleStyle
}
>
{
itemData
.
get
(
'title'
)}
<
/Text
>
<
View
style
=
{
styles
.
descStyle
}
>
<
Image
style
=
{
styles
.
iconStyle
}
source
=
{{
uri
:
imageUri
}}
/
>
<
TouchableOpacity
onLongPress
=
{()
=>
{
this
.
props
.
onLongPressListItem
&&
this
.
props
.
onLongPressListItem
(
itemData
);
}}
>
<
View
style
=
{
styles
.
contentContainer
}
>
<
Text
style
=
{
styles
.
detail
}
numberOfLines
=
{
3
}
numberOfLines
=
{
2
}
style
=
{
styles
.
titleStyle
}
>
{
content
}
{
itemData
.
get
(
'title'
)
}
<
/Text
>
<
View
style
=
{
styles
.
descStyle
}
>
<
Image
style
=
{
styles
.
iconStyle
}
source
=
{{
uri
:
imageUri
}}
/
>
<
Text
style
=
{
styles
.
detail
}
numberOfLines
=
{
3
}
>
{
content
}
<
/Text
>
<
/View
>
<
/View
>
<
/
View
>
<
/
TouchableOpacity
>
<
MessageListCellFooter
onPressListItem
=
{
this
.
props
.
onPressListItem
}
itemData
=
{
itemData
}
...
...
js/message/components/list/MessageListTextCell.js
View file @
d1c0326
...
...
@@ -8,6 +8,7 @@ import ReactNative, {
StyleSheet
,
Dimensions
,
Platform
,
TouchableOpacity
}
from
'react-native'
;
export
default
class
MessageListTextCell
extends
Component
{
...
...
@@ -20,20 +21,26 @@ export default class MessageListTextCell extends Component {
let
body
=
itemData
.
get
(
'body'
);
let
content
=
body
?
body
.
get
(
'content'
,
''
)
:
''
;
return
(
<
View
style
=
{
styles
.
container
}
>
<
Text
numberOfLines
=
{
2
}
style
=
{
styles
.
titleStyle
}
>
{
itemData
.
get
(
'title'
)}
<
/Text
>
<
Text
style
=
{
styles
.
detail
}
>
{
content
}
<
/Text
>
<
View
style
=
{
styles
.
separator
}
/
>
<
/View
>
<
TouchableOpacity
onLongPress
=
{()
=>
{
this
.
props
.
onLongPressListItem
&&
this
.
props
.
onLongPressListItem
(
itemData
);
}}
>
<
View
style
=
{
styles
.
container
}
>
<
Text
numberOfLines
=
{
2
}
style
=
{
styles
.
titleStyle
}
>
{
itemData
.
get
(
'title'
)}
<
/Text
>
<
Text
style
=
{
styles
.
detail
}
>
{
content
}
<
/Text
>
<
View
style
=
{
styles
.
separator
}
/
>
<
/View
>
<
/TouchableOpacity
>
)
}
}
...
...
js/message/components/message/Message.js
View file @
d1c0326
...
...
@@ -14,6 +14,7 @@ import ReactNative, {
RefreshControl
,
}
from
'react-native'
;
import
TimerMixin
from
'react-timer-mixin'
;
import
MessageCell
from
'./MessageCell'
;
export
default
class
Message
extends
Component
{
...
...
@@ -32,14 +33,18 @@ export default class Message extends Component {
trigggePullToRefresh
()
{
if
(
Platform
.
OS
===
'ios'
)
{
InteractionManager
.
runAfterInteractions
(()
=>
{
this
.
timer
=
TimerMixin
.
setTimeout
(()
=>
{
this
.
listView
&&
this
.
listView
.
getScrollResponder
().
startPullToRefresh
();
});
}
,
0
);
}
else
{
this
.
props
.
onRefresh
&&
this
.
props
.
onRefresh
();
}
}
componentWillUnmount
()
{
this
.
timer
&&
TimerMixin
.
clearTimeout
(
this
.
timer
);
}
renderRow
(
rowData
:
object
,
sectionID
:
number
,
rowID
:
number
)
{
return
(
<
MessageCell
...
...
@@ -64,7 +69,7 @@ export default class Message extends Component {
<
View
style
=
{
styles
.
container
}
>
{
Platform
.
OS
===
'ios'
?
Platform
.
OS
===
'ios'
?
<
ListView
ref
=
{(
c
)
=>
{
this
.
listView
=
c
;
...
...
@@ -102,7 +107,7 @@ export default class Message extends Component {
/>
}
/
>
}
}
<
/View
>
);
}
...
...
js/message/components/message/MessageCell.js
View file @
d1c0326
...
...
@@ -23,7 +23,7 @@ export default class MessageCell extends Component {
if
(
msgNumber
<=
0
)
{
return
null
;
}
msgNumber
=
msgNumber
>
9
?
'9+'
:
msgNumber
;
return
(
<
View
style
=
{
styles
.
unreadMsgContainer
}
>
<
Text
style
=
{
styles
.
unreadMsg
}
>
...
...
@@ -43,7 +43,7 @@ export default class MessageCell extends Component {
text
=
isEmpty
?
'会员等级变更提醒、会员生日福利'
:
content
;
break
;
case
2
:
text
=
isEmpty
?
'
新注册用户提示新人专享优惠券信息
'
:
content
;
text
=
isEmpty
?
'
我的优惠券、红包、有货币
'
:
content
;
break
;
case
3
:
text
=
isEmpty
?
'没有收到任何关于你的消息'
:
content
;
...
...
js/message/constants/actionTypes.js
View file @
d1c0326
...
...
@@ -18,4 +18,7 @@ export default keyMirror({
MESSAGE_LIST_SUCCESS
:
null
,
MESSAGE_LIST_FAILURE
:
null
,
DELETE_MESSAGE_LIST_ITEM_REQUEST
:
null
,
DELETE_MESSAGE_LIST_ITEM_SUCCESS
:
null
,
DELETE_MESSAGE_LIST_ITEM_FAILURE
:
null
,
});
...
...
js/message/containers/MessageListContainer.js
View file @
d1c0326
...
...
@@ -49,6 +49,7 @@ class MessageListContainer extends Component {
this
.
onEndReached
=
this
.
onEndReached
.
bind
(
this
);
this
.
onPressListItem
=
this
.
onPressListItem
.
bind
(
this
);
this
.
onPressEmptyItem
=
this
.
onPressEmptyItem
.
bind
(
this
);
this
.
deleteListItem
=
this
.
deleteListItem
.
bind
(
this
);
}
componentDidMount
()
{
...
...
@@ -94,6 +95,11 @@ class MessageListContainer extends Component {
NativeModules
.
YH_CommonHelper
.
logEvent
(
'YB_MESS_LOOK_AROUND_C'
,
param
);
}
deleteListItem
(
item
)
{
let
messageId
=
item
.
get
(
'id'
,
''
)
this
.
props
.
actions
.
deleteMessage
(
messageId
);
}
render
()
{
let
{
list
}
=
this
.
props
;
return
(
...
...
@@ -103,6 +109,7 @@ class MessageListContainer extends Component {
onEndReached
=
{
this
.
onEndReached
}
onPressListItem
=
{
this
.
onPressListItem
}
onPressEmptyItem
=
{
this
.
onPressEmptyItem
}
deleteListItem
=
{
this
.
deleteListItem
}
/
>
<
/View
>
);
...
...
js/message/reducers/list/listActions.js
View file @
d1c0326
...
...
@@ -11,6 +11,10 @@ const {
MESSAGE_LIST_SUCCESS
,
MESSAGE_LIST_FAILURE
,
DELETE_MESSAGE_LIST_ITEM_REQUEST
,
DELETE_MESSAGE_LIST_ITEM_SUCCESS
,
DELETE_MESSAGE_LIST_ITEM_FAILURE
,
}
=
require
(
'../../constants/actionTypes'
).
default
;
...
...
@@ -48,6 +52,26 @@ export function messageListFailure(error) {
};
}
export
function
deleteMessageRequest
(
list
)
{
return
{
type
:
DELETE_MESSAGE_LIST_ITEM_REQUEST
,
payload
:
list
};
}
export
function
deleteMessageSuccess
()
{
return
{
type
:
DELETE_MESSAGE_LIST_ITEM_SUCCESS
,
};
}
export
function
deleteMessageFailure
(
error
)
{
return
{
type
:
DELETE_MESSAGE_LIST_ITEM_FAILURE
,
payload
:
error
};
}
export
function
messageList
()
{
return
(
dispatch
,
getState
)
=>
{
let
{
app
,
list
}
=
getState
();
...
...
@@ -106,3 +130,37 @@ function parseMessageList(json) {
total
,
};
}
export
function
deleteMessage
(
messageId
)
{
return
(
dispatch
,
getState
)
=>
{
let
{
app
,
list
}
=
getState
();
list
=
list
.
list
.
toJS
();
for
(
var
i
=
0
;
i
<
list
.
length
;
i
++
)
{
let
item
=
list
[
i
];
let
msgID
=
item
.
id
;
if
(
msgID
===
messageId
)
{
list
.
splice
(
i
,
1
);
break
;
}
}
let
deleteItem
=
(
sourcePage
)
=>
{
dispatch
(
deleteMessageRequest
(
list
));
return
new
MessageListService
(
app
.
host
).
deleteMessage
(
sourcePage
,
messageId
)
.
then
(
json
=>
{
dispatch
(
deleteMessageSuccess
(
messageId
));
})
.
catch
(
error
=>
{
dispatch
(
deleteMessageFailure
(
error
));
});
}
ReactNative
.
NativeModules
.
YH_CommonHelper
.
sourcePage
(
'YH_RNMessageViewController'
)
.
then
(
result
=>
{
let
sourcePage
=
result
[
0
]?
result
[
0
]:
''
;
deleteItem
(
sourcePage
);
}).
catch
(
error
=>
{
deleteItem
(
''
);
})
};
}
...
...
js/message/reducers/list/listReducer.js
View file @
d1c0326
...
...
@@ -11,6 +11,10 @@ const {
MESSAGE_LIST_SUCCESS
,
MESSAGE_LIST_FAILURE
,
DELETE_MESSAGE_LIST_ITEM_REQUEST
,
DELETE_MESSAGE_LIST_ITEM_SUCCESS
,
DELETE_MESSAGE_LIST_ITEM_FAILURE
,
}
=
require
(
'../../constants/actionTypes'
).
default
;
const
initialState
=
new
InitialState
;
...
...
@@ -58,6 +62,11 @@ export default function listReducer(state=initialState, action) {
.
set
(
'shouldShowEmpty'
,
true
);
}
case
DELETE_MESSAGE_LIST_ITEM_REQUEST
:
{
let
list
=
action
.
payload
;
return
state
.
set
(
'list'
,
Immutable
.
fromJS
(
list
));
}
}
return
state
;
...
...
js/message/reducers/message/messageInitialState.js
View file @
d1c0326
...
...
@@ -13,7 +13,7 @@ let defaults = Immutable.fromJS([
{
id
:
2
,
inboxCatName
:
'我的资产'
,
content
:
'
新注册用户提示新人专享优惠券信息
'
,
content
:
'
我的优惠券、红包、有货币
'
,
unReadCount
:
0
,
createTime
:
''
},
...
...
@@ -27,7 +27,7 @@ let defaults = Immutable.fromJS([
{
id
:
4
,
inboxCatName
:
'其他'
,
content
:
'没有收到任何系统
给
消息'
,
content
:
'没有收到任何系统消息'
,
unReadCount
:
0
,
createTime
:
''
},
...
...
js/message/services/MessageListService.js
View file @
d1c0326
...
...
@@ -30,4 +30,21 @@ export default class MessageListService {
throw
(
error
);
});
}
async
deleteMessage
(
fromPage
,
messageId
)
{
return
await
this
.
api
.
post
({
url
:
''
,
body
:
{
fromPage
,
id
:
messageId
,
method
:
'app.inbox.delmessage'
,
}
})
.
then
((
json
)
=>
{
return
json
;
})
.
catch
((
error
)
=>
{
throw
(
error
);
});
}
}
...
...
Please
register
or
login
to post a comment